Skip to content
This repository was archived by the owner on Mar 26, 2024. It is now read-only.

Commit 64e206f

Browse files
committed
Optimise room creation event lookups part 2 (matrix-org#13224)
1 parent c68a22c commit 64e206f

File tree

4 files changed

+78
-19
lines changed

4 files changed

+78
-19
lines changed

changelog.d/13224.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Further reduce queries used sending events when creating new rooms. Contributed by Nick @ Beeper (@fizzadar).

synapse/handlers/room.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,11 @@ async def create_room(
894894
# override any attempt to set room versions via the creation_content
895895
creation_content["room_version"] = room_version.identifier
896896

897-
last_stream_id = await self._send_events_for_new_room(
897+
(
898+
last_stream_id,
899+
last_sent_event_id,
900+
depth,
901+
) = await self._send_events_for_new_room(
898902
requester,
899903
room_id,
900904
preset_config=preset_config,
@@ -910,7 +914,7 @@ async def create_room(
910914
if "name" in config:
911915
name = config["name"]
912916
(
913-
_,
917+
name_event,
914918
last_stream_id,
915919
) = await self.event_creation_handler.create_and_send_nonmember_event(
916920
requester,
@@ -922,12 +926,16 @@ async def create_room(
922926
"content": {"name": name},
923927
},
924928
ratelimit=False,
929+
prev_event_ids=[last_sent_event_id],
930+
depth=depth,
925931
)
932+
last_sent_event_id = name_event.event_id
933+
depth += 1
926934

927935
if "topic" in config:
928936
topic = config["topic"]
929937
(
930-
_,
938+
topic_event,
931939
last_stream_id,
932940
) = await self.event_creation_handler.create_and_send_nonmember_event(
933941
requester,
@@ -939,7 +947,11 @@ async def create_room(
939947
"content": {"topic": topic},
940948
},
941949
ratelimit=False,
950+
prev_event_ids=[last_sent_event_id],
951+
depth=depth,
942952
)
953+
last_sent_event_id = topic_event.event_id
954+
depth += 1
943955

944956
# we avoid dropping the lock between invites, as otherwise joins can
945957
# start coming in and making the createRoom slow.
@@ -957,7 +969,7 @@ async def create_room(
957969

958970
for invitee in invite_list:
959971
(
960-
_,
972+
member_event_id,
961973
last_stream_id,
962974
) = await self.room_member_handler.update_membership_locked(
963975
requester,
@@ -967,7 +979,11 @@ async def create_room(
967979
ratelimit=False,
968980
content=content,
969981
new_room=True,
982+
prev_event_ids=[last_sent_event_id],
983+
depth=depth,
970984
)
985+
last_sent_event_id = member_event_id
986+
depth += 1
971987

972988
for invite_3pid in invite_3pid_list:
973989
id_server = invite_3pid["id_server"]
@@ -976,7 +992,10 @@ async def create_room(
976992
medium = invite_3pid["medium"]
977993
# Note that do_3pid_invite can raise a ShadowBanError, but this was
978994
# handled above by emptying invite_3pid_list.
979-
last_stream_id = await self.hs.get_room_member_handler().do_3pid_invite(
995+
(
996+
member_event_id,
997+
last_stream_id,
998+
) = await self.hs.get_room_member_handler().do_3pid_invite(
980999
room_id,
9811000
requester.user,
9821001
medium,
@@ -985,7 +1004,11 @@ async def create_room(
9851004
requester,
9861005
txn_id=None,
9871006
id_access_token=id_access_token,
1007+
prev_event_ids=[last_sent_event_id],
1008+
depth=depth,
9881009
)
1010+
last_sent_event_id = member_event_id
1011+
depth += 1
9891012

9901013
result = {"room_id": room_id}
9911014

@@ -1013,20 +1036,22 @@ async def _send_events_for_new_room(
10131036
power_level_content_override: Optional[JsonDict] = None,
10141037
creator_join_profile: Optional[JsonDict] = None,
10151038
ratelimit: bool = True,
1016-
) -> int:
1039+
) -> Tuple[int, str, int]:
10171040
"""Sends the initial events into a new room.
10181041
10191042
`power_level_content_override` doesn't apply when initial state has
10201043
power level state event content.
10211044
10221045
Returns:
1023-
The stream_id of the last event persisted.
1046+
A tuple containing the stream ID, event ID and depth of the last
1047+
event sent to the room.
10241048
"""
10251049

10261050
creator_id = creator.user.to_string()
10271051

10281052
event_keys = {"room_id": room_id, "sender": creator_id, "state_key": ""}
10291053

1054+
depth = 1
10301055
last_sent_event_id: Optional[str] = None
10311056

10321057
def create(etype: str, content: JsonDict, **kwargs: Any) -> JsonDict:
@@ -1039,6 +1064,7 @@ def create(etype: str, content: JsonDict, **kwargs: Any) -> JsonDict:
10391064

10401065
async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
10411066
nonlocal last_sent_event_id
1067+
nonlocal depth
10421068

10431069
event = create(etype, content, **kwargs)
10441070
logger.debug("Sending %s in new room", etype)
@@ -1055,9 +1081,11 @@ async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
10551081
# Note: we don't pass state_event_ids here because this triggers
10561082
# an additional query per event to look them up from the events table.
10571083
prev_event_ids=[last_sent_event_id] if last_sent_event_id else [],
1084+
depth=depth,
10581085
)
10591086

10601087
last_sent_event_id = sent_event.event_id
1088+
depth += 1
10611089

10621090
return last_stream_id
10631091

@@ -1083,6 +1111,7 @@ async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
10831111
content=creator_join_profile,
10841112
new_room=True,
10851113
prev_event_ids=[last_sent_event_id],
1114+
depth=depth,
10861115
)
10871116
last_sent_event_id = member_event_id
10881117

@@ -1176,7 +1205,7 @@ async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
11761205
content={"algorithm": RoomEncryptionAlgorithms.DEFAULT},
11771206
)
11781207

1179-
return last_sent_stream_id
1208+
return last_sent_stream_id, last_sent_event_id, depth
11801209

11811210
def _generate_room_id(self) -> str:
11821211
"""Generates a random room ID.

synapse/handlers/room_member.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ async def _local_membership_update(
269269
allow_no_prev_events: bool = False,
270270
prev_event_ids: Optional[List[str]] = None,
271271
state_event_ids: Optional[List[str]] = None,
272+
depth: Optional[int] = None,
272273
txn_id: Optional[str] = None,
273274
ratelimit: bool = True,
274275
content: Optional[dict] = None,
@@ -299,6 +300,9 @@ async def _local_membership_update(
299300
prev_events are set so we need to set them ourself via this argument.
300301
This should normally be left as None, which will cause the auth_event_ids
301302
to be calculated based on the room state at the prev_events.
303+
depth: Override the depth used to order the event in the DAG.
304+
Should normally be set to None, which will cause the depth to be calculated
305+
based on the prev_events.
302306
303307
txn_id:
304308
ratelimit:
@@ -354,6 +358,7 @@ async def _local_membership_update(
354358
allow_no_prev_events=allow_no_prev_events,
355359
prev_event_ids=prev_event_ids,
356360
state_event_ids=state_event_ids,
361+
depth=depth,
357362
require_consent=require_consent,
358363
outlier=outlier,
359364
historical=historical,
@@ -450,6 +455,7 @@ async def update_membership(
450455
allow_no_prev_events: bool = False,
451456
prev_event_ids: Optional[List[str]] = None,
452457
state_event_ids: Optional[List[str]] = None,
458+
depth: Optional[int] = None,
453459
) -> Tuple[str, int]:
454460
"""Update a user's membership in a room.
455461
@@ -485,6 +491,9 @@ async def update_membership(
485491
prev_events are set so we need to set them ourself via this argument.
486492
This should normally be left as None, which will cause the auth_event_ids
487493
to be calculated based on the room state at the prev_events.
494+
depth: Override the depth used to order the event in the DAG.
495+
Should normally be set to None, which will cause the depth to be calculated
496+
based on the prev_events.
488497
489498
Returns:
490499
A tuple of the new event ID and stream ID.
@@ -524,6 +533,7 @@ async def update_membership(
524533
allow_no_prev_events=allow_no_prev_events,
525534
prev_event_ids=prev_event_ids,
526535
state_event_ids=state_event_ids,
536+
depth=depth,
527537
)
528538

529539
return result
@@ -546,6 +556,7 @@ async def update_membership_locked(
546556
allow_no_prev_events: bool = False,
547557
prev_event_ids: Optional[List[str]] = None,
548558
state_event_ids: Optional[List[str]] = None,
559+
depth: Optional[int] = None,
549560
) -> Tuple[str, int]:
550561
"""Helper for update_membership.
551562
@@ -583,6 +594,9 @@ async def update_membership_locked(
583594
prev_events are set so we need to set them ourself via this argument.
584595
This should normally be left as None, which will cause the auth_event_ids
585596
to be calculated based on the room state at the prev_events.
597+
depth: Override the depth used to order the event in the DAG.
598+
Should normally be set to None, which will cause the depth to be calculated
599+
based on the prev_events.
586600
587601
Returns:
588602
A tuple of the new event ID and stream ID.
@@ -713,6 +727,7 @@ async def update_membership_locked(
713727
allow_no_prev_events=allow_no_prev_events,
714728
prev_event_ids=prev_event_ids,
715729
state_event_ids=state_event_ids,
730+
depth=depth,
716731
content=content,
717732
require_consent=require_consent,
718733
outlier=outlier,
@@ -929,6 +944,7 @@ async def update_membership_locked(
929944
ratelimit=ratelimit,
930945
prev_event_ids=latest_event_ids,
931946
state_event_ids=state_event_ids,
947+
depth=depth,
932948
content=content,
933949
require_consent=require_consent,
934950
outlier=outlier,
@@ -1284,7 +1300,9 @@ async def do_3pid_invite(
12841300
requester: Requester,
12851301
txn_id: Optional[str],
12861302
id_access_token: Optional[str] = None,
1287-
) -> int:
1303+
prev_event_ids: Optional[List[str]] = None,
1304+
depth: Optional[int] = None,
1305+
) -> Tuple[str, int]:
12881306
"""Invite a 3PID to a room.
12891307
12901308
Args:
@@ -1297,9 +1315,13 @@ async def do_3pid_invite(
12971315
txn_id: The transaction ID this is part of, or None if this is not
12981316
part of a transaction.
12991317
id_access_token: The optional identity server access token.
1318+
depth: Override the depth used to order the event in the DAG.
1319+
prev_event_ids: The event IDs to use as the prev events
1320+
Should normally be set to None, which will cause the depth to be calculated
1321+
based on the prev_events.
13001322
13011323
Returns:
1302-
The new stream ID.
1324+
Tuple of event ID and stream ordering position
13031325
13041326
Raises:
13051327
ShadowBanError if the requester has been shadow-banned.
@@ -1345,7 +1367,7 @@ async def do_3pid_invite(
13451367
# We don't check the invite against the spamchecker(s) here (through
13461368
# user_may_invite) because we'll do it further down the line anyway (in
13471369
# update_membership_locked).
1348-
_, stream_id = await self.update_membership(
1370+
event_id, stream_id = await self.update_membership(
13491371
requester, UserID.from_string(invitee), room_id, "invite", txn_id=txn_id
13501372
)
13511373
else:
@@ -1359,7 +1381,7 @@ async def do_3pid_invite(
13591381
if spam_check != NOT_SPAM:
13601382
raise SynapseError(403, "Cannot send threepid invite", spam_check)
13611383

1362-
stream_id = await self._make_and_store_3pid_invite(
1384+
event, stream_id = await self._make_and_store_3pid_invite(
13631385
requester,
13641386
id_server,
13651387
medium,
@@ -1368,9 +1390,12 @@ async def do_3pid_invite(
13681390
inviter,
13691391
txn_id=txn_id,
13701392
id_access_token=id_access_token,
1393+
prev_event_ids=prev_event_ids,
1394+
depth=depth,
13711395
)
1396+
event_id = event.event_id
13721397

1373-
return stream_id
1398+
return event_id, stream_id
13741399

13751400
async def _make_and_store_3pid_invite(
13761401
self,
@@ -1382,7 +1407,9 @@ async def _make_and_store_3pid_invite(
13821407
user: UserID,
13831408
txn_id: Optional[str],
13841409
id_access_token: Optional[str] = None,
1385-
) -> int:
1410+
prev_event_ids: Optional[List[str]] = None,
1411+
depth: Optional[int] = None,
1412+
) -> Tuple[EventBase, int]:
13861413
room_state = await self._storage_controllers.state.get_current_state(
13871414
room_id,
13881415
StateFilter.from_types(
@@ -1475,8 +1502,10 @@ async def _make_and_store_3pid_invite(
14751502
},
14761503
ratelimit=False,
14771504
txn_id=txn_id,
1505+
prev_event_ids=prev_event_ids,
1506+
depth=depth,
14781507
)
1479-
return stream_id
1508+
return event, stream_id
14801509

14811510
async def _is_host_in_room(self, current_state_ids: StateMap[str]) -> bool:
14821511
# Have we just created the room, and is this about to be the very

tests/rest/client/test_rooms.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ def test_post_room_no_keys(self) -> None:
707707
self.assertEqual(200, channel.code, channel.result)
708708
self.assertTrue("room_id" in channel.json_body)
709709
assert channel.resource_usage is not None
710-
self.assertEqual(33, channel.resource_usage.db_txn_count)
710+
self.assertEqual(32, channel.resource_usage.db_txn_count)
711711

712712
def test_post_room_initial_state(self) -> None:
713713
# POST with initial_state config key, expect new room id
@@ -720,7 +720,7 @@ def test_post_room_initial_state(self) -> None:
720720
self.assertEqual(200, channel.code, channel.result)
721721
self.assertTrue("room_id" in channel.json_body)
722722
assert channel.resource_usage is not None
723-
self.assertEqual(37, channel.resource_usage.db_txn_count)
723+
self.assertEqual(35, channel.resource_usage.db_txn_count)
724724

725725
def test_post_room_visibility_key(self) -> None:
726726
# POST with visibility config key, expect new room id
@@ -3065,7 +3065,7 @@ def test_threepid_invite_spamcheck_deprecated(self) -> None:
30653065
# Mock a few functions to prevent the test from failing due to failing to talk to
30663066
# a remote IS. We keep the mock for make_and_store_3pid_invite around so we
30673067
# can check its call_count later on during the test.
3068-
make_invite_mock = Mock(return_value=make_awaitable(0))
3068+
make_invite_mock = Mock(return_value=make_awaitable((Mock(event_id="abc"), 0)))
30693069
self.hs.get_room_member_handler()._make_and_store_3pid_invite = make_invite_mock
30703070
self.hs.get_identity_handler().lookup_3pid = Mock(
30713071
return_value=make_awaitable(None),
@@ -3126,7 +3126,7 @@ def test_threepid_invite_spamcheck(self) -> None:
31263126
# Mock a few functions to prevent the test from failing due to failing to talk to
31273127
# a remote IS. We keep the mock for make_and_store_3pid_invite around so we
31283128
# can check its call_count later on during the test.
3129-
make_invite_mock = Mock(return_value=make_awaitable(0))
3129+
make_invite_mock = Mock(return_value=make_awaitable((Mock(event_id="abc"), 0)))
31303130
self.hs.get_room_member_handler()._make_and_store_3pid_invite = make_invite_mock
31313131
self.hs.get_identity_handler().lookup_3pid = Mock(
31323132
return_value=make_awaitable(None),

0 commit comments

Comments
 (0)