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

Commit 982fe29

Browse files
authored
Optimise room creation event lookups part 2 (#13224)
1 parent 1d5c80b commit 982fe29

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
@@ -889,7 +889,11 @@ async def create_room(
889889
# override any attempt to set room versions via the creation_content
890890
creation_content["room_version"] = room_version.identifier
891891

892-
last_stream_id = await self._send_events_for_new_room(
892+
(
893+
last_stream_id,
894+
last_sent_event_id,
895+
depth,
896+
) = await self._send_events_for_new_room(
893897
requester,
894898
room_id,
895899
preset_config=preset_config,
@@ -905,7 +909,7 @@ async def create_room(
905909
if "name" in config:
906910
name = config["name"]
907911
(
908-
_,
912+
name_event,
909913
last_stream_id,
910914
) = await self.event_creation_handler.create_and_send_nonmember_event(
911915
requester,
@@ -917,12 +921,16 @@ async def create_room(
917921
"content": {"name": name},
918922
},
919923
ratelimit=False,
924+
prev_event_ids=[last_sent_event_id],
925+
depth=depth,
920926
)
927+
last_sent_event_id = name_event.event_id
928+
depth += 1
921929

922930
if "topic" in config:
923931
topic = config["topic"]
924932
(
925-
_,
933+
topic_event,
926934
last_stream_id,
927935
) = await self.event_creation_handler.create_and_send_nonmember_event(
928936
requester,
@@ -934,7 +942,11 @@ async def create_room(
934942
"content": {"topic": topic},
935943
},
936944
ratelimit=False,
945+
prev_event_ids=[last_sent_event_id],
946+
depth=depth,
937947
)
948+
last_sent_event_id = topic_event.event_id
949+
depth += 1
938950

939951
# we avoid dropping the lock between invites, as otherwise joins can
940952
# start coming in and making the createRoom slow.
@@ -949,7 +961,7 @@ async def create_room(
949961

950962
for invitee in invite_list:
951963
(
952-
_,
964+
member_event_id,
953965
last_stream_id,
954966
) = await self.room_member_handler.update_membership_locked(
955967
requester,
@@ -959,7 +971,11 @@ async def create_room(
959971
ratelimit=False,
960972
content=content,
961973
new_room=True,
974+
prev_event_ids=[last_sent_event_id],
975+
depth=depth,
962976
)
977+
last_sent_event_id = member_event_id
978+
depth += 1
963979

964980
for invite_3pid in invite_3pid_list:
965981
id_server = invite_3pid["id_server"]
@@ -968,7 +984,10 @@ async def create_room(
968984
medium = invite_3pid["medium"]
969985
# Note that do_3pid_invite can raise a ShadowBanError, but this was
970986
# handled above by emptying invite_3pid_list.
971-
last_stream_id = await self.hs.get_room_member_handler().do_3pid_invite(
987+
(
988+
member_event_id,
989+
last_stream_id,
990+
) = await self.hs.get_room_member_handler().do_3pid_invite(
972991
room_id,
973992
requester.user,
974993
medium,
@@ -977,7 +996,11 @@ async def create_room(
977996
requester,
978997
txn_id=None,
979998
id_access_token=id_access_token,
999+
prev_event_ids=[last_sent_event_id],
1000+
depth=depth,
9801001
)
1002+
last_sent_event_id = member_event_id
1003+
depth += 1
9811004

9821005
result = {"room_id": room_id}
9831006

@@ -1005,20 +1028,22 @@ async def _send_events_for_new_room(
10051028
power_level_content_override: Optional[JsonDict] = None,
10061029
creator_join_profile: Optional[JsonDict] = None,
10071030
ratelimit: bool = True,
1008-
) -> int:
1031+
) -> Tuple[int, str, int]:
10091032
"""Sends the initial events into a new room.
10101033
10111034
`power_level_content_override` doesn't apply when initial state has
10121035
power level state event content.
10131036
10141037
Returns:
1015-
The stream_id of the last event persisted.
1038+
A tuple containing the stream ID, event ID and depth of the last
1039+
event sent to the room.
10161040
"""
10171041

10181042
creator_id = creator.user.to_string()
10191043

10201044
event_keys = {"room_id": room_id, "sender": creator_id, "state_key": ""}
10211045

1046+
depth = 1
10221047
last_sent_event_id: Optional[str] = None
10231048

10241049
def create(etype: str, content: JsonDict, **kwargs: Any) -> JsonDict:
@@ -1031,6 +1056,7 @@ def create(etype: str, content: JsonDict, **kwargs: Any) -> JsonDict:
10311056

10321057
async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
10331058
nonlocal last_sent_event_id
1059+
nonlocal depth
10341060

10351061
event = create(etype, content, **kwargs)
10361062
logger.debug("Sending %s in new room", etype)
@@ -1047,9 +1073,11 @@ async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
10471073
# Note: we don't pass state_event_ids here because this triggers
10481074
# an additional query per event to look them up from the events table.
10491075
prev_event_ids=[last_sent_event_id] if last_sent_event_id else [],
1076+
depth=depth,
10501077
)
10511078

10521079
last_sent_event_id = sent_event.event_id
1080+
depth += 1
10531081

10541082
return last_stream_id
10551083

@@ -1075,6 +1103,7 @@ async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
10751103
content=creator_join_profile,
10761104
new_room=True,
10771105
prev_event_ids=[last_sent_event_id],
1106+
depth=depth,
10781107
)
10791108
last_sent_event_id = member_event_id
10801109

@@ -1168,7 +1197,7 @@ async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
11681197
content={"algorithm": RoomEncryptionAlgorithms.DEFAULT},
11691198
)
11701199

1171-
return last_sent_stream_id
1200+
return last_sent_stream_id, last_sent_event_id, depth
11721201

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

synapse/handlers/room_member.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ async def _local_membership_update(
285285
allow_no_prev_events: bool = False,
286286
prev_event_ids: Optional[List[str]] = None,
287287
state_event_ids: Optional[List[str]] = None,
288+
depth: Optional[int] = None,
288289
txn_id: Optional[str] = None,
289290
ratelimit: bool = True,
290291
content: Optional[dict] = None,
@@ -315,6 +316,9 @@ async def _local_membership_update(
315316
prev_events are set so we need to set them ourself via this argument.
316317
This should normally be left as None, which will cause the auth_event_ids
317318
to be calculated based on the room state at the prev_events.
319+
depth: Override the depth used to order the event in the DAG.
320+
Should normally be set to None, which will cause the depth to be calculated
321+
based on the prev_events.
318322
319323
txn_id:
320324
ratelimit:
@@ -370,6 +374,7 @@ async def _local_membership_update(
370374
allow_no_prev_events=allow_no_prev_events,
371375
prev_event_ids=prev_event_ids,
372376
state_event_ids=state_event_ids,
377+
depth=depth,
373378
require_consent=require_consent,
374379
outlier=outlier,
375380
historical=historical,
@@ -466,6 +471,7 @@ async def update_membership(
466471
allow_no_prev_events: bool = False,
467472
prev_event_ids: Optional[List[str]] = None,
468473
state_event_ids: Optional[List[str]] = None,
474+
depth: Optional[int] = None,
469475
) -> Tuple[str, int]:
470476
"""Update a user's membership in a room.
471477
@@ -501,6 +507,9 @@ async def update_membership(
501507
prev_events are set so we need to set them ourself via this argument.
502508
This should normally be left as None, which will cause the auth_event_ids
503509
to be calculated based on the room state at the prev_events.
510+
depth: Override the depth used to order the event in the DAG.
511+
Should normally be set to None, which will cause the depth to be calculated
512+
based on the prev_events.
504513
505514
Returns:
506515
A tuple of the new event ID and stream ID.
@@ -540,6 +549,7 @@ async def update_membership(
540549
allow_no_prev_events=allow_no_prev_events,
541550
prev_event_ids=prev_event_ids,
542551
state_event_ids=state_event_ids,
552+
depth=depth,
543553
)
544554

545555
return result
@@ -562,6 +572,7 @@ async def update_membership_locked(
562572
allow_no_prev_events: bool = False,
563573
prev_event_ids: Optional[List[str]] = None,
564574
state_event_ids: Optional[List[str]] = None,
575+
depth: Optional[int] = None,
565576
) -> Tuple[str, int]:
566577
"""Helper for update_membership.
567578
@@ -599,6 +610,9 @@ async def update_membership_locked(
599610
prev_events are set so we need to set them ourself via this argument.
600611
This should normally be left as None, which will cause the auth_event_ids
601612
to be calculated based on the room state at the prev_events.
613+
depth: Override the depth used to order the event in the DAG.
614+
Should normally be set to None, which will cause the depth to be calculated
615+
based on the prev_events.
602616
603617
Returns:
604618
A tuple of the new event ID and stream ID.
@@ -732,6 +746,7 @@ async def update_membership_locked(
732746
allow_no_prev_events=allow_no_prev_events,
733747
prev_event_ids=prev_event_ids,
734748
state_event_ids=state_event_ids,
749+
depth=depth,
735750
content=content,
736751
require_consent=require_consent,
737752
outlier=outlier,
@@ -967,6 +982,7 @@ async def update_membership_locked(
967982
ratelimit=ratelimit,
968983
prev_event_ids=latest_event_ids,
969984
state_event_ids=state_event_ids,
985+
depth=depth,
970986
content=content,
971987
require_consent=require_consent,
972988
outlier=outlier,
@@ -1322,7 +1338,9 @@ async def do_3pid_invite(
13221338
requester: Requester,
13231339
txn_id: Optional[str],
13241340
id_access_token: Optional[str] = None,
1325-
) -> int:
1341+
prev_event_ids: Optional[List[str]] = None,
1342+
depth: Optional[int] = None,
1343+
) -> Tuple[str, int]:
13261344
"""Invite a 3PID to a room.
13271345
13281346
Args:
@@ -1335,9 +1353,13 @@ async def do_3pid_invite(
13351353
txn_id: The transaction ID this is part of, or None if this is not
13361354
part of a transaction.
13371355
id_access_token: The optional identity server access token.
1356+
depth: Override the depth used to order the event in the DAG.
1357+
prev_event_ids: The event IDs to use as the prev events
1358+
Should normally be set to None, which will cause the depth to be calculated
1359+
based on the prev_events.
13381360
13391361
Returns:
1340-
The new stream ID.
1362+
Tuple of event ID and stream ordering position
13411363
13421364
Raises:
13431365
ShadowBanError if the requester has been shadow-banned.
@@ -1383,7 +1405,7 @@ async def do_3pid_invite(
13831405
# We don't check the invite against the spamchecker(s) here (through
13841406
# user_may_invite) because we'll do it further down the line anyway (in
13851407
# update_membership_locked).
1386-
_, stream_id = await self.update_membership(
1408+
event_id, stream_id = await self.update_membership(
13871409
requester, UserID.from_string(invitee), room_id, "invite", txn_id=txn_id
13881410
)
13891411
else:
@@ -1402,7 +1424,7 @@ async def do_3pid_invite(
14021424
additional_fields=spam_check[1],
14031425
)
14041426

1405-
stream_id = await self._make_and_store_3pid_invite(
1427+
event, stream_id = await self._make_and_store_3pid_invite(
14061428
requester,
14071429
id_server,
14081430
medium,
@@ -1411,9 +1433,12 @@ async def do_3pid_invite(
14111433
inviter,
14121434
txn_id=txn_id,
14131435
id_access_token=id_access_token,
1436+
prev_event_ids=prev_event_ids,
1437+
depth=depth,
14141438
)
1439+
event_id = event.event_id
14151440

1416-
return stream_id
1441+
return event_id, stream_id
14171442

14181443
async def _make_and_store_3pid_invite(
14191444
self,
@@ -1425,7 +1450,9 @@ async def _make_and_store_3pid_invite(
14251450
user: UserID,
14261451
txn_id: Optional[str],
14271452
id_access_token: Optional[str] = None,
1428-
) -> int:
1453+
prev_event_ids: Optional[List[str]] = None,
1454+
depth: Optional[int] = None,
1455+
) -> Tuple[EventBase, int]:
14291456
room_state = await self._storage_controllers.state.get_current_state(
14301457
room_id,
14311458
StateFilter.from_types(
@@ -1518,8 +1545,10 @@ async def _make_and_store_3pid_invite(
15181545
},
15191546
ratelimit=False,
15201547
txn_id=txn_id,
1548+
prev_event_ids=prev_event_ids,
1549+
depth=depth,
15211550
)
1522-
return stream_id
1551+
return event, stream_id
15231552

15241553
async def _is_host_in_room(self, current_state_ids: StateMap[str]) -> bool:
15251554
# 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
@@ -709,7 +709,7 @@ def test_post_room_no_keys(self) -> None:
709709
self.assertEqual(200, channel.code, channel.result)
710710
self.assertTrue("room_id" in channel.json_body)
711711
assert channel.resource_usage is not None
712-
self.assertEqual(37, channel.resource_usage.db_txn_count)
712+
self.assertEqual(32, channel.resource_usage.db_txn_count)
713713

714714
def test_post_room_initial_state(self) -> None:
715715
# POST with initial_state config key, expect new room id
@@ -722,7 +722,7 @@ def test_post_room_initial_state(self) -> None:
722722
self.assertEqual(200, channel.code, channel.result)
723723
self.assertTrue("room_id" in channel.json_body)
724724
assert channel.resource_usage is not None
725-
self.assertEqual(41, channel.resource_usage.db_txn_count)
725+
self.assertEqual(35, channel.resource_usage.db_txn_count)
726726

727727
def test_post_room_visibility_key(self) -> None:
728728
# POST with visibility config key, expect new room id
@@ -3283,7 +3283,7 @@ def test_threepid_invite_spamcheck_deprecated(self) -> None:
32833283
# Mock a few functions to prevent the test from failing due to failing to talk to
32843284
# a remote IS. We keep the mock for make_and_store_3pid_invite around so we
32853285
# can check its call_count later on during the test.
3286-
make_invite_mock = Mock(return_value=make_awaitable(0))
3286+
make_invite_mock = Mock(return_value=make_awaitable((Mock(event_id="abc"), 0)))
32873287
self.hs.get_room_member_handler()._make_and_store_3pid_invite = make_invite_mock
32883288
self.hs.get_identity_handler().lookup_3pid = Mock(
32893289
return_value=make_awaitable(None),
@@ -3344,7 +3344,7 @@ def test_threepid_invite_spamcheck(self) -> None:
33443344
# Mock a few functions to prevent the test from failing due to failing to talk to
33453345
# a remote IS. We keep the mock for make_and_store_3pid_invite around so we
33463346
# can check its call_count later on during the test.
3347-
make_invite_mock = Mock(return_value=make_awaitable(0))
3347+
make_invite_mock = Mock(return_value=make_awaitable((Mock(event_id="abc"), 0)))
33483348
self.hs.get_room_member_handler()._make_and_store_3pid_invite = make_invite_mock
33493349
self.hs.get_identity_handler().lookup_3pid = Mock(
33503350
return_value=make_awaitable(None),

0 commit comments

Comments
 (0)