Skip to content

Commit ae877aa

Browse files
Convert Sliding Sync tests to use higher-level compute_interested_rooms (#18399)
Spawning from #18375 (comment), This updates some sliding sync tests to use a higher level function in order to move test coverage to cover both fallback & new tables. Important when #18375 is merged. In other words, adjust tests to target `compute_interested_room(...)` (relevant to both new and fallback path) instead of the lower level `get_room_membership_for_user_at_to_token(...)` that only applies to the fallback path. ### Dev notes ``` SYNAPSE_TEST_LOG_LEVEL=INFO poetry run trial tests.handlers.test_sliding_sync.ComputeInterestedRoomsTestCase_new ``` ``` SYNAPSE_TEST_LOG_LEVEL=INFO poetry run trial tests.rest.client.sliding_sync ``` ``` SYNAPSE_POSTGRES=1 SYNAPSE_POSTGRES_USER=postgres SYNAPSE_TEST_LOG_LEVEL=INFO poetry run trial tests.handlers.test_sliding_sync.ComputeInterestedRoomsTestCase_new.test_display_name_changes_leave_after_token_range ``` ### Pull Request Checklist <!-- Please read https://element-hq.github.io/synapse/latest/development/contributing_guide.html before submitting your pull request --> * [x] Pull request is based on the develop branch * [x] Pull request includes a [changelog file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog). The entry should: - Be a short description of your change which makes sense to users. "Fixed a bug that prevented receiving messages from other servers." instead of "Moved X method from `EventStore` to `EventWorkerStore`.". - Use markdown where necessary, mostly for `code blocks`. - End with either a period (.) or an exclamation mark (!). - Start with a capital letter. - Feel free to credit yourself, by adding a sentence "Contributed by @github_username." or "Contributed by [Your Name]." to the end of the entry. * [x] [Code style](https://element-hq.github.io/synapse/latest/code_style.html) is correct (run the [linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters)) --------- Co-authored-by: Eric Eastwood <[email protected]>
1 parent 740fc88 commit ae877aa

File tree

7 files changed

+1238
-437
lines changed

7 files changed

+1238
-437
lines changed

changelog.d/18399.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Refactor [MSC4186](https://github.com/matrix-org/matrix-spec-proposals/pull/4186) Simplified Sliding Sync room list tests to cover both new and fallback logic paths.

synapse/handlers/sliding_sync/room_lists.py

Lines changed: 101 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,47 @@ async def _compute_interested_rooms_new_tables(
244244
# Note: this won't include rooms the user has left themselves. We add back
245245
# `newly_left` rooms below. This is more efficient than fetching all rooms and
246246
# then filtering out the old left rooms.
247-
room_membership_for_user_map = await self.store.get_sliding_sync_rooms_for_user(
248-
user_id
247+
room_membership_for_user_map = (
248+
await self.store.get_sliding_sync_rooms_for_user_from_membership_snapshots(
249+
user_id
250+
)
251+
)
252+
# To play nice with the rewind logic below, we need to go fetch the rooms the
253+
# user has left themselves but only if it changed after the `to_token`.
254+
#
255+
# If a leave happens *after* the token range, we may have still been joined (or
256+
# any non-self-leave which is relevant to sync) to the room before so we need to
257+
# include it in the list of potentially relevant rooms and apply our rewind
258+
# logic (outside of this function) to see if it's actually relevant.
259+
#
260+
# We do this separately from
261+
# `get_sliding_sync_rooms_for_user_from_membership_snapshots` as those results
262+
# are cached and the `to_token` isn't very cache friendly (people are constantly
263+
# requesting with new tokens) so we separate it out here.
264+
self_leave_room_membership_for_user_map = (
265+
await self.store.get_sliding_sync_self_leave_rooms_after_to_token(
266+
user_id, to_token
267+
)
249268
)
269+
if self_leave_room_membership_for_user_map:
270+
# FIXME: It would be nice to avoid this copy but since
271+
# `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
272+
# can't return a mutable value like a `dict`. We make the copy to get a
273+
# mutable dict that we can change. We try to only make a copy when necessary
274+
# (if we actually need to change something) as in most cases, the logic
275+
# doesn't need to run.
276+
room_membership_for_user_map = dict(room_membership_for_user_map)
277+
room_membership_for_user_map.update(self_leave_room_membership_for_user_map)
250278

251279
# Remove invites from ignored users
252280
ignored_users = await self.store.ignored_users(user_id)
253281
if ignored_users:
254-
# TODO: It would be nice to avoid these copies
282+
# FIXME: It would be nice to avoid this copy but since
283+
# `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
284+
# can't return a mutable value like a `dict`. We make the copy to get a
285+
# mutable dict that we can change. We try to only make a copy when necessary
286+
# (if we actually need to change something) as in most cases, the logic
287+
# doesn't need to run.
255288
room_membership_for_user_map = dict(room_membership_for_user_map)
256289
# Make a copy so we don't run into an error: `dictionary changed size during
257290
# iteration`, when we remove items
@@ -263,11 +296,23 @@ async def _compute_interested_rooms_new_tables(
263296
):
264297
room_membership_for_user_map.pop(room_id, None)
265298

299+
(
300+
newly_joined_room_ids,
301+
newly_left_room_map,
302+
) = await self._get_newly_joined_and_left_rooms(
303+
user_id, from_token=from_token, to_token=to_token
304+
)
305+
266306
changes = await self._get_rewind_changes_to_current_membership_to_token(
267307
sync_config.user, room_membership_for_user_map, to_token=to_token
268308
)
269309
if changes:
270-
# TODO: It would be nice to avoid these copies
310+
# FIXME: It would be nice to avoid this copy but since
311+
# `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
312+
# can't return a mutable value like a `dict`. We make the copy to get a
313+
# mutable dict that we can change. We try to only make a copy when necessary
314+
# (if we actually need to change something) as in most cases, the logic
315+
# doesn't need to run.
271316
room_membership_for_user_map = dict(room_membership_for_user_map)
272317
for room_id, change in changes.items():
273318
if change is None:
@@ -278,7 +323,7 @@ async def _compute_interested_rooms_new_tables(
278323
existing_room = room_membership_for_user_map.get(room_id)
279324
if existing_room is not None:
280325
# Update room membership events to the point in time of the `to_token`
281-
room_membership_for_user_map[room_id] = RoomsForUserSlidingSync(
326+
room_for_user = RoomsForUserSlidingSync(
282327
room_id=room_id,
283328
sender=change.sender,
284329
membership=change.membership,
@@ -290,18 +335,18 @@ async def _compute_interested_rooms_new_tables(
290335
room_type=existing_room.room_type,
291336
is_encrypted=existing_room.is_encrypted,
292337
)
293-
294-
(
295-
newly_joined_room_ids,
296-
newly_left_room_map,
297-
) = await self._get_newly_joined_and_left_rooms(
298-
user_id, from_token=from_token, to_token=to_token
299-
)
300-
dm_room_ids = await self._get_dm_rooms_for_user(user_id)
338+
if filter_membership_for_sync(
339+
user_id=user_id,
340+
room_membership_for_user=room_for_user,
341+
newly_left=room_id in newly_left_room_map,
342+
):
343+
room_membership_for_user_map[room_id] = room_for_user
344+
else:
345+
room_membership_for_user_map.pop(room_id, None)
301346

302347
# Add back `newly_left` rooms (rooms left in the from -> to token range).
303348
#
304-
# We do this because `get_sliding_sync_rooms_for_user(...)` doesn't include
349+
# We do this because `get_sliding_sync_rooms_for_user_from_membership_snapshots(...)` doesn't include
305350
# rooms that the user left themselves as it's more efficient to add them back
306351
# here than to fetch all rooms and then filter out the old left rooms. The user
307352
# only leaves a room once in a blue moon so this barely needs to run.
@@ -310,7 +355,12 @@ async def _compute_interested_rooms_new_tables(
310355
newly_left_room_map.keys() - room_membership_for_user_map.keys()
311356
)
312357
if missing_newly_left_rooms:
313-
# TODO: It would be nice to avoid these copies
358+
# FIXME: It would be nice to avoid this copy but since
359+
# `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
360+
# can't return a mutable value like a `dict`. We make the copy to get a
361+
# mutable dict that we can change. We try to only make a copy when necessary
362+
# (if we actually need to change something) as in most cases, the logic
363+
# doesn't need to run.
314364
room_membership_for_user_map = dict(room_membership_for_user_map)
315365
for room_id in missing_newly_left_rooms:
316366
newly_left_room_for_user = newly_left_room_map[room_id]
@@ -327,14 +377,21 @@ async def _compute_interested_rooms_new_tables(
327377
# If the membership exists, it's just a normal user left the room on
328378
# their own
329379
if newly_left_room_for_user_sliding_sync is not None:
330-
room_membership_for_user_map[room_id] = (
331-
newly_left_room_for_user_sliding_sync
332-
)
380+
if filter_membership_for_sync(
381+
user_id=user_id,
382+
room_membership_for_user=newly_left_room_for_user_sliding_sync,
383+
newly_left=room_id in newly_left_room_map,
384+
):
385+
room_membership_for_user_map[room_id] = (
386+
newly_left_room_for_user_sliding_sync
387+
)
388+
else:
389+
room_membership_for_user_map.pop(room_id, None)
333390

334391
change = changes.get(room_id)
335392
if change is not None:
336393
# Update room membership events to the point in time of the `to_token`
337-
room_membership_for_user_map[room_id] = RoomsForUserSlidingSync(
394+
room_for_user = RoomsForUserSlidingSync(
338395
room_id=room_id,
339396
sender=change.sender,
340397
membership=change.membership,
@@ -346,6 +403,14 @@ async def _compute_interested_rooms_new_tables(
346403
room_type=newly_left_room_for_user_sliding_sync.room_type,
347404
is_encrypted=newly_left_room_for_user_sliding_sync.is_encrypted,
348405
)
406+
if filter_membership_for_sync(
407+
user_id=user_id,
408+
room_membership_for_user=room_for_user,
409+
newly_left=room_id in newly_left_room_map,
410+
):
411+
room_membership_for_user_map[room_id] = room_for_user
412+
else:
413+
room_membership_for_user_map.pop(room_id, None)
349414

350415
# If we are `newly_left` from the room but can't find any membership,
351416
# then we have been "state reset" out of the room
@@ -367,7 +432,7 @@ async def _compute_interested_rooms_new_tables(
367432
newly_left_room_for_user.event_pos.to_room_stream_token(),
368433
)
369434

370-
room_membership_for_user_map[room_id] = RoomsForUserSlidingSync(
435+
room_for_user = RoomsForUserSlidingSync(
371436
room_id=room_id,
372437
sender=newly_left_room_for_user.sender,
373438
membership=newly_left_room_for_user.membership,
@@ -378,6 +443,16 @@ async def _compute_interested_rooms_new_tables(
378443
room_type=room_type,
379444
is_encrypted=is_encrypted,
380445
)
446+
if filter_membership_for_sync(
447+
user_id=user_id,
448+
room_membership_for_user=room_for_user,
449+
newly_left=room_id in newly_left_room_map,
450+
):
451+
room_membership_for_user_map[room_id] = room_for_user
452+
else:
453+
room_membership_for_user_map.pop(room_id, None)
454+
455+
dm_room_ids = await self._get_dm_rooms_for_user(user_id)
381456

382457
if sync_config.lists:
383458
sync_room_map = room_membership_for_user_map
@@ -493,7 +568,12 @@ async def _compute_interested_rooms_new_tables(
493568

494569
if sync_config.room_subscriptions:
495570
with start_active_span("assemble_room_subscriptions"):
496-
# TODO: It would be nice to avoid these copies
571+
# FIXME: It would be nice to avoid this copy but since
572+
# `get_sliding_sync_rooms_for_user_from_membership_snapshots` is cached, it
573+
# can't return a mutable value like a `dict`. We make the copy to get a
574+
# mutable dict that we can change. We try to only make a copy when necessary
575+
# (if we actually need to change something) as in most cases, the logic
576+
# doesn't need to run.
497577
room_membership_for_user_map = dict(room_membership_for_user_map)
498578

499579
# Find which rooms are partially stated and may need to be filtered out

synapse/storage/_base.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,17 @@ def _invalidate_state_caches(
130130
"_get_rooms_for_local_user_where_membership_is_inner", (user_id,)
131131
)
132132
self._attempt_to_invalidate_cache(
133-
"get_sliding_sync_rooms_for_user", (user_id,)
133+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", (user_id,)
134134
)
135135

136136
# Purge other caches based on room state.
137137
self._attempt_to_invalidate_cache("get_room_summary", (room_id,))
138138
self._attempt_to_invalidate_cache("get_partial_current_state_ids", (room_id,))
139139
self._attempt_to_invalidate_cache("get_room_type", (room_id,))
140140
self._attempt_to_invalidate_cache("get_room_encryption", (room_id,))
141-
self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
141+
self._attempt_to_invalidate_cache(
142+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", None
143+
)
142144

143145
def _invalidate_state_caches_all(self, room_id: str) -> None:
144146
"""Invalidates caches that are based on the current state, but does
@@ -168,7 +170,9 @@ def _invalidate_state_caches_all(self, room_id: str) -> None:
168170
self._attempt_to_invalidate_cache("get_room_summary", (room_id,))
169171
self._attempt_to_invalidate_cache("get_room_type", (room_id,))
170172
self._attempt_to_invalidate_cache("get_room_encryption", (room_id,))
171-
self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
173+
self._attempt_to_invalidate_cache(
174+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", None
175+
)
172176

173177
def _attempt_to_invalidate_cache(
174178
self, cache_name: str, key: Optional[Collection[Any]]

synapse/storage/databases/main/cache.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def _process_event_stream_row(self, token: int, row: EventsStreamRow) -> None:
307307
"get_rooms_for_user", (data.state_key,)
308308
)
309309
self._attempt_to_invalidate_cache(
310-
"get_sliding_sync_rooms_for_user", None
310+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", None
311311
)
312312
self._membership_stream_cache.entity_has_changed(data.state_key, token) # type: ignore[attr-defined]
313313
elif data.type == EventTypes.RoomEncryption:
@@ -319,7 +319,7 @@ def _process_event_stream_row(self, token: int, row: EventsStreamRow) -> None:
319319

320320
if (data.type, data.state_key) in SLIDING_SYNC_RELEVANT_STATE_SET:
321321
self._attempt_to_invalidate_cache(
322-
"get_sliding_sync_rooms_for_user", None
322+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", None
323323
)
324324
elif row.type == EventsStreamAllStateRow.TypeId:
325325
assert isinstance(data, EventsStreamAllStateRow)
@@ -330,7 +330,9 @@ def _process_event_stream_row(self, token: int, row: EventsStreamRow) -> None:
330330
self._attempt_to_invalidate_cache("get_rooms_for_user", None)
331331
self._attempt_to_invalidate_cache("get_room_type", (data.room_id,))
332332
self._attempt_to_invalidate_cache("get_room_encryption", (data.room_id,))
333-
self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
333+
self._attempt_to_invalidate_cache(
334+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", None
335+
)
334336
else:
335337
raise Exception("Unknown events stream row type %s" % (row.type,))
336338

@@ -394,7 +396,8 @@ def _invalidate_caches_for_event(
394396
"_get_rooms_for_local_user_where_membership_is_inner", (state_key,)
395397
)
396398
self._attempt_to_invalidate_cache(
397-
"get_sliding_sync_rooms_for_user", (state_key,)
399+
"get_sliding_sync_rooms_for_user_from_membership_snapshots",
400+
(state_key,),
398401
)
399402

400403
self._attempt_to_invalidate_cache(
@@ -413,7 +416,9 @@ def _invalidate_caches_for_event(
413416
self._attempt_to_invalidate_cache("get_room_encryption", (room_id,))
414417

415418
if (etype, state_key) in SLIDING_SYNC_RELEVANT_STATE_SET:
416-
self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
419+
self._attempt_to_invalidate_cache(
420+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", None
421+
)
417422

418423
if relates_to:
419424
self._attempt_to_invalidate_cache(
@@ -470,7 +475,9 @@ def _invalidate_caches_for_room_events(self, room_id: str) -> None:
470475
self._attempt_to_invalidate_cache(
471476
"_get_rooms_for_local_user_where_membership_is_inner", None
472477
)
473-
self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
478+
self._attempt_to_invalidate_cache(
479+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", None
480+
)
474481
self._attempt_to_invalidate_cache("did_forget", None)
475482
self._attempt_to_invalidate_cache("get_forgotten_rooms_for_user", None)
476483
self._attempt_to_invalidate_cache("get_references_for_event", None)
@@ -529,7 +536,9 @@ def _invalidate_caches_for_room(self, room_id: str) -> None:
529536
self._attempt_to_invalidate_cache(
530537
"get_current_hosts_in_room_ordered", (room_id,)
531538
)
532-
self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
539+
self._attempt_to_invalidate_cache(
540+
"get_sliding_sync_rooms_for_user_from_membership_snapshots", None
541+
)
533542
self._attempt_to_invalidate_cache("did_forget", None)
534543
self._attempt_to_invalidate_cache("get_forgotten_rooms_for_user", None)
535544
self._attempt_to_invalidate_cache("_get_membership_from_event_id", None)

0 commit comments

Comments
 (0)