Change in vdsm[master]: schedule: Port schedule module to Python 3

nsoffer at redhat.com nsoffer at redhat.com
Fri Apr 8 15:30:11 UTC 2016


Nir Soffer has uploaded a new change for review.

Change subject: schedule: Port schedule module to Python 3
......................................................................

schedule: Port schedule module to Python 3

In Python 3, you cannot use push a tuple into a heap if one of the
objects in the tuple does not support ordering. Implement the minimal
rich comparison to make it work on Python 3.

Since ScheduledCall supports ordering now, we don't need to wrap it into
a tuple, and we can push the object itself into the heap. We used a
tuple before because in Python 2 it using a tuple was faster then
implementing a __cmp__ method. Unfortunally, we don't have this option
with Python 3.

Change-Id: Ie6d20fe1a1d262d5489be5bedba929709fa59e35
Signed-off-by: Nir Soffer <nsoffer at redhat.com>
---
M lib/vdsm/schedule.py
M tests/scheduleTests.py
2 files changed, 48 insertions(+), 11 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/80/55880/1

diff --git a/lib/vdsm/schedule.py b/lib/vdsm/schedule.py
index 5712023..e9d406c 100644
--- a/lib/vdsm/schedule.py
+++ b/lib/vdsm/schedule.py
@@ -127,13 +127,12 @@
         yet.
         """
         deadline = self._clock() + delay
-        call = ScheduledCall(callable)
+        call = ScheduledCall(deadline, callable)
         with self._cond:
             if not self._running:
                 raise AssertionError("Scheduler not running")
-            heapq.heappush(self._calls, (deadline, call))
-            next_call = self._calls[0][1]
-            if next_call is call:
+            heapq.heappush(self._calls, call)
+            if self._calls[0] is call:
                 self._cond.notify()
         return call
 
@@ -161,16 +160,15 @@
 
     def _time_until_deadline(self):
         if len(self._calls) > 0:
-            next_deadline = self._calls[0][0]
-            return next_deadline - self._clock()
+            return self._calls[0]._deadline - self._clock()
         return self.DEFAULT_DELAY
 
     def _pop_expired_calls(self):
         now = self._clock()
         expired = []
         while len(self._calls) > 0:
-            deadline, call = self._calls[0]
-            if deadline > now:
+            call = self._calls[0]
+            if call._deadline > now:
                 break
             heapq.heappop(self._calls)
             if call.valid():
@@ -180,7 +178,7 @@
     def _cancel_calls(self):
         # Help the garbage collector by breaking reference cycles
         with self._cond:
-            for deadline, call in self._calls:
+            for call in self._calls:
                 call.cancel()
 
 
@@ -192,11 +190,12 @@
     This class is thread safe; any thread can cancel a call.
     """
 
-    __slots__ = ('_callable',)
+    __slots__ = ('_deadline', '_callable')
 
     _log = logging.getLogger("Scheduler")
 
-    def __init__(self, callable):
+    def __init__(self, deadline, callable):
+        self._deadline = deadline
         self._callable = callable
 
     def cancel(self):
@@ -213,6 +212,12 @@
         finally:
             self._callable = _INVALID
 
+    # Rich comparision support (required for Python 3).  This is the minimal
+    # implementation to allow pushing a call into a heap.
+
+    def __lt__(self, other):
+        return self._deadline < other._deadline
+
 
 # Sentinel for marking calls as invalid. Callable so we can invalidate a call
 # in a thread safe manner without locks.
diff --git a/tests/scheduleTests.py b/tests/scheduleTests.py
index 750f609..f9c4682 100644
--- a/tests/scheduleTests.py
+++ b/tests/scheduleTests.py
@@ -218,3 +218,35 @@
 
     def __call__(self):
         raise Exception("This task is broken")
+
+
+class TestScheduledCall(VdsmTestCase):
+
+    def setUp(self):
+        self.count = 0
+
+    def callback(self):
+        self.count += 1
+
+    def test_create(self):
+        call = schedule.ScheduledCall(0, self.callback)
+        self.assertEqual(0, self.count)
+        self.assertTrue(call.valid)
+
+    def test_execute(self):
+        call = schedule.ScheduledCall(0, self.callback)
+        call._execute()
+        self.assertEqual(1, self.count)
+        self.assertFalse(call.valid())
+
+    def test_execute_callback_once(self):
+        call = schedule.ScheduledCall(0, self.callback)
+        call._execute()
+        call._execute()
+        self.assertEqual(1, self.count)
+
+    def test_order(self):
+        now = utils.monotonic_time()
+        call_soon = schedule.ScheduledCall(now, self.callback)
+        call_later = schedule.ScheduledCall(now + 1, self.callback)
+        self.assertLess(call_soon, call_later)


-- 
To view, visit https://gerrit.ovirt.org/55880
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie6d20fe1a1d262d5489be5bedba929709fa59e35
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer at redhat.com>


More information about the vdsm-patches mailing list