summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Johnston <erikj@element.io>2024-02-20 14:29:18 +0000
committerGitHub <noreply@github.com>2024-02-20 14:29:18 +0000
commitcdbbf3653d02e94b8c73f5533a50cab004a3f41a (patch)
treed3fa74976dadf98790f280b22a261923a18a8ccf
parentbugfix: always prefer unthreaded receipt when >1 exist (MSC4102) (#16927) (diff)
downloadsynapse-cdbbf3653d02e94b8c73f5533a50cab004a3f41a.tar.xz
Don't lock up when joining large rooms (#16903)
Co-authored-by: Andrew Morgan <andrew@amorgan.xyz>
-rw-r--r--changelog.d/16903.bugfix1
-rw-r--r--synapse/handlers/federation_event.py26
2 files changed, 18 insertions, 9 deletions
diff --git a/changelog.d/16903.bugfix b/changelog.d/16903.bugfix
new file mode 100644

index 0000000000..85a909b681 --- /dev/null +++ b/changelog.d/16903.bugfix
@@ -0,0 +1 @@ +Fix performance issue when joining very large rooms that can cause the server to lock up. Introduced in v1.100.0. diff --git a/synapse/handlers/federation_event.py b/synapse/handlers/federation_event.py
index bde45308d4..83f6a25981 100644 --- a/synapse/handlers/federation_event.py +++ b/synapse/handlers/federation_event.py
@@ -1757,17 +1757,25 @@ class FederationEventHandler: events_and_contexts_to_persist.append((event, context)) - for event in sorted_auth_events: + for i, event in enumerate(sorted_auth_events): await prep(event) - await self.persist_events_and_notify( - room_id, - events_and_contexts_to_persist, - # Mark these events backfilled as they're historic events that will - # eventually be backfilled. For example, missing events we fetch - # during backfill should be marked as backfilled as well. - backfilled=True, - ) + # The above function is typically not async, and so won't yield to + # the reactor. For large rooms let's yield to the reactor + # occasionally to ensure we don't block other work. + if (i + 1) % 1000 == 0: + await self._clock.sleep(0) + + # Also persist the new event in batches for similar reasons as above. + for batch in batch_iter(events_and_contexts_to_persist, 1000): + await self.persist_events_and_notify( + room_id, + batch, + # Mark these events as backfilled as they're historic events that will + # eventually be backfilled. For example, missing events we fetch + # during backfill should be marked as backfilled as well. + backfilled=True, + ) @trace async def _check_event_auth(