PollScheduler: tweek termination logic
authorZac Medico <zmedico@gentoo.org>
Fri, 11 Mar 2011 06:02:19 +0000 (22:02 -0800)
committerZac Medico <zmedico@gentoo.org>
Fri, 11 Mar 2011 06:02:19 +0000 (22:02 -0800)
* PollScheduler and all subclasses now use the _terminated_tasks
  variable to check whether or not _terminate_tasks() has been called,
  and behave appropriately in that case.

* The _schedule_tasks() method now has documentation about the
  relationship with _terminate_tasks() and _terminated_tasks.

pym/_emerge/MetadataRegen.py
pym/_emerge/PollScheduler.py
pym/_emerge/QueueScheduler.py
pym/_emerge/Scheduler.py

index 45c4f4d29f0c978b9743653ba48f08004759df6d..810317533a0064c9ea398ce428a0a64273c8a6f6 100644 (file)
@@ -44,7 +44,7 @@ class MetadataRegen(PollScheduler):
                portage.writemsg_stdout("Regenerating cache entries...\n")
                every_cp.sort(reverse=True)
                try:
-                       while not self._terminated.is_set():
+                       while not self._terminated_tasks:
                                yield every_cp.pop()
                except IndexError:
                        pass
@@ -56,13 +56,13 @@ class MetadataRegen(PollScheduler):
                consumer = self._consumer
 
                for cp in self._cp_iter:
-                       if self._terminated.is_set():
+                       if self._terminated_tasks:
                                break
                        cp_set.add(cp)
                        portage.writemsg_stdout("Processing %s\n" % cp)
                        cpv_list = portdb.cp_list(cp)
                        for cpv in cpv_list:
-                               if self._terminated.is_set():
+                               if self._terminated_tasks:
                                        break
                                valid_pkgs.add(cpv)
                                ebuild_path, repo_path = portdb.findname2(cpv)
@@ -94,7 +94,7 @@ class MetadataRegen(PollScheduler):
                while self._jobs:
                        self._poll_loop()
 
-               if self._terminated.is_set():
+               if self._terminated_tasks:
                        self.returncode = 1
                        return
 
@@ -145,9 +145,10 @@ class MetadataRegen(PollScheduler):
                @returns: True if there may be remaining tasks to schedule,
                        False otherwise.
                """
+               if self._terminated_tasks:
+                       return False
+
                while self._can_add_job():
-                       if self._terminated.is_set():
-                               return False
                        try:
                                metadata_process = next(self._process_iter)
                        except StopIteration:
@@ -167,7 +168,7 @@ class MetadataRegen(PollScheduler):
                        self.returncode = 1
                        self._error_count += 1
                        self._valid_pkgs.discard(metadata_process.cpv)
-                       if not self._terminated.is_set():
+                       if not self._terminated_tasks:
                                portage.writemsg("Error processing %s, continuing...\n" % \
                                        (metadata_process.cpv,), noiselevel=-1)
 
index 94fd92407c41d5ef6076c4addfbbca38f5b5183b..8f4bd64b9506a8000c978ff991a7d464ca2e66c6 100644 (file)
@@ -65,6 +65,24 @@ class PollScheduler(object):
                """
                raise NotImplementedError()
 
+       def _schedule_tasks(self):
+               """
+               This is called from inside the _schedule() method, which
+               guarantees the following:
+
+               1) It will not be called recursively.
+               2) _terminate_tasks() will not be called while it is running.
+               3) The state of the boolean _terminated_tasks variable will
+                  not change while it is running.
+
+               Unless this method is used to perform user interface updates,
+               or something like that, the first thing it should do is check
+               the state of _terminated_tasks and if that is True then it
+               should return False immediately (since there's no need to
+               schedule anything after _terminate_tasks() has been called).
+               """
+               raise NotImplementedError()
+
        def _schedule(self):
                """
                Calls _schedule_tasks() and automatically returns early from
@@ -90,6 +108,9 @@ class PollScheduler(object):
                return self._jobs
 
        def _can_add_job(self):
+               if self._terminated_tasks:
+                       return False
+
                max_jobs = self._max_jobs
                max_load = self._max_load
 
index 8a7ea300a55f04f1ceb9aa5f72b4f1d4ddc82f27..2d727c95dbbf09c3324d25ceafb103558565678f 100644 (file)
@@ -79,6 +79,9 @@ class QueueScheduler(PollScheduler):
                @returns: True if there may be remaining tasks to schedule,
                        False otherwise.
                """
+               if self._terminated_tasks:
+                       return False
+
                while self._can_add_job():
                        n = self._max_jobs - self._running_job_count()
                        if n < 1:
index 9f72856340e389b5bdd59129b773e0825155ff59..c6161201a140fbbdb670aa1a6441c24e1eb0f7f5 100644 (file)
@@ -1443,7 +1443,7 @@ class Scheduler(PollScheduler):
                                build_dir=build_dir, build_log=build_log,
                                pkg=pkg,
                                returncode=merge.returncode))
-                       if not self._terminated.is_set():
+                       if not self._terminated_tasks:
                                self._failed_pkg_msg(self._failed_pkgs[-1], "install", "to")
                                self._status_display.failed = len(self._failed_pkgs)
                        return
@@ -1478,7 +1478,7 @@ class Scheduler(PollScheduler):
                mtimedb.commit()
 
        def _build_exit(self, build):
-               if build.returncode == os.EX_OK and self._terminated.is_set():
+               if build.returncode == os.EX_OK and self._terminated_tasks:
                        # We've been interrupted, so we won't
                        # add this to the merge queue.
                        self.curval += 1
@@ -1507,7 +1507,7 @@ class Scheduler(PollScheduler):
                                build_dir=build_dir, build_log=build_log,
                                pkg=build.pkg,
                                returncode=build.returncode))
-                       if not self._terminated.is_set():
+                       if not self._terminated_tasks:
                                self._failed_pkg_msg(self._failed_pkgs[-1], "emerge", "for")
                                self._status_display.failed = len(self._failed_pkgs)
                        self._deallocate_config(build.settings)
@@ -1687,7 +1687,7 @@ class Scheduler(PollScheduler):
                                self._poll_loop()
 
        def _keep_scheduling(self):
-               return bool(not self._terminated.is_set() and self._pkg_queue and \
+               return bool(not self._terminated_tasks and self._pkg_queue and \
                        not (self._failed_pkgs and not self._build_opts.fetchonly))
 
        def _is_work_scheduled(self):