summary refs log tree commit diff
path: root/synapse
diff options
context:
space:
mode:
authorMathieu Velten <matmaul@gmail.com>2024-03-14 14:49:54 +0100
committerGitHub <noreply@github.com>2024-03-14 13:49:54 +0000
commitcb562d73aaa592c05b96672724ba296d02cee896 (patch)
treeeead02d23e1dbb580e0a7410894be84d02d70ddb /synapse
parentBump types-psycopg2 from 2.9.21.16 to 2.9.21.20240311 (#16995) (diff)
downloadsynapse-cb562d73aaa592c05b96672724ba296d02cee896.tar.xz
Improve lock performance when a lot of locks are waiting (#16840)
When a lot of locks are waiting for a single lock, notifying all locks
independently with `call_later` on each release is really costly and
incurs some kind of async contention, where the CPU is spinning a lot
for not much.

The included test is taking around 30s before the change, and 0.5s
after.

It was found following failing tests with
https://github.com/element-hq/synapse/pull/16827.
Diffstat (limited to 'synapse')
-rw-r--r--synapse/handlers/worker_lock.py15
1 files changed, 9 insertions, 6 deletions
diff --git a/synapse/handlers/worker_lock.py b/synapse/handlers/worker_lock.py
index a870fd1124..7e578cf462 100644
--- a/synapse/handlers/worker_lock.py
+++ b/synapse/handlers/worker_lock.py
@@ -182,12 +182,15 @@ class WorkerLocksHandler:
         if not locks:
             return
 
-        def _wake_deferred(deferred: defer.Deferred) -> None:
-            if not deferred.called:
-                deferred.callback(None)
-
-        for lock in locks:
-            self._clock.call_later(0, _wake_deferred, lock.deferred)
+        def _wake_all_locks(
+            locks: Collection[Union[WaitingLock, WaitingMultiLock]]
+        ) -> None:
+            for lock in locks:
+                deferred = lock.deferred
+                if not deferred.called:
+                    deferred.callback(None)
+
+        self._clock.call_later(0, _wake_all_locks, locks)
 
     @wrap_as_background_process("_cleanup_locks")
     async def _cleanup_locks(self) -> None: