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

Commit daa1ac8

Browse files
authored
Fix device list update stream ids going backward (#7158)
Occasionally we could get a federation device list update transaction which looked like: ``` [ {'edu_type': 'm.device_list_update', 'content': {'user_id': '@user:test', 'device_id': 'D2', 'prev_id': [], 'stream_id': 12, 'deleted': True}}, {'edu_type': 'm.device_list_update', 'content': {'user_id': '@user:test', 'device_id': 'D1', 'prev_id': [12], 'stream_id': 11, 'deleted': True}}, {'edu_type': 'm.device_list_update', 'content': {'user_id': '@user:test', 'device_id': 'D3', 'prev_id': [11], 'stream_id': 13, 'deleted': True}} ] ``` Having `stream_ids` which are lower than `prev_ids` looks odd. It might work (I'm not actually sure), but in any case it doesn't seem like a reasonable thing to expect other implementations to support.
1 parent 61bb834 commit daa1ac8

File tree

3 files changed

+15
-2
lines changed

3 files changed

+15
-2
lines changed

changelog.d/7158.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix device list update stream ids going backward.

synapse/storage/data_stores/main/devices.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ def get_device_updates_by_remote(self, destination, from_stream_id, limit):
165165
# the max stream_id across each set of duplicate entries
166166
#
167167
# maps (user_id, device_id) -> (stream_id, opentracing_context)
168-
# as long as their stream_id does not match that of the last row
169168
#
170169
# opentracing_context contains the opentracing metadata for the request
171170
# that created the poke
@@ -270,7 +269,14 @@ def _get_device_update_edus_by_remote(self, destination, from_stream_id, query_m
270269
prev_id = yield self._get_last_device_update_for_remote_user(
271270
destination, user_id, from_stream_id
272271
)
273-
for device_id, device in iteritems(user_devices):
272+
273+
# make sure we go through the devices in stream order
274+
device_ids = sorted(
275+
user_devices.keys(), key=lambda i: query_map[(user_id, i)][0],
276+
)
277+
278+
for device_id in device_ids:
279+
device = user_devices[device_id]
274280
stream_id, opentracing_context = query_map[(user_id, device_id)]
275281
result = {
276282
"user_id": user_id,

tests/federation/test_federation_sender.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ def test_upload_signatures(self):
297297
c = edu["content"]
298298
if stream_id is not None:
299299
self.assertEqual(c["prev_id"], [stream_id])
300+
self.assertGreaterEqual(c["stream_id"], stream_id)
300301
stream_id = c["stream_id"]
301302
devices = {edu["content"]["device_id"] for edu in self.edus}
302303
self.assertEqual({"D1", "D2"}, devices)
@@ -330,6 +331,7 @@ def test_delete_devices(self):
330331
c.items(),
331332
{"user_id": u1, "prev_id": [stream_id], "deleted": True}.items(),
332333
)
334+
self.assertGreaterEqual(c["stream_id"], stream_id)
333335
stream_id = c["stream_id"]
334336
devices = {edu["content"]["device_id"] for edu in self.edus}
335337
self.assertEqual({"D1", "D2", "D3"}, devices)
@@ -366,6 +368,8 @@ def test_unreachable_server(self):
366368
self.assertEqual(edu["edu_type"], "m.device_list_update")
367369
c = edu["content"]
368370
self.assertEqual(c["prev_id"], [stream_id] if stream_id is not None else [])
371+
if stream_id is not None:
372+
self.assertGreaterEqual(c["stream_id"], stream_id)
369373
stream_id = c["stream_id"]
370374
devices = {edu["content"]["device_id"] for edu in self.edus}
371375
self.assertEqual({"D1", "D2", "D3"}, devices)
@@ -482,6 +486,8 @@ def check_device_update_edu(
482486
}
483487

484488
self.assertLessEqual(expected.items(), content.items())
489+
if prev_stream_id is not None:
490+
self.assertGreaterEqual(content["stream_id"], prev_stream_id)
485491
return content["stream_id"]
486492

487493
def check_signing_key_update_txn(self, txn: JsonDict,) -> None:

0 commit comments

Comments
 (0)