Skip to content

Commit 422f3ec

Browse files
authored
Sliding sync: omit bump stamp when it is unchanged (#17788)
This saves some DB lookups in rooms
1 parent 4e90221 commit 422f3ec

File tree

5 files changed

+136
-12
lines changed

5 files changed

+136
-12
lines changed

changelog.d/17788.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Sliding sync minor performance improvement by omitting unchanged data from incremental responses.

synapse/handlers/sliding_sync/__init__.py

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,22 +1057,42 @@ async def get_room_sync_data(
10571057
)
10581058
)
10591059

1060-
# Figure out the last bump event in the room
1061-
#
1062-
# By default, just choose the membership event position for any non-join membership
1063-
bump_stamp = room_membership_for_user_at_to_token.event_pos.stream
1060+
# Figure out the last bump event in the room. If the bump stamp hasn't
1061+
# changed we omit it from the response.
1062+
bump_stamp = None
1063+
1064+
always_return_bump_stamp = (
1065+
# We use the membership event position for any non-join
1066+
room_membership_for_user_at_to_token.membership != Membership.JOIN
1067+
# We didn't fetch any timeline events but we should still check for
1068+
# a bump_stamp that might be somewhere
1069+
or limited is None
1070+
# There might be a bump event somewhere before the timeline events
1071+
# that we fetched, that we didn't previously send down
1072+
or limited is True
1073+
# Always give the client some frame of reference if this is the
1074+
# first time they are seeing the room down the connection
1075+
or initial
1076+
)
1077+
10641078
# If we're joined to the room, we need to find the last bump event before the
10651079
# `to_token`
10661080
if room_membership_for_user_at_to_token.membership == Membership.JOIN:
1067-
# Try and get a bump stamp, if not we just fall back to the
1068-
# membership token.
1081+
# Try and get a bump stamp
10691082
new_bump_stamp = await self._get_bump_stamp(
1070-
room_id, to_token, timeline_events
1083+
room_id,
1084+
to_token,
1085+
timeline_events,
1086+
check_outside_timeline=always_return_bump_stamp,
10711087
)
10721088
if new_bump_stamp is not None:
10731089
bump_stamp = new_bump_stamp
10741090

1075-
if bump_stamp < 0:
1091+
if bump_stamp is None and always_return_bump_stamp:
1092+
# By default, just choose the membership event position for any non-join membership
1093+
bump_stamp = room_membership_for_user_at_to_token.event_pos.stream
1094+
1095+
if bump_stamp is not None and bump_stamp < 0:
10761096
# We never want to send down negative stream orderings, as you can't
10771097
# sensibly compare positive and negative stream orderings (they have
10781098
# different meanings).
@@ -1165,14 +1185,23 @@ async def get_room_sync_data(
11651185

11661186
@trace
11671187
async def _get_bump_stamp(
1168-
self, room_id: str, to_token: StreamToken, timeline: List[EventBase]
1188+
self,
1189+
room_id: str,
1190+
to_token: StreamToken,
1191+
timeline: List[EventBase],
1192+
check_outside_timeline: bool,
11691193
) -> Optional[int]:
1170-
"""Get a bump stamp for the room, if we have a bump event
1194+
"""Get a bump stamp for the room, if we have a bump event and it has
1195+
changed.
11711196
11721197
Args:
11731198
room_id
11741199
to_token: The upper bound of token to return
11751200
timeline: The list of events we have fetched.
1201+
limited: If the timeline was limited.
1202+
check_outside_timeline: Whether we need to check for bump stamp for
1203+
events before the timeline if we didn't find a bump stamp in
1204+
the timeline events.
11761205
"""
11771206

11781207
# First check the timeline events we're returning to see if one of
@@ -1192,6 +1221,11 @@ async def _get_bump_stamp(
11921221
if new_bump_stamp > 0:
11931222
return new_bump_stamp
11941223

1224+
if not check_outside_timeline:
1225+
# If we are not a limited sync, then we know the bump stamp can't
1226+
# have changed.
1227+
return None
1228+
11951229
# We can quickly query for the latest bump event in the room using the
11961230
# sliding sync tables.
11971231
latest_room_bump_stamp = await self.store.get_latest_bump_stamp_for_room(

synapse/rest/client/sync.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,11 +1010,13 @@ async def encode_rooms(
10101010
serialized_rooms: Dict[str, JsonDict] = {}
10111011
for room_id, room_result in rooms.items():
10121012
serialized_rooms[room_id] = {
1013-
"bump_stamp": room_result.bump_stamp,
10141013
"notification_count": room_result.notification_count,
10151014
"highlight_count": room_result.highlight_count,
10161015
}
10171016

1017+
if room_result.bump_stamp is not None:
1018+
serialized_rooms[room_id]["bump_stamp"] = room_result.bump_stamp
1019+
10181020
if room_result.joined_count is not None:
10191021
serialized_rooms[room_id]["joined_count"] = room_result.joined_count
10201022

synapse/types/handlers/sliding_sync.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class RoomResult:
158158
name changes to mark the room as unread and bump it to the top. For
159159
encrypted rooms, we just have to consider any activity as a bump because we
160160
can't see the content and the client has to figure it out for themselves.
161+
This may not be included if there hasn't been a change.
161162
joined_count: The number of users with membership of join, including the client's
162163
own user ID. (same as sync `v2 m.joined_member_count`)
163164
invited_count: The number of users with membership of invite. (same as sync v2
@@ -193,7 +194,7 @@ class StrippedHero:
193194
limited: Optional[bool]
194195
# Only optional because it won't be included for invite/knock rooms with `stripped_state`
195196
num_live: Optional[int]
196-
bump_stamp: int
197+
bump_stamp: Optional[int]
197198
joined_count: Optional[int]
198199
invited_count: Optional[int]
199200
notification_count: int

tests/rest/client/sliding_sync/test_rooms_meta.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,92 @@ def test_rooms_bump_stamp_backfill(self) -> None:
10961096

10971097
self.assertGreater(response_body["rooms"][room_id]["bump_stamp"], 0)
10981098

1099+
def test_rooms_bump_stamp_no_change_incremental(self) -> None:
1100+
"""Test that the bump stamp is omitted if there has been no change"""
1101+
1102+
user1_id = self.register_user("user1", "pass")
1103+
user1_tok = self.login(user1_id, "pass")
1104+
1105+
room_id1 = self.helper.create_room_as(
1106+
user1_id,
1107+
tok=user1_tok,
1108+
)
1109+
1110+
# Make the Sliding Sync request
1111+
sync_body = {
1112+
"lists": {
1113+
"foo-list": {
1114+
"ranges": [[0, 1]],
1115+
"required_state": [],
1116+
"timeline_limit": 100,
1117+
}
1118+
}
1119+
}
1120+
response_body, from_token = self.do_sync(sync_body, tok=user1_tok)
1121+
1122+
# Initial sync so we expect to see a bump stamp
1123+
self.assertIn("bump_stamp", response_body["rooms"][room_id1])
1124+
1125+
# Send an event that is not in the bump events list
1126+
self.helper.send_event(
1127+
room_id1, type="org.matrix.test", content={}, tok=user1_tok
1128+
)
1129+
1130+
response_body, from_token = self.do_sync(
1131+
sync_body, since=from_token, tok=user1_tok
1132+
)
1133+
1134+
# There hasn't been a change to the bump stamps, so we ignore it
1135+
self.assertNotIn("bump_stamp", response_body["rooms"][room_id1])
1136+
1137+
def test_rooms_bump_stamp_change_incremental(self) -> None:
1138+
"""Test that the bump stamp is included if there has been a change, even
1139+
if its not in the timeline"""
1140+
1141+
user1_id = self.register_user("user1", "pass")
1142+
user1_tok = self.login(user1_id, "pass")
1143+
1144+
room_id1 = self.helper.create_room_as(
1145+
user1_id,
1146+
tok=user1_tok,
1147+
)
1148+
1149+
# Make the Sliding Sync request
1150+
sync_body = {
1151+
"lists": {
1152+
"foo-list": {
1153+
"ranges": [[0, 1]],
1154+
"required_state": [],
1155+
"timeline_limit": 2,
1156+
}
1157+
}
1158+
}
1159+
response_body, from_token = self.do_sync(sync_body, tok=user1_tok)
1160+
1161+
# Initial sync so we expect to see a bump stamp
1162+
self.assertIn("bump_stamp", response_body["rooms"][room_id1])
1163+
first_bump_stamp = response_body["rooms"][room_id1]["bump_stamp"]
1164+
1165+
# Send a bump event at the start.
1166+
self.helper.send(room_id1, "test", tok=user1_tok)
1167+
1168+
# Send events that are not in the bump events list to fill the timeline
1169+
for _ in range(5):
1170+
self.helper.send_event(
1171+
room_id1, type="org.matrix.test", content={}, tok=user1_tok
1172+
)
1173+
1174+
response_body, from_token = self.do_sync(
1175+
sync_body, since=from_token, tok=user1_tok
1176+
)
1177+
1178+
# There was a bump event in the timeline gap, so we should see the bump
1179+
# stamp be updated.
1180+
self.assertIn("bump_stamp", response_body["rooms"][room_id1])
1181+
second_bump_stamp = response_body["rooms"][room_id1]["bump_stamp"]
1182+
1183+
self.assertGreater(second_bump_stamp, first_bump_stamp)
1184+
10991185
def test_rooms_bump_stamp_invites(self) -> None:
11001186
"""
11011187
Test that `bump_stamp` is present and points to the membership event,

0 commit comments

Comments
 (0)