[Zope-CVS] CVS: Products/Scheduler - Scheduler.py:1.21 Task.py:1.3

Chris McDonough chrism@zope.com
Mon, 7 Jul 2003 17:32:24 -0400


Update of /cvs-repository/Products/Scheduler
In directory cvs.zope.org:/tmp/cvs-serv22918

Modified Files:
	Scheduler.py Task.py 
Log Message:
Don't let UI fail when there is a data structure inconsistency.

Give users a way to recover from a data structure inconsistencies.

Do cleanup of old lists in times btree.


=== Products/Scheduler/Scheduler.py 1.20 => 1.21 ===
--- Products/Scheduler/Scheduler.py:1.20	Sat Jun 28 15:32:27 2003
+++ Products/Scheduler/Scheduler.py	Mon Jul  7 17:31:50 2003
@@ -38,7 +38,8 @@
 from Products.Scheduler import IDescheduledEvent
 from Products.Scheduler import ITimeEvent
 from Products.Scheduler.Task import Task
-from SchedulerPermissions import *
+from Products.Scheduler.Task import InconsistentSchedulerMarkerTask
+from Products.Scheduler.SchedulerPermissions import *
 
 from zLOG import LOG, PROBLEM, ERROR, BLATHER
 
@@ -246,7 +247,15 @@
         for t, taskid_list in timelist:
             for taskid in taskid_list:
                 task = self.tasks.get(taskid)
-                task = aq_base(task).__of__(self)
+                if task is None:
+                    # there is a consistency problem between the times and
+                    # tasks btrees.
+                    # this has happened in production on the bonzai
+                    # project.  we don't know what has caused it yet, so
+                    # we work around it but don't fail.
+                    task=InconsistentSchedulerMarkerTask(t,taskid).__of__(self)
+                else:
+                    task = aq_base(task).__of__(self)
                 l.append((t, task, taskid))
         return l
                 
@@ -286,7 +295,10 @@
         del self.tasks[taskid]
         l = self.times[time]
         l.remove(taskid)
-        self.times[time] = l
+        if l:
+            self.times[time] = l
+        else:
+            del self.times[time]
 
     security.declareProtected(CHANGE_SCHEDULE_PERM, 'checkConsistency')
     def checkConsistency(self):
@@ -325,6 +337,24 @@
 
         if l:
             return '\n'.join(l)
+        return 'OK'
+
+    security.declareProtected(CHANGE_SCHEDULE_PERM, 'fixupTimesBTrees')
+    def fixupTimesBtree(self):
+        """ Make times btree consistent (recover from desync) """
+        newtree = IOBTree.IOBTree()
+        timelist = self.times.items(None, sys.maxint - 1)
+        for t, taskid_list in timelist:
+            for taskid in taskid_list:
+                task = self.tasks.get(taskid)
+                if task is None:
+                    continue
+                else:
+                    l = newtree.get(t, [])
+                    l.append(taskid)
+                    newtree[t] = l
+        self.oldtimes = self.times
+        self.times = newtree
         return 'OK'
 
     security.declareProtected(CHANGE_SCHEDULE_PERM, 'manage_scheduleTask')


=== Products/Scheduler/Task.py 1.2 => 1.3 ===
--- Products/Scheduler/Task.py:1.2	Tue Jun  3 10:50:45 2003
+++ Products/Scheduler/Task.py	Mon Jul  7 17:31:50 2003
@@ -170,7 +170,47 @@
                               retry_backoff_time=self.retry_backoff_time,
                               filter_data=self.filter_data)
 
+class InconsistentSchedulerMarkerTask(Implicit):
+    """ A task implementation which is operated against when there
+    is a scheduler data structure inconsistency which causes a
+    task to not be found for a particular time """
+    
+    security = ClassSecurityInfo()
+    security.declareObjectPublic()
+    security.setDefaultAccess("allow")
+
+    __implements__ = IScheduledEvent
+
+    def __init__(self, when, taskid):
+        self.when = when
+        self.taskid = taskid
+
+    def __call__(self):
+        """ Do nothing """
+        return None
+
+    def next(self):
+        """ Do nothing """
+        return None
+
+    def getDescription(self):
+        return ('Scheduler inconsistency for taskid %s (when: %s)!' %
+                (self.taskid, self.when))
+
+    getInfo = info = getDescription
+
+    def getTime(self):
+        return 0
+
+    def getFilterData(self):
+        return None
+
+    def __getstate__(self):
+        raise RuntimeError, ('%s class cannot be persisted' %
+                             self.__class__.__name__)
+
 def pretty_time(t):
     return time.ctime(t)
 
 Globals.InitializeClass(Task)
+Globals.InitializeClass(InconsistentSchedulerMarkerTask)