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

Commit 370bca3

Browse files
David Robertsonclokeprichvdh
authoredOct 6, 2021
Don't drop user dir deltas when server leaves room (#10982)
Fix a long-standing bug where a batch of user directory changes would be silently dropped if the server left a room early in the batch. * Pull out `wait_for_background_update` in tests Co-authored-by: Patrick Cloke <[email protected]> Co-authored-by: Richard van der Hoff <[email protected]>
1 parent 38b7db5 commit 370bca3

11 files changed

+63
-79
lines changed
 

‎changelog.d/10982.bugfix

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a long-standing bug where the remainder of a batch of user directory changes would be silently dropped if the server left a room early in the batch.

‎synapse/handlers/user_directory.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ async def _handle_deltas(self, deltas: List[Dict[str, Any]]) -> None:
220220

221221
for user_id in user_ids:
222222
await self._handle_remove_user(room_id, user_id)
223-
return
223+
continue
224224
else:
225225
logger.debug("Server is still in room: %r", room_id)
226226

‎tests/handlers/test_stats.py

+3-18
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,7 @@ def _perform_background_initial_update(self):
103103
# Do the initial population of the stats via the background update
104104
self._add_background_updates()
105105

106-
while not self.get_success(
107-
self.store.db_pool.updates.has_completed_background_updates()
108-
):
109-
self.get_success(
110-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
111-
)
106+
self.wait_for_background_updates()
112107

113108
def test_initial_room(self):
114109
"""
@@ -140,12 +135,7 @@ def test_initial_room(self):
140135
# Do the initial population of the user directory via the background update
141136
self._add_background_updates()
142137

143-
while not self.get_success(
144-
self.store.db_pool.updates.has_completed_background_updates()
145-
):
146-
self.get_success(
147-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
148-
)
138+
self.wait_for_background_updates()
149139

150140
r = self.get_success(self.get_all_room_state())
151141

@@ -568,12 +558,7 @@ def test_incomplete_stats(self):
568558
)
569559
)
570560

571-
while not self.get_success(
572-
self.store.db_pool.updates.has_completed_background_updates()
573-
):
574-
self.get_success(
575-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
576-
)
561+
self.wait_for_background_updates()
577562

578563
r1stats_complete = self._get_current_stats("room", r1)
579564
u1stats_complete = self._get_current_stats("user", u1)

‎tests/handlers/test_user_directory.py

+39
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,45 @@ def test_reactivation_makes_regular_user_searchable(self) -> None:
363363
self.assertEqual(len(s["results"]), 1)
364364
self.assertEqual(s["results"][0]["user_id"], user)
365365

366+
def test_process_join_after_server_leaves_room(self) -> None:
367+
alice = self.register_user("alice", "pass")
368+
alice_token = self.login(alice, "pass")
369+
bob = self.register_user("bob", "pass")
370+
bob_token = self.login(bob, "pass")
371+
372+
# Alice makes two rooms. Bob joins one of them.
373+
room1 = self.helper.create_room_as(alice, tok=alice_token)
374+
room2 = self.helper.create_room_as(alice, tok=alice_token)
375+
print("room1=", room1)
376+
print("room2=", room2)
377+
self.helper.join(room1, bob, tok=bob_token)
378+
379+
# The user sharing tables should have been updated.
380+
public1 = self.get_success(self.user_dir_helper.get_users_in_public_rooms())
381+
self.assertEqual(set(public1), {(alice, room1), (alice, room2), (bob, room1)})
382+
383+
# Alice leaves room1. The user sharing tables should be updated.
384+
self.helper.leave(room1, alice, tok=alice_token)
385+
public2 = self.get_success(self.user_dir_helper.get_users_in_public_rooms())
386+
self.assertEqual(set(public2), {(alice, room2), (bob, room1)})
387+
388+
# Pause the processing of new events.
389+
dir_handler = self.hs.get_user_directory_handler()
390+
dir_handler.update_user_directory = False
391+
392+
# Bob leaves one room and joins the other.
393+
self.helper.leave(room1, bob, tok=bob_token)
394+
self.helper.join(room2, bob, tok=bob_token)
395+
396+
# Process the leave and join in one go.
397+
dir_handler.update_user_directory = True
398+
dir_handler.notify_new_event()
399+
self.wait_for_background_updates()
400+
401+
# The user sharing tables should have been updated.
402+
public3 = self.get_success(self.user_dir_helper.get_users_in_public_rooms())
403+
self.assertEqual(set(public3), {(alice, room2), (bob, room2)})
404+
366405
def test_private_room(self) -> None:
367406
"""
368407
A user can be searched for only by people that are either in a public

‎tests/storage/databases/main/test_room.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,7 @@ def test_background_populate_rooms_creator_column(self):
7979
self.store.db_pool.updates._all_done = False
8080

8181
# Now let's actually drive the updates to completion
82-
while not self.get_success(
83-
self.store.db_pool.updates.has_completed_background_updates()
84-
):
85-
self.get_success(
86-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
87-
)
82+
self.wait_for_background_updates()
8883

8984
# Make sure the background update filled in the room creator
9085
room_creator_after = self.get_success(

‎tests/storage/test_cleanup_extrems.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,7 @@ def run_delta_file(txn):
6666
# Ugh, have to reset this flag
6767
self.store.db_pool.updates._all_done = False
6868

69-
while not self.get_success(
70-
self.store.db_pool.updates.has_completed_background_updates()
71-
):
72-
self.get_success(
73-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
74-
)
69+
self.wait_for_background_updates()
7570

7671
def test_soft_failed_extremities_handled_correctly(self):
7772
"""Test that extremities are correctly calculated in the presence of

‎tests/storage/test_client_ips.py

+3-18
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,7 @@ def test_updating_monthly_active_user_when_space(self):
242242

243243
def test_devices_last_seen_bg_update(self):
244244
# First make sure we have completed all updates.
245-
while not self.get_success(
246-
self.store.db_pool.updates.has_completed_background_updates()
247-
):
248-
self.get_success(
249-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
250-
)
245+
self.wait_for_background_updates()
251246

252247
user_id = "@user:id"
253248
device_id = "MY_DEVICE"
@@ -311,12 +306,7 @@ def test_devices_last_seen_bg_update(self):
311306
self.store.db_pool.updates._all_done = False
312307

313308
# Now let's actually drive the updates to completion
314-
while not self.get_success(
315-
self.store.db_pool.updates.has_completed_background_updates()
316-
):
317-
self.get_success(
318-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
319-
)
309+
self.wait_for_background_updates()
320310

321311
# We should now get the correct result again
322312
result = self.get_success(
@@ -337,12 +327,7 @@ def test_devices_last_seen_bg_update(self):
337327

338328
def test_old_user_ips_pruned(self):
339329
# First make sure we have completed all updates.
340-
while not self.get_success(
341-
self.store.db_pool.updates.has_completed_background_updates()
342-
):
343-
self.get_success(
344-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
345-
)
330+
self.wait_for_background_updates()
346331

347332
user_id = "@user:id"
348333
device_id = "MY_DEVICE"

‎tests/storage/test_event_chain.py

+2-12
Original file line numberDiff line numberDiff line change
@@ -578,12 +578,7 @@ def test_background_update_single_room(self):
578578
# Ugh, have to reset this flag
579579
self.store.db_pool.updates._all_done = False
580580

581-
while not self.get_success(
582-
self.store.db_pool.updates.has_completed_background_updates()
583-
):
584-
self.get_success(
585-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
586-
)
581+
self.wait_for_background_updates()
587582

588583
# Test that the `has_auth_chain_index` has been set
589584
self.assertTrue(self.get_success(self.store.has_auth_chain_index(room_id)))
@@ -619,12 +614,7 @@ def test_background_update_multiple_rooms(self):
619614
# Ugh, have to reset this flag
620615
self.store.db_pool.updates._all_done = False
621616

622-
while not self.get_success(
623-
self.store.db_pool.updates.has_completed_background_updates()
624-
):
625-
self.get_success(
626-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
627-
)
617+
self.wait_for_background_updates()
628618

629619
# Test that the `has_auth_chain_index` has been set
630620
self.assertTrue(self.get_success(self.store.has_auth_chain_index(room_id1)))

‎tests/storage/test_roommember.py

+2-12
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,7 @@ def prepare(self, reactor, clock, homeserver):
169169

170170
def test_can_rerun_update(self):
171171
# First make sure we have completed all updates.
172-
while not self.get_success(
173-
self.store.db_pool.updates.has_completed_background_updates()
174-
):
175-
self.get_success(
176-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
177-
)
172+
self.wait_for_background_updates()
178173

179174
# Now let's create a room, which will insert a membership
180175
user = UserID("alice", "test")
@@ -197,9 +192,4 @@ def test_can_rerun_update(self):
197192
self.store.db_pool.updates._all_done = False
198193

199194
# Now let's actually drive the updates to completion
200-
while not self.get_success(
201-
self.store.db_pool.updates.has_completed_background_updates()
202-
):
203-
self.get_success(
204-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
205-
)
195+
self.wait_for_background_updates()

‎tests/storage/test_user_directory.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,7 @@ def _purge_and_rebuild_user_dir(self) -> None:
212212
)
213213
)
214214

215-
while not self.get_success(
216-
self.store.db_pool.updates.has_completed_background_updates()
217-
):
218-
self.get_success(
219-
self.store.db_pool.updates.do_next_background_update(100), by=0.1
220-
)
215+
self.wait_for_background_updates()
221216

222217
def test_initial(self) -> None:
223218
"""

‎tests/unittest.py

+9
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,15 @@ def wait_on_thread(self, deferred, timeout=10):
317317
self.reactor.advance(0.01)
318318
time.sleep(0.01)
319319

320+
def wait_for_background_updates(self) -> None:
321+
"""Block until all background database updates have completed."""
322+
while not self.get_success(
323+
self.store.db_pool.updates.has_completed_background_updates()
324+
):
325+
self.get_success(
326+
self.store.db_pool.updates.do_next_background_update(100), by=0.1
327+
)
328+
320329
def make_homeserver(self, reactor, clock):
321330
"""
322331
Make and return a homeserver.

0 commit comments

Comments
 (0)
This repository has been archived.