| @@ -60,8 +60,7 @@ def globalize(num_workers=8): | |||
| _global_queues = _CopyvioQueues() | |||
| for i in xrange(num_workers): | |||
| worker = _CopyvioWorker(_global_queues) | |||
| worker.start("global-{0}".format(i)) | |||
| worker = _CopyvioWorker("global-{0}".format(i), _global_queues) | |||
| _global_workers.append(worker) | |||
| _is_globalized = True | |||
| @@ -134,16 +133,19 @@ class _CopyvioQueues(object): | |||
| class _CopyvioWorker(object): | |||
| """A multithreaded URL opener/parser instance.""" | |||
| def __init__(self, queues, until=None): | |||
| def __init__(self, name, queues, until=None): | |||
| self._queues = queues | |||
| self._until = until | |||
| self._thread = None | |||
| self._thread = thread = Thread(target=self._run) | |||
| self._site = None | |||
| self._queue = None | |||
| self._opener = build_opener() | |||
| self._logger = getLogger("earwigbot.wiki.cvworker." + name) | |||
| self._logger = None | |||
| thread.name = "cvworker-" + name | |||
| thread.daemon = True | |||
| thread.start() | |||
| def _open_url(self, source): | |||
| """Open a URL and return its parsed content, or None. | |||
| @@ -195,42 +197,44 @@ class _CopyvioWorker(object): | |||
| return handler(content) | |||
| def _dequeue(self): | |||
| """Remove a source from one of the queues.""" | |||
| def _acquire_new_site(self): | |||
| """Block for a new unassigned site queue.""" | |||
| if self._until: | |||
| timeout = self._until - time() | |||
| if timeout <= 0: | |||
| return | |||
| raise Empty | |||
| else: | |||
| timeout = None | |||
| if self._queue: | |||
| self._logger.debug(u"Popping source from existing queue ({0})".format(self._site)) | |||
| self._logger.debug("Waiting for new site queue") | |||
| site, queue = self._queues.unassigned.get(timeout=timeout) | |||
| if site is StopIteration: | |||
| raise StopIteration | |||
| self._logger.debug(u"Acquired new site queue: {0}".format(site)) | |||
| self._site = site | |||
| self._queue = queue | |||
| def _dequeue(self): | |||
| """Remove a source from one of the queues.""" | |||
| if not self._queue: | |||
| self._acquire_new_site() | |||
| logmsg = u"Fetching a new source URL from site queue {0}" | |||
| self._logger.debug(logmsg.format(self._site)) | |||
| self._queues.lock.acquire() | |||
| try: | |||
| source = self._queue.pop() | |||
| self._logger.debug(u"Got URL: {0}".format(source.url)) | |||
| with self._queues.lock: | |||
| if not self._queue: | |||
| self._logger.debug(u"Destroying site {0}".format(self._site)) | |||
| del self._queues.sites[self._site] | |||
| self._queue = None | |||
| else: | |||
| self._logger.debug("Waiting for unassigned URL queue") | |||
| site, queue = self._queues.unassigned.get(timeout=timeout) | |||
| if site is StopIteration: | |||
| return StopIteration | |||
| self._logger.debug(u"Got queue: {0}".format(site)) | |||
| source = queue.pop() | |||
| self._logger.debug(u"Got URL: {0}".format(source.url)) | |||
| with self._queues.lock: | |||
| if not queue: | |||
| self._logger.debug(u"Destroying site {0}".format(site)) | |||
| del self._queues.sites[site] | |||
| else: | |||
| self._logger.debug(u"Saving site {0}".format(site)) | |||
| self._site = site | |||
| self._queue = queue | |||
| except IndexError: | |||
| self._logger.debug("Queue is empty") | |||
| del self._queues.sites[self._site] | |||
| self._queue = None | |||
| self._queues.lock.release() | |||
| return self._dequeue() | |||
| self._queues.lock.release() | |||
| self._logger.debug(u"Got source URL: {0}".format(source.url)) | |||
| if not source.active(): | |||
| self._logger.debug(u"Inactive source; trying again") | |||
| self._logger.debug("Source is inactive") | |||
| return self._dequeue() | |||
| return source | |||
| @@ -245,21 +249,15 @@ class _CopyvioWorker(object): | |||
| try: | |||
| source = self._dequeue() | |||
| except Empty: | |||
| self._logger.debug("Exiting: queue timed out") | |||
| return | |||
| if source is StopIteration: | |||
| except StopIteration: | |||
| self._logger.debug("Exiting: got stop signal") | |||
| return | |||
| text = self._open_url(source) | |||
| if text: | |||
| source.workspace.compare(source, MarkovChain(text)) | |||
| def start(self, name): | |||
| """Start the worker in a new thread, with a given name.""" | |||
| self._logger = getLogger("earwigbot.wiki.cvworker." + name) | |||
| self._thread = thread = Thread(target=self._run) | |||
| thread.name = "cvworker-" + name | |||
| thread.daemon = True | |||
| thread.start() | |||
| class CopyvioWorkspace(object): | |||
| """Manages a single copyvio check distributed across threads.""" | |||
| @@ -284,8 +282,8 @@ class CopyvioWorkspace(object): | |||
| else: | |||
| self._queues = _CopyvioQueues() | |||
| for i in xrange(num_workers): | |||
| worker = _CopyvioWorker(self._queues, until) | |||
| worker.start("local-{0:04}.{1}".format(id(self) % 10000, i)) | |||
| name = "local-{0:04}.{1}".format(id(self) % 10000, i) | |||
| worker = _CopyvioWorker(name, self._queues, until) | |||
| def _calculate_confidence(self, delta): | |||
| """Return the confidence of a violation as a float between 0 and 1.""" | |||