<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[13484] CalendarServer/trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/13484">13484</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2014-05-15 18:54:55 -0700 (Thu, 15 May 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Fix base class ordering to ensure schedule work group locking occurs. Fix dashboard so it can run even
when the server is down or being started/stopped.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkcalendarserverdashboard_servicepy">CalendarServer/trunk/calendarserver/dashboard_service.py</a></li>
<li><a href="#CalendarServertrunkcalendarservertoolsdashboardpy">CalendarServer/trunk/calendarserver/tools/dashboard.py</a></li>
<li><a href="#CalendarServertrunkrequirementsstabletxt">CalendarServer/trunk/requirements-stable.txt</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingworkpy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/work.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkcalendarserverdashboard_servicepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/dashboard_service.py (13483 => 13484)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/dashboard_service.py        2014-05-16 01:50:56 UTC (rev 13483)
+++ CalendarServer/trunk/calendarserver/dashboard_service.py        2014-05-16 01:54:55 UTC (rev 13484)
</span><span class="lines">@@ -124,9 +124,12 @@
</span><span class="cx">         @rtype: L{str}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        txn = self.factory.store.newTransaction()
-        records = (yield JobItem.histogram(txn))
-        yield txn.commit()
</del><ins>+        if self.factory.store:
+            txn = self.factory.store.newTransaction()
+            records = (yield JobItem.histogram(txn))
+            yield txn.commit()
+        else:
+            records = {}
</ins><span class="cx"> 
</span><span class="cx">         returnValue(records)
</span><span class="cx"> 
</span><span class="lines">@@ -139,9 +142,13 @@
</span><span class="cx">         @rtype: L{str}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        queuer = self.factory.store.queuer
-        loads = queuer.workerPool.eachWorkerLoad()
-        level = queuer.workerPool.loadLevel()
</del><ins>+        if self.factory.store:
+            queuer = self.factory.store.queuer
+            loads = queuer.workerPool.eachWorkerLoad()
+            level = queuer.workerPool.loadLevel()
+        else:
+            loads = []
+            level = 0
</ins><span class="cx"> 
</span><span class="cx">         return succeed({&quot;workers&quot;: loads, &quot;level&quot;: level})
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServertrunkcalendarservertoolsdashboardpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/tools/dashboard.py (13483 => 13484)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/tools/dashboard.py        2014-05-16 01:50:56 UTC (rev 13483)
+++ CalendarServer/trunk/calendarserver/tools/dashboard.py        2014-05-16 01:54:55 UTC (rev 13484)
</span><span class="lines">@@ -96,6 +96,11 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+def defaultIfNone(x, default):
+    return x if x is not None else default
+
+
+
</ins><span class="cx"> class Dashboard(object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Main dashboard controller. Use Python's L{sched} feature to schedule
</span><span class="lines">@@ -113,6 +118,7 @@
</span><span class="cx">         self.seconds = 0.1 if usesCurses else 1.0
</span><span class="cx">         self.sched = sched.scheduler(time.time, time.sleep)
</span><span class="cx">         self.client = DashboardClient((&quot;localhost&quot;, 8100), True)
</span><ins>+        self.client_error = False
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><span class="lines">@@ -160,11 +166,34 @@
</span><span class="cx">         self.updateDisplay(True)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def resetWindows(self):
+        &quot;&quot;&quot;
+        Reset the current set of windows.
+        &quot;&quot;&quot;
+        if self.windows:
+            for window in self.windows:
+                window.deactivate()
+            old_windows = self.windows
+            self.windows = []
+            top = 0
+            for old in old_windows:
+                self.windows.append(old.__class__(self.usesCurses, self.client).makeWindow(top=top))
+                self.windows[-1].activate()
+                top += self.windows[-1].nlines + 1
+
+
</ins><span class="cx">     def updateDisplay(self, initialUpdate=False):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Periodic update of the current window and check for a key press.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         self.client.update()
</span><ins>+        client_error = len(self.client.currentData) == 0
+        if client_error ^ self.client_error:
+            self.client_error = client_error
+            self.resetWindows()
+        elif filter(lambda x: x.requiresReset(), self.windows):
+            self.resetWindows()
+
</ins><span class="cx">         try:
</span><span class="cx">             if not self.paused or initialUpdate:
</span><span class="cx">                 for window in filter(
</span><span class="lines">@@ -172,8 +201,9 @@
</span><span class="cx">                     self.windows
</span><span class="cx">                 ):
</span><span class="cx">                     window.update()
</span><del>-        except Exception as e:
-            print(str(e))
</del><ins>+        except Exception as e: #@UnusedVariable
+            #print(str(e))
+            pass
</ins><span class="cx">         if not self.usesCurses:
</span><span class="cx">             print(&quot;-------------&quot;)
</span><span class="cx"> 
</span><span class="lines">@@ -208,7 +238,7 @@
</span><span class="cx">         self.socket = None
</span><span class="cx">         self.sockname = sockname
</span><span class="cx">         self.useTCP = useTCP
</span><del>-        self.currentData = None
</del><ins>+        self.currentData = {}
</ins><span class="cx">         self.items = []
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -223,21 +253,26 @@
</span><span class="cx">                 self.socket.setblocking(0)
</span><span class="cx">             self.socket.sendall(json.dumps(items) + &quot;\r\n&quot;)
</span><span class="cx">             data = &quot;&quot;
</span><ins>+            t = time.time()
</ins><span class="cx">             while not data.endswith(&quot;\n&quot;):
</span><span class="cx">                 try:
</span><span class="cx">                     d = self.socket.recv(1024)
</span><span class="cx">                 except socket.error as se:
</span><span class="cx">                     if se.args[0] != errno.EWOULDBLOCK:
</span><span class="cx">                         raise
</span><ins>+                    if time.time() - t &gt; 5:
+                        raise socket.error
</ins><span class="cx">                     continue
</span><span class="cx">                 if d:
</span><span class="cx">                     data += d
</span><span class="cx">                 else:
</span><span class="cx">                     break
</span><span class="cx">             data = json.loads(data)
</span><del>-        except socket.error as e:
-            data = {&quot;Failed&quot;: &quot;Unable to read statistics from server: %s %s&quot; % (self.sockname, e)}
</del><ins>+        except socket.error:
+            data = {}
</ins><span class="cx">             self.socket = None
</span><ins>+        except ValueError:
+            data = {}
</ins><span class="cx">         return data
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -245,6 +280,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Update the current data from the server.
</span><span class="cx">         &quot;&quot;&quot;
</span><ins>+
</ins><span class="cx">         self.currentData = self.readSock(self.items)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -252,7 +288,8 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Update the current data from the server.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        return self.readSock([item])[item]
</del><ins>+        data = self.readSock([item])
+        return data[item] if data else None
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def addItem(self, item):
</span><span class="lines">@@ -282,6 +319,8 @@
</span><span class="cx">     def __init__(self, usesCurses, client):
</span><span class="cx">         self.usesCurses = usesCurses
</span><span class="cx">         self.client = client
</span><ins>+        self.rowCount = 0
+        self.needsReset = False
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def makeWindow(self, top=0, left=0):
</span><span class="lines">@@ -315,6 +354,14 @@
</span><span class="cx">         return True
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def requiresReset(self):
+        &quot;&quot;&quot;
+        Indicates that the window needs a full reset, because e.g., the
+        number of items it didplays has changed.
+        &quot;&quot;&quot;
+        return self.needsReset
+
+
</ins><span class="cx">     def activate(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         About to start displaying.
</span><span class="lines">@@ -342,7 +389,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def clientData(self):
</span><del>-        return self.client.currentData[self.clientItem]
</del><ins>+        return self.client.currentData.get(self.clientItem)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def readItem(self, item):
</span><span class="lines">@@ -417,13 +464,17 @@
</span><span class="cx">     FORMAT_WIDTH = 78
</span><span class="cx"> 
</span><span class="cx">     def makeWindow(self, top=0, left=0):
</span><del>-        nlines = self.readItem(&quot;jobcount&quot;)
-        self._createWindow(&quot;Jobs&quot;, nlines + 5, ncols=self.FORMAT_WIDTH, begin_y=top, begin_x=left)
</del><ins>+        nlines = defaultIfNone(self.readItem(&quot;jobcount&quot;), 0)
+        self.rowCount = nlines
+        self._createWindow(&quot;Jobs&quot;, self.rowCount + 5, ncols=self.FORMAT_WIDTH, begin_y=top, begin_x=left)
</ins><span class="cx">         return self
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def update(self):
</span><del>-        records = self.clientData()
</del><ins>+        records = defaultIfNone(self.clientData(), {})
+        if len(records) != self.rowCount:
+            self.needsReset = True
+            return
</ins><span class="cx">         self.iter += 1
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -496,20 +547,24 @@
</span><span class="cx"> 
</span><span class="cx">     help = &quot;display server child job assignments&quot;
</span><span class="cx">     clientItem = &quot;job_assignments&quot;
</span><del>-    FORMAT_WIDTH = 32
</del><ins>+    FORMAT_WIDTH = 40
</ins><span class="cx"> 
</span><span class="cx">     def makeWindow(self, top=0, left=0):
</span><del>-        slots = self.readItem(self.clientItem)[&quot;workers&quot;]
</del><ins>+        slots = defaultIfNone(self.readItem(self.clientItem), {&quot;workers&quot;: ()})[&quot;workers&quot;]
+        self.rowCount = len(slots)
</ins><span class="cx">         self._createWindow(
</span><del>-            &quot;Job Assignments&quot;, len(slots) + 5, self.FORMAT_WIDTH,
</del><ins>+            &quot;Job Assignments&quot;, self.rowCount + 5, self.FORMAT_WIDTH,
</ins><span class="cx">             begin_y=top, begin_x=left
</span><span class="cx">         )
</span><span class="cx">         return self
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def update(self):
</span><del>-        data = self.clientData()
</del><ins>+        data = defaultIfNone(self.clientData(), {&quot;workers&quot;: {}, &quot;level&quot;: 0})
</ins><span class="cx">         records = data[&quot;workers&quot;]
</span><ins>+        if len(records) != self.rowCount:
+            self.needsReset = True
+            return
</ins><span class="cx">         self.iter += 1
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -522,25 +577,28 @@
</span><span class="cx"> 
</span><span class="cx">         x = 1
</span><span class="cx">         y = 1
</span><del>-        s = &quot; {:&gt;4}{:&gt;12}{:&gt;12} &quot;.format(
-            &quot;Slot&quot;, &quot;assigned&quot;, &quot;completed&quot;
</del><ins>+        s = &quot; {:&gt;4}{:&gt;12}{:&gt;8}{:&gt;12} &quot;.format(
+            &quot;Slot&quot;, &quot;assigned&quot;, &quot;load&quot;, &quot;completed&quot;
</ins><span class="cx">         )
</span><span class="cx">         if self.usesCurses:
</span><span class="cx">             self.window.addstr(y, x, s, curses.A_REVERSE)
</span><span class="cx">         else:
</span><span class="cx">             print(s)
</span><span class="cx">         y += 1
</span><ins>+        total_assigned = 0
</ins><span class="cx">         total_completed = 0
</span><span class="cx">         for ctr, details in enumerate(records):
</span><del>-            assigned, completed = details
</del><ins>+            assigned, load, completed = details
+            total_assigned += assigned
</ins><span class="cx">             total_completed += completed
</span><span class="cx">             changed = (
</span><span class="cx">                 ctr in self.lastResult and
</span><span class="cx">                 self.lastResult[ctr] != assigned
</span><span class="cx">             )
</span><del>-            s = &quot; {:&gt;4}{:&gt;12}{:&gt;12} &quot;.format(
</del><ins>+            s = &quot; {:&gt;4}{:&gt;12}{:&gt;8}{:&gt;12} &quot;.format(
</ins><span class="cx">                 ctr,
</span><span class="cx">                 assigned,
</span><ins>+                load,
</ins><span class="cx">                 completed,
</span><span class="cx">             )
</span><span class="cx">             try:
</span><span class="lines">@@ -555,8 +613,9 @@
</span><span class="cx">                 pass
</span><span class="cx">             y += 1
</span><span class="cx"> 
</span><del>-        s = &quot; {:&lt;6}{:&gt;10}{:&gt;12}&quot;.format(
</del><ins>+        s = &quot; {:&lt;6}{:&gt;10}{:&gt;8}{:&gt;12}&quot;.format(
</ins><span class="cx">             &quot;Total:&quot;,
</span><ins>+            total_assigned,
</ins><span class="cx">             &quot;{}%&quot;.format(data[&quot;level&quot;]),
</span><span class="cx">             total_completed,
</span><span class="cx">         )
</span><span class="lines">@@ -585,17 +644,21 @@
</span><span class="cx">     FORMAT_WIDTH = 72
</span><span class="cx"> 
</span><span class="cx">     def makeWindow(self, top=0, left=0):
</span><del>-        slots = self.readItem(self.clientItem)[&quot;slots&quot;]
</del><ins>+        slots = defaultIfNone(self.readItem(self.clientItem), {&quot;slots&quot;: ()})[&quot;slots&quot;]
+        self.rowCount = len(slots)
</ins><span class="cx">         self._createWindow(
</span><del>-            &quot;HTTP Slots&quot;, len(slots) + 5, self.FORMAT_WIDTH,
</del><ins>+            &quot;HTTP Slots&quot;, self.rowCount + 5, self.FORMAT_WIDTH,
</ins><span class="cx">             begin_y=top, begin_x=left
</span><span class="cx">         )
</span><span class="cx">         return self
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def update(self):
</span><del>-        data = self.clientData()
</del><ins>+        data = defaultIfNone(self.clientData(), {&quot;slots&quot;: {}, &quot;overloaded&quot;: False})
</ins><span class="cx">         records = data[&quot;slots&quot;]
</span><ins>+        if len(records) != self.rowCount:
+            self.needsReset = True
+            return
</ins><span class="cx">         self.iter += 1
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -688,13 +751,22 @@
</span><span class="cx">     clientItem = &quot;stats_system&quot;
</span><span class="cx"> 
</span><span class="cx">     def makeWindow(self, top=0, left=0):
</span><del>-        slots = self.readItem(self.clientItem)
-        self._createWindow(&quot;System&quot;, len(slots) + 3, begin_y=top, begin_x=left)
</del><ins>+        slots = defaultIfNone(self.readItem(self.clientItem), (1, 2, 3, 4,))
+        self.rowCount = len(slots)
+        self._createWindow(&quot;System&quot;, self.rowCount + 3, begin_y=top, begin_x=left)
</ins><span class="cx">         return self
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def update(self):
</span><del>-        records = self.clientData()
</del><ins>+        records = defaultIfNone(self.clientData(), {
+            &quot;cpu use&quot;: 0.0,
+            &quot;memory percent&quot;: 0.0,
+            &quot;memory used&quot;: 0,
+            &quot;start time&quot;: time.time(),
+        })
+        if len(records) != self.rowCount:
+            self.needsReset = True
+            return
</ins><span class="cx">         self.iter += 1
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -763,7 +835,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def update(self):
</span><del>-        records = self.clientData()
</del><ins>+        records = defaultIfNone(self.clientData(), {})
</ins><span class="cx">         self.iter += 1
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -787,7 +859,15 @@
</span><span class="cx">             print(s2)
</span><span class="cx">         y += 2
</span><span class="cx">         for key, seconds in ((&quot;current&quot;, 60,), (&quot;1m&quot;, 60,), (&quot;5m&quot;, 5 * 60,), (&quot;1h&quot;, 60 * 60,),):
</span><del>-            stat = records[key]
</del><ins>+            stat = records.get(key, {
+                &quot;requests&quot;: 0,
+                &quot;t&quot;: 0.0,
+                &quot;t-resp-wr&quot;: 0.0,
+                &quot;T-MAX&quot;: 0.0,
+                &quot;slots&quot;: 0,
+                &quot;cpu&quot;: 0.0,
+                &quot;500&quot;: 0,
+            })
</ins><span class="cx">             s = &quot; {:&lt;8}{:&gt;8}{:&gt;10.1f}{:&gt;10.1f}{:&gt;10.1f}{:&gt;10.1f}{:&gt;8.2f}{:&gt;7.1f}%{:&gt;8} &quot;.format(
</span><span class="cx">                 key,
</span><span class="cx">                 stat[&quot;requests&quot;],
</span></span></pre></div>
<a id="CalendarServertrunkrequirementsstabletxt"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/requirements-stable.txt (13483 => 13484)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-stable.txt        2014-05-16 01:50:56 UTC (rev 13483)
+++ CalendarServer/trunk/requirements-stable.txt        2014-05-16 01:54:55 UTC (rev 13484)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> # For CalendarServer development, don't try to get these projects from PyPI; use svn.
</span><span class="cx"> 
</span><span class="cx"> -e .
</span><del>--e svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@13475#egg=twextpy
</del><ins>+-e svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@13483#egg=twextpy
</ins><span class="cx"> -e svn+http://svn.calendarserver.org/repository/calendarserver/PyKerberos/trunk@13420#egg=kerberos
</span><span class="cx"> -e svn+http://svn.calendarserver.org/repository/calendarserver/PyCalendar/trunk@13420#egg=pycalendar
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingworkpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/work.py (13483 => 13484)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/work.py        2014-05-16 01:50:56 UTC (rev 13483)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/work.py        2014-05-16 01:54:55 UTC (rev 13484)
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class ScheduleWorkMixin(object):
</del><ins>+class ScheduleWorkMixin(WorkItem):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Base class for common schedule work item behavior.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -131,7 +131,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class ScheduleOrganizerWork(WorkItem, fromTable(schema.SCHEDULE_ORGANIZER_WORK), ScheduleWorkMixin):
</del><ins>+class ScheduleOrganizerWork(ScheduleWorkMixin, fromTable(schema.SCHEDULE_ORGANIZER_WORK)):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     The associated work item table is SCHEDULE_ORGANIZER_WORK.
</span><span class="cx"> 
</span><span class="lines">@@ -272,7 +272,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class ScheduleReplyWork(WorkItem, fromTable(schema.SCHEDULE_REPLY_WORK), ScheduleReplyWorkMixin):
</del><ins>+class ScheduleReplyWork(ScheduleReplyWorkMixin, fromTable(schema.SCHEDULE_REPLY_WORK)):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     The associated work item table is SCHEDULE_REPLY_WORK.
</span><span class="cx"> 
</span><span class="lines">@@ -353,7 +353,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class ScheduleReplyCancelWork(WorkItem, fromTable(schema.SCHEDULE_REPLY_CANCEL_WORK), ScheduleReplyWorkMixin):
</del><ins>+class ScheduleReplyCancelWork(ScheduleReplyWorkMixin, fromTable(schema.SCHEDULE_REPLY_CANCEL_WORK)):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     The associated work item table is SCHEDULE_REPLY_CANCEL_WORK.
</span><span class="cx"> 
</span><span class="lines">@@ -416,7 +416,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class ScheduleRefreshWork(WorkItem, fromTable(schema.SCHEDULE_REFRESH_WORK), ScheduleWorkMixin):
</del><ins>+class ScheduleRefreshWork(ScheduleWorkMixin, fromTable(schema.SCHEDULE_REFRESH_WORK)):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     The associated work item table is SCHEDULE_REFRESH_WORK.
</span><span class="cx"> 
</span><span class="lines">@@ -604,7 +604,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class ScheduleAutoReplyWork(WorkItem, fromTable(schema.SCHEDULE_AUTO_REPLY_WORK), ScheduleWorkMixin):
</del><ins>+class ScheduleAutoReplyWork(ScheduleWorkMixin, fromTable(schema.SCHEDULE_AUTO_REPLY_WORK)):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     The associated work item table is SCHEDULE_AUTO_REPLY_WORK.
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>