Change in vdsm[master]: rwlock: Support timed acquire

nsoffer at redhat.com nsoffer at redhat.com
Thu Jun 25 21:11:53 UTC 2015


Nir Soffer has uploaded a new change for review.

Change subject: rwlock: Support timed acquire
......................................................................

rwlock: Support timed acquire

Add acquire timeout - with timeout=0, can be used to implement
non-blocking acquire. With bigger timeout, make it easy to fail a
request after a timeout, instead of leaving a blocked thread forever.

Change-Id: Idd9b11452d74b566b8989f41244f2d0534327214
Signed-off-by: Nir Soffer <nsoffer at redhat.com>
---
M lib/vdsm/rwlock.py
M tests/rwlock_test.py
2 files changed, 65 insertions(+), 21 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/09/42909/1

diff --git a/lib/vdsm/rwlock.py b/lib/vdsm/rwlock.py
index 900d91d..72f962c 100644
--- a/lib/vdsm/rwlock.py
+++ b/lib/vdsm/rwlock.py
@@ -22,6 +22,10 @@
 import threading
 
 
+class Timeout(Exception):
+    pass
+
+
 class RWLock(object):
 
     def __init__(self):
@@ -30,16 +34,16 @@
         self._readers = set()
         self._writer = None
 
-    def acquireWrite(self):
+    def acquireWrite(self, timeout=None):
         with self._lock:
             if self._writer or self._readers or self._waiters:
-                self._wait(True)
+                self._wait(True, timeout)
             self._writer = threading.current_thread()
 
-    def acquireRead(self):
+    def acquireRead(self, timeout=None):
         with self._lock:
             if self._writer or self._waiters:
-                self._wait(False)
+                self._wait(False, timeout)
             self._readers.add(threading.current_thread())
 
     def release(self):
@@ -60,13 +64,13 @@
             if self._waiters:
                 self._wakeup_waiter()
 
-    def _wait(self, wants_write):
+    def _wait(self, wants_write, timeout):
         waiter = Waiter(wants_write)
         self._waiters.append(waiter)
         try:
             self._lock.release()
             try:
-                waiter.wait()
+                waiter.wait(timeout)
             finally:
                 self._lock.acquire()
         finally:
@@ -84,8 +88,10 @@
         self.wants_write = wants_write
         self._event = threading.Event()
 
-    def wait(self):
-        self._event.wait()
+    def wait(self, timeout):
+        if not self._event.wait(timeout):
+            raise Timeout("Timeout acquiring lock for %s" %
+                          "writing" if self.wants_write else "reading")
 
     def wakeup(self):
         self._event.set()
diff --git a/tests/rwlock_test.py b/tests/rwlock_test.py
index e67e27a..5ddf066 100644
--- a/tests/rwlock_test.py
+++ b/tests/rwlock_test.py
@@ -25,10 +25,40 @@
 from testlib import VdsmTestCase
 from testValidation import slowtest, stresstest
 
-from vdsm.rwlock import RWLock
+from vdsm.rwlock import RWLock, Timeout
 
 
 class RWLockTests(VdsmTestCase):
+
+    def test_writer_blocks_other_writer(self):
+        lock = RWLock()
+        lock.acquireWrite()
+        try:
+            log = []
+            start_thread(writer, lock, log, timeout=0).join()
+            self.assertEqual(log, ["writer timeout"])
+        finally:
+            lock.release()
+
+    def test_writer_blocks_other_reader(self):
+        lock = RWLock()
+        lock.acquireWrite()
+        try:
+            log = []
+            start_thread(reader, lock, log, timeout=0).join()
+            self.assertEqual(log, ["reader timeout"])
+        finally:
+            lock.release()
+
+    def test_reader_blocks_other_writer(self):
+        lock = RWLock()
+        lock.acquireRead()
+        try:
+            log = []
+            start_thread(writer, lock, log, timeout=0).join()
+            self.assertEqual(log, ["writer timeout"])
+        finally:
+            lock.release()
 
     @slowtest
     def test_concurrent_readers(self):
@@ -194,22 +224,30 @@
         self.assertEqual(log, ["reader acquired"])
 
 
-def writer(lock, log, hold=0):
-    lock.acquireWrite()
+def writer(lock, log, timeout=1, hold=0):
     try:
-        log.append("writer acquired")
-        time.sleep(hold)
-    finally:
-        lock.release()
+        lock.acquireWrite(timeout)
+    except Timeout:
+        log.append("writer timeout")
+    else:
+        try:
+            log.append("writer acquired")
+            time.sleep(hold)
+        finally:
+            lock.release()
 
 
-def reader(lock, log, hold=0):
-    lock.acquireRead()
+def reader(lock, log, timeout=1, hold=0):
     try:
-        log.append("reader acquired")
-        time.sleep(hold)
-    finally:
-        lock.release()
+        lock.acquireRead(timeout)
+    except Timeout:
+        log.append("reader timeout")
+    else:
+        try:
+            log.append("reader acquired")
+            time.sleep(hold)
+        finally:
+            lock.release()
 
 
 def start_thread(func, *args, **kwargs):


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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Idd9b11452d74b566b8989f41244f2d0534327214
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