Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix sliding sync for rooms with unknown room version #17733

Merged
merged 3 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/17733.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a bug in SSS which could prevent /sync from working for certain user accounts.
10 changes: 10 additions & 0 deletions synapse/handlers/sliding_sync/room_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
EventTypes,
Membership,
)
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.events import StrippedStateEvent
from synapse.events.utils import parse_stripped_state_event
from synapse.logging.opentracing import start_active_span, trace
Expand Down Expand Up @@ -942,6 +943,15 @@ async def get_room_membership_for_user_at_to_token(
excluded_rooms=self.rooms_to_exclude_globally,
)

# We filter out unknown room versions before we try and load any
# metadata about the room. They shouldn't go down sync anyway, and their
# metadata may be in a broken state.
room_for_user_list = [
room_for_user
for room_for_user in room_for_user_list
if room_for_user.room_version_id in KNOWN_ROOM_VERSIONS
]

# Remove invites from ignored users
ignored_users = await self.store.ignored_users(user_id)
if ignored_users:
Expand Down
5 changes: 5 additions & 0 deletions synapse/storage/databases/main/roommember.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

from synapse.api.constants import EventTypes, Membership
from synapse.api.errors import Codes, SynapseError
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.logging.opentracing import trace
from synapse.metrics import LaterGauge
from synapse.metrics.background_process_metrics import wrap_as_background_process
Expand Down Expand Up @@ -1443,6 +1444,10 @@ def get_sliding_sync_rooms_for_user_txn(
is_encrypted=bool(row[9]),
)
for row in txn
# We filter out unknown room versions proactively. They
# shouldn't go down sync and their metadata may be in a broken
# state (causing errors).
if row[4] in KNOWN_ROOM_VERSIONS
}

return await self.db_pool.runInteraction(
Expand Down
52 changes: 52 additions & 0 deletions tests/rest/client/sliding_sync/test_rooms_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -1197,3 +1197,55 @@ def test_rooms_meta_is_dm(self) -> None:
joined_dm_room_id: True,
},
)

def test_old_room_with_unknown_room_version(self) -> None:
"""Test that an old room with unknown room version does not break
sync."""
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass")

# We first create a standard room, then we'll change the room version in
# the DB.
room_id = self.helper.create_room_as(
user1_id,
tok=user1_tok,
)

# Poke the database and update the room version to an unknown one.
self.get_success(
self.hs.get_datastores().main.db_pool.simple_update(
"rooms",
keyvalues={"room_id": room_id},
updatevalues={"room_version": "unknown-room-version"},
desc="updated-room-version",
)
)

# Invalidate method so that it returns the currently updated version
# instead of the cached version.
self.hs.get_datastores().main.get_room_version_id.invalidate((room_id,))

# For old unknown room versions we won't have an entry in this table
# (due to us skipping unknown room versions in the background update).
self.get_success(
self.store.db_pool.simple_delete(
table="sliding_sync_joined_rooms",
keyvalues={"room_id": room_id},
desc="delete_sliding_room",
)
)

# Also invalidate some caches to ensure we pull things from the DB.
self.store._events_stream_cache._entity_to_key.pop(room_id)
self.store._get_max_event_pos.invalidate((room_id,))

sync_body = {
"lists": {
"foo-list": {
"ranges": [[0, 1]],
"required_state": [],
"timeline_limit": 5,
}
}
}
response_body, _ = self.do_sync(sync_body, tok=user1_tok)
Loading