diff --git a/changelog.d/13992.misc b/changelog.d/13992.misc
new file mode 100644
index 0000000000..58150a2b35
--- /dev/null
+++ b/changelog.d/13992.misc
@@ -0,0 +1 @@
+Speed up calculating push actions in large rooms.
diff --git a/synapse/push/bulk_push_rule_evaluator.py b/synapse/push/bulk_push_rule_evaluator.py
index 7bfe380543..4270438918 100644
--- a/synapse/push/bulk_push_rule_evaluator.py
+++ b/synapse/push/bulk_push_rule_evaluator.py
@@ -332,6 +332,11 @@ class BulkPushRuleEvaluator:
# Push rules say we should notify the user of this event
actions_by_user[uid] = actions
+ # If there aren't any actions then we can skip the rest of the
+ # processing.
+ if not actions_by_user:
+ return
+
# This is a check for the case where user joins a room without being
# allowed to see history, and then the server receives a delayed event
# from before the user joined, which they should not be pushed for
diff --git a/synapse/visibility.py b/synapse/visibility.py
index c810a05907..c4048d2477 100644
--- a/synapse/visibility.py
+++ b/synapse/visibility.py
@@ -162,6 +162,10 @@ async def filter_event_for_clients_with_state(
if event.internal_metadata.is_soft_failed():
return []
+ # Fast path if we don't have any user IDs to check.
+ if not user_ids:
+ return ()
+
# Make a set for all user IDs that haven't been filtered out by a check.
allowed_user_ids = set(user_ids)
diff --git a/tests/rest/client/test_rooms.py b/tests/rest/client/test_rooms.py
index e281aef779..7f8cf4fab0 100644
--- a/tests/rest/client/test_rooms.py
+++ b/tests/rest/client/test_rooms.py
@@ -710,7 +710,7 @@ class RoomsCreateTestCase(RoomBase):
self.assertEqual(HTTPStatus.OK, channel.code, channel.result)
self.assertTrue("room_id" in channel.json_body)
assert channel.resource_usage is not None
- self.assertEqual(35, channel.resource_usage.db_txn_count)
+ self.assertEqual(34, channel.resource_usage.db_txn_count)
def test_post_room_initial_state(self) -> None:
# POST with initial_state config key, expect new room id
@@ -723,7 +723,7 @@ class RoomsCreateTestCase(RoomBase):
self.assertEqual(HTTPStatus.OK, channel.code, channel.result)
self.assertTrue("room_id" in channel.json_body)
assert channel.resource_usage is not None
- self.assertEqual(38, channel.resource_usage.db_txn_count)
+ self.assertEqual(37, channel.resource_usage.db_txn_count)
def test_post_room_visibility_key(self) -> None:
# POST with visibility config key, expect new room id
|