Skip to content

Commit 709b736

Browse files
Sliding sync: use new DB tables (#17630)
Based on #17629 Utilizing the new sliding sync tables added in #17512 for fast acquisition of rooms for the user and filtering/sorting. --------- Co-authored-by: Eric Eastwood <eric.eastwood@beta.gouv.fr>
1 parent 560b43a commit 709b736

21 files changed

+877
-18
lines changed

changelog.d/17630.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use new database tables for sliding sync.

synapse/handlers/sliding_sync/room_lists.py

Lines changed: 549 additions & 13 deletions
Large diffs are not rendered by default.

synapse/storage/_base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ def _invalidate_state_caches(
126126
self._attempt_to_invalidate_cache(
127127
"_get_rooms_for_local_user_where_membership_is_inner", (user_id,)
128128
)
129+
self._attempt_to_invalidate_cache(
130+
"get_sliding_sync_rooms_for_user", (user_id,)
131+
)
129132

130133
# Purge other caches based on room state.
131134
self._attempt_to_invalidate_cache("get_room_summary", (room_id,))
@@ -160,6 +163,7 @@ def _invalidate_state_caches_all(self, room_id: str) -> None:
160163
self._attempt_to_invalidate_cache("get_room_summary", (room_id,))
161164
self._attempt_to_invalidate_cache("get_room_type", (room_id,))
162165
self._attempt_to_invalidate_cache("get_room_encryption", (room_id,))
166+
self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
163167

164168
def _attempt_to_invalidate_cache(
165169
self, cache_name: str, key: Optional[Collection[Any]]

synapse/storage/background_updates.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
from synapse.metrics.background_process_metrics import run_as_background_process
4545
from synapse.storage.engines import PostgresEngine
4646
from synapse.storage.types import Connection, Cursor
47-
from synapse.types import JsonDict
47+
from synapse.types import JsonDict, StrCollection
4848
from synapse.util import Clock, json_encoder
4949

5050
from . import engines
@@ -487,6 +487,25 @@ async def has_completed_background_update(self, update_name: str) -> bool:
487487

488488
return not update_exists
489489

490+
async def have_completed_background_updates(
491+
self, update_names: StrCollection
492+
) -> bool:
493+
"""Return the name of background updates that have not yet been
494+
completed"""
495+
if self._all_done:
496+
return True
497+
498+
rows = await self.db_pool.simple_select_many_batch(
499+
table="background_updates",
500+
column="update_name",
501+
iterable=update_names,
502+
retcols=("update_name",),
503+
desc="get_uncompleted_background_updates",
504+
)
505+
506+
# If we find any rows then we've not completed the update.
507+
return not bool(rows)
508+
490509
async def do_next_background_update(self, sleep: bool = True) -> bool:
491510
"""Does some amount of work on the next queued background update
492511

synapse/storage/databases/main/cache.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ def _invalidate_caches_for_event(
346346
self._attempt_to_invalidate_cache(
347347
"_get_rooms_for_local_user_where_membership_is_inner", (state_key,)
348348
)
349+
self._attempt_to_invalidate_cache(
350+
"get_sliding_sync_rooms_for_user", (state_key,)
351+
)
349352

350353
self._attempt_to_invalidate_cache(
351354
"did_forget",
@@ -417,6 +420,7 @@ def _invalidate_caches_for_room_events(self, room_id: str) -> None:
417420
self._attempt_to_invalidate_cache(
418421
"_get_rooms_for_local_user_where_membership_is_inner", None
419422
)
423+
self._attempt_to_invalidate_cache("get_sliding_sync_rooms_for_user", None)
420424
self._attempt_to_invalidate_cache("did_forget", None)
421425
self._attempt_to_invalidate_cache("get_forgotten_rooms_for_user", None)
422426
self._attempt_to_invalidate_cache("get_references_for_event", None)

synapse/storage/databases/main/events_bg_updates.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,6 +2342,17 @@ def _fill_table_txn(txn: LoggingTransaction) -> None:
23422342

23432343
return len(memberships_to_update_rows)
23442344

2345+
async def have_finished_sliding_sync_background_jobs(self) -> bool:
2346+
"""Return if its safe to use the sliding sync membership tables."""
2347+
2348+
return await self.db_pool.updates.have_completed_background_updates(
2349+
(
2350+
_BackgroundUpdates.SLIDING_SYNC_PREFILL_JOINED_ROOMS_TO_RECALCULATE_TABLE_BG_UPDATE,
2351+
_BackgroundUpdates.SLIDING_SYNC_JOINED_ROOMS_BG_UPDATE,
2352+
_BackgroundUpdates.SLIDING_SYNC_MEMBERSHIP_SNAPSHOTS_BG_UPDATE,
2353+
)
2354+
)
2355+
23452356

23462357
def _resolve_stale_data_in_sliding_sync_tables(
23472358
txn: LoggingTransaction,

synapse/storage/databases/main/roommember.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@
5353
from synapse.storage.databases.main.cache import CacheInvalidationWorkerStore
5454
from synapse.storage.databases.main.events_worker import EventsWorkerStore
5555
from synapse.storage.engines import Sqlite3Engine
56-
from synapse.storage.roommember import MemberSummary, ProfileInfo, RoomsForUser
56+
from synapse.storage.roommember import (
57+
MemberSummary,
58+
ProfileInfo,
59+
RoomsForUser,
60+
RoomsForUserSlidingSync,
61+
)
5762
from synapse.types import (
5863
JsonDict,
5964
PersistedEventPosition,
@@ -1377,6 +1382,54 @@ async def update_room_forgetter_stream_pos(self, stream_id: int) -> None:
13771382
desc="room_forgetter_stream_pos",
13781383
)
13791384

1385+
@cached(iterable=True, max_entries=10000)
1386+
async def get_sliding_sync_rooms_for_user(
1387+
self,
1388+
user_id: str,
1389+
) -> Mapping[str, RoomsForUserSlidingSync]:
1390+
"""Get all the rooms for a user to handle a sliding sync request.
1391+
1392+
Ignores forgotten rooms and rooms that the user has been kicked from.
1393+
1394+
Returns:
1395+
Map from room ID to membership info
1396+
"""
1397+
1398+
def get_sliding_sync_rooms_for_user_txn(
1399+
txn: LoggingTransaction,
1400+
) -> Dict[str, RoomsForUserSlidingSync]:
1401+
sql = """
1402+
SELECT m.room_id, m.sender, m.membership, m.membership_event_id,
1403+
r.room_version,
1404+
m.event_instance_name, m.event_stream_ordering,
1405+
COALESCE(j.room_type, m.room_type),
1406+
COALESCE(j.is_encrypted, m.is_encrypted)
1407+
FROM sliding_sync_membership_snapshots AS m
1408+
INNER JOIN rooms AS r USING (room_id)
1409+
LEFT JOIN sliding_sync_joined_rooms AS j ON (j.room_id = m.room_id AND m.membership = 'join')
1410+
WHERE user_id = ?
1411+
AND m.forgotten = 0
1412+
"""
1413+
txn.execute(sql, (user_id,))
1414+
return {
1415+
row[0]: RoomsForUserSlidingSync(
1416+
room_id=row[0],
1417+
sender=row[1],
1418+
membership=row[2],
1419+
event_id=row[3],
1420+
room_version_id=row[4],
1421+
event_pos=PersistedEventPosition(row[5], row[6]),
1422+
room_type=row[7],
1423+
is_encrypted=row[8],
1424+
)
1425+
for row in txn
1426+
}
1427+
1428+
return await self.db_pool.runInteraction(
1429+
"get_sliding_sync_rooms_for_user",
1430+
get_sliding_sync_rooms_for_user_txn,
1431+
)
1432+
13801433

13811434
class RoomMemberBackgroundUpdateStore(SQLBaseStore):
13821435
def __init__(

synapse/storage/roommember.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ class RoomsForUser:
3939
room_version_id: str
4040

4141

42+
@attr.s(slots=True, frozen=True, weakref_slot=False, auto_attribs=True)
43+
class RoomsForUserSlidingSync:
44+
room_id: str
45+
sender: Optional[str]
46+
membership: str
47+
event_id: Optional[str]
48+
event_pos: PersistedEventPosition
49+
room_version_id: str
50+
51+
room_type: Optional[str]
52+
is_encrypted: bool
53+
54+
4255
@attr.s(slots=True, frozen=True, weakref_slot=False, auto_attribs=True)
4356
class GetRoomsForUserWithStreamOrdering:
4457
room_id: str

tests/rest/client/sliding_sync/test_connection_tracking.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#
1414
import logging
1515

16-
from parameterized import parameterized
16+
from parameterized import parameterized, parameterized_class
1717

1818
from twisted.test.proto_helpers import MemoryReactor
1919

@@ -28,6 +28,18 @@
2828
logger = logging.getLogger(__name__)
2929

3030

31+
# FIXME: This can be removed once we bump `SCHEMA_COMPAT_VERSION` and run the
32+
# foreground update for
33+
# `sliding_sync_joined_rooms`/`sliding_sync_membership_snapshots` (tracked by
34+
# https://github.com/element-hq/synapse/issues/17623)
35+
@parameterized_class(
36+
("use_new_tables",),
37+
[
38+
(True,),
39+
(False,),
40+
],
41+
class_name_func=lambda cls, num, params_dict: f"{cls.__name__}_{'new' if params_dict['use_new_tables'] else 'fallback'}",
42+
)
3143
class SlidingSyncConnectionTrackingTestCase(SlidingSyncBase):
3244
"""
3345
Test connection tracking in the Sliding Sync API.
@@ -44,6 +56,8 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
4456
self.store = hs.get_datastores().main
4557
self.storage_controllers = hs.get_storage_controllers()
4658

59+
super().prepare(reactor, clock, hs)
60+
4761
def test_rooms_required_state_incremental_sync_LIVE(self) -> None:
4862
"""Test that we only get state updates in incremental sync for rooms
4963
we've already seen (LIVE).

tests/rest/client/sliding_sync/test_extension_account_data.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#
1414
import logging
1515

16+
from parameterized import parameterized_class
17+
1618
from twisted.test.proto_helpers import MemoryReactor
1719

1820
import synapse.rest.admin
@@ -28,6 +30,18 @@
2830
logger = logging.getLogger(__name__)
2931

3032

33+
# FIXME: This can be removed once we bump `SCHEMA_COMPAT_VERSION` and run the
34+
# foreground update for
35+
# `sliding_sync_joined_rooms`/`sliding_sync_membership_snapshots` (tracked by
36+
# https://github.com/element-hq/synapse/issues/17623)
37+
@parameterized_class(
38+
("use_new_tables",),
39+
[
40+
(True,),
41+
(False,),
42+
],
43+
class_name_func=lambda cls, num, params_dict: f"{cls.__name__}_{'new' if params_dict['use_new_tables'] else 'fallback'}",
44+
)
3145
class SlidingSyncAccountDataExtensionTestCase(SlidingSyncBase):
3246
"""Tests for the account_data sliding sync extension"""
3347

@@ -43,6 +57,8 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
4357
self.store = hs.get_datastores().main
4458
self.account_data_handler = hs.get_account_data_handler()
4559

60+
super().prepare(reactor, clock, hs)
61+
4662
def test_no_data_initial_sync(self) -> None:
4763
"""
4864
Test that enabling the account_data extension works during an intitial sync,

0 commit comments

Comments
 (0)