summary refs log tree commit diff
path: root/tests/util/test_rwlock.py
diff options
context:
space:
mode:
authorSean Quah <8349537+squahtx@users.noreply.github.com>2022-03-01 15:27:15 +0000
committerGitHub <noreply@github.com>2022-03-01 15:27:15 +0000
commit4d6b6c17c860a6ef258e513d841dbda6ea151cbd (patch)
tree1ab3f9180e5b6f1931d442536dc63559a1950420 /tests/util/test_rwlock.py
parentAdd module callbacks called for reacting to deactivation status change and pr... (diff)
downloadsynapse-4d6b6c17c860a6ef258e513d841dbda6ea151cbd.tar.xz
Fix rare error in `ReadWriteLock` when writers complete immediately (#12105)
Signed-off-by: Sean Quah <seanq@element.io>
Diffstat (limited to 'tests/util/test_rwlock.py')
-rw-r--r--tests/util/test_rwlock.py30
1 files changed, 30 insertions, 0 deletions
diff --git a/tests/util/test_rwlock.py b/tests/util/test_rwlock.py
index a10071c70f..0774625b85 100644
--- a/tests/util/test_rwlock.py
+++ b/tests/util/test_rwlock.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 from twisted.internet import defer
+from twisted.internet.defer import Deferred
 
 from synapse.util.async_helpers import ReadWriteLock
 
@@ -83,3 +84,32 @@ class ReadWriteLockTestCase(unittest.TestCase):
         self.assertTrue(d.called)
         with d.result:
             pass
+
+    def test_lock_handoff_to_nonblocking_writer(self):
+        """Test a writer handing the lock to another writer that completes instantly."""
+        rwlock = ReadWriteLock()
+        key = "key"
+
+        unblock: "Deferred[None]" = Deferred()
+
+        async def blocking_write():
+            with await rwlock.write(key):
+                await unblock
+
+        async def nonblocking_write():
+            with await rwlock.write(key):
+                pass
+
+        d1 = defer.ensureDeferred(blocking_write())
+        d2 = defer.ensureDeferred(nonblocking_write())
+        self.assertFalse(d1.called)
+        self.assertFalse(d2.called)
+
+        # Unblock the first writer. The second writer will complete without blocking.
+        unblock.callback(None)
+        self.assertTrue(d1.called)
+        self.assertTrue(d2.called)
+
+        # The `ReadWriteLock` should operate as normal.
+        d3 = defer.ensureDeferred(nonblocking_write())
+        self.assertTrue(d3.called)