mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2024-09-03 02:41:55 +00:00
Fix incorrect get_rooms_for_user
for remote user (#11999)
When the server leaves a room the `get_rooms_for_user` cache is not correctly invalidated for the remote users in the room. This means that subsequent calls to `get_rooms_for_user` for the remote users would incorrectly include the room (it shouldn't be included because the server no longer knows anything about the room).
This commit is contained in:
parent
5598556b77
commit
dc9fe61050
1
changelog.d/11999.bugfix
Normal file
1
changelog.d/11999.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Fix long standing bug where `get_rooms_for_user` was not correctly invalidated for remote users when the server left a room.
|
@ -975,6 +975,17 @@ class PersistEventsStore:
|
|||||||
to_delete = delta_state.to_delete
|
to_delete = delta_state.to_delete
|
||||||
to_insert = delta_state.to_insert
|
to_insert = delta_state.to_insert
|
||||||
|
|
||||||
|
# Figure out the changes of membership to invalidate the
|
||||||
|
# `get_rooms_for_user` cache.
|
||||||
|
# We find out which membership events we may have deleted
|
||||||
|
# and which we have added, then we invalidate the caches for all
|
||||||
|
# those users.
|
||||||
|
members_changed = {
|
||||||
|
state_key
|
||||||
|
for ev_type, state_key in itertools.chain(to_delete, to_insert)
|
||||||
|
if ev_type == EventTypes.Member
|
||||||
|
}
|
||||||
|
|
||||||
if delta_state.no_longer_in_room:
|
if delta_state.no_longer_in_room:
|
||||||
# Server is no longer in the room so we delete the room from
|
# Server is no longer in the room so we delete the room from
|
||||||
# current_state_events, being careful we've already updated the
|
# current_state_events, being careful we've already updated the
|
||||||
@ -993,6 +1004,11 @@ class PersistEventsStore:
|
|||||||
"""
|
"""
|
||||||
txn.execute(sql, (stream_id, self._instance_name, room_id))
|
txn.execute(sql, (stream_id, self._instance_name, room_id))
|
||||||
|
|
||||||
|
# We also want to invalidate the membership caches for users
|
||||||
|
# that were in the room.
|
||||||
|
users_in_room = self.store.get_users_in_room_txn(txn, room_id)
|
||||||
|
members_changed.update(users_in_room)
|
||||||
|
|
||||||
self.db_pool.simple_delete_txn(
|
self.db_pool.simple_delete_txn(
|
||||||
txn,
|
txn,
|
||||||
table="current_state_events",
|
table="current_state_events",
|
||||||
@ -1102,17 +1118,6 @@ class PersistEventsStore:
|
|||||||
|
|
||||||
# Invalidate the various caches
|
# Invalidate the various caches
|
||||||
|
|
||||||
# Figure out the changes of membership to invalidate the
|
|
||||||
# `get_rooms_for_user` cache.
|
|
||||||
# We find out which membership events we may have deleted
|
|
||||||
# and which we have added, then we invalidate the caches for all
|
|
||||||
# those users.
|
|
||||||
members_changed = {
|
|
||||||
state_key
|
|
||||||
for ev_type, state_key in itertools.chain(to_delete, to_insert)
|
|
||||||
if ev_type == EventTypes.Member
|
|
||||||
}
|
|
||||||
|
|
||||||
for member in members_changed:
|
for member in members_changed:
|
||||||
txn.call_after(
|
txn.call_after(
|
||||||
self.store.get_rooms_for_user_with_stream_ordering.invalidate,
|
self.store.get_rooms_for_user_with_stream_ordering.invalidate,
|
||||||
|
@ -329,3 +329,110 @@ class ExtremPruneTestCase(HomeserverTestCase):
|
|||||||
|
|
||||||
# Check the new extremity is just the new remote event.
|
# Check the new extremity is just the new remote event.
|
||||||
self.assert_extremities([local_message_event_id, remote_event_2.event_id])
|
self.assert_extremities([local_message_event_id, remote_event_2.event_id])
|
||||||
|
|
||||||
|
|
||||||
|
class InvalideUsersInRoomCacheTestCase(HomeserverTestCase):
|
||||||
|
servlets = [
|
||||||
|
admin.register_servlets,
|
||||||
|
room.register_servlets,
|
||||||
|
login.register_servlets,
|
||||||
|
]
|
||||||
|
|
||||||
|
def prepare(self, reactor, clock, homeserver):
|
||||||
|
self.state = self.hs.get_state_handler()
|
||||||
|
self.persistence = self.hs.get_storage().persistence
|
||||||
|
self.store = self.hs.get_datastore()
|
||||||
|
|
||||||
|
def test_remote_user_rooms_cache_invalidated(self):
|
||||||
|
"""Test that if the server leaves a room the `get_rooms_for_user` cache
|
||||||
|
is invalidated for remote users.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Set up a room with a local and remote user in it.
|
||||||
|
user_id = self.register_user("user", "pass")
|
||||||
|
token = self.login("user", "pass")
|
||||||
|
|
||||||
|
room_id = self.helper.create_room_as(
|
||||||
|
"user", room_version=RoomVersions.V6.identifier, tok=token
|
||||||
|
)
|
||||||
|
|
||||||
|
body = self.helper.send(room_id, body="Test", tok=token)
|
||||||
|
local_message_event_id = body["event_id"]
|
||||||
|
|
||||||
|
# Fudge a join event for a remote user.
|
||||||
|
remote_user = "@user:other"
|
||||||
|
remote_event_1 = event_from_pdu_json(
|
||||||
|
{
|
||||||
|
"type": EventTypes.Member,
|
||||||
|
"state_key": remote_user,
|
||||||
|
"content": {"membership": Membership.JOIN},
|
||||||
|
"room_id": room_id,
|
||||||
|
"sender": remote_user,
|
||||||
|
"depth": 5,
|
||||||
|
"prev_events": [local_message_event_id],
|
||||||
|
"auth_events": [],
|
||||||
|
"origin_server_ts": self.clock.time_msec(),
|
||||||
|
},
|
||||||
|
RoomVersions.V6,
|
||||||
|
)
|
||||||
|
|
||||||
|
context = self.get_success(self.state.compute_event_context(remote_event_1))
|
||||||
|
self.get_success(self.persistence.persist_event(remote_event_1, context))
|
||||||
|
|
||||||
|
# Call `get_rooms_for_user` to add the remote user to the cache
|
||||||
|
rooms = self.get_success(self.store.get_rooms_for_user(remote_user))
|
||||||
|
self.assertEqual(set(rooms), {room_id})
|
||||||
|
|
||||||
|
# Now we have the local server leave the room, and check that calling
|
||||||
|
# `get_user_in_room` for the remote user no longer includes the room.
|
||||||
|
self.helper.leave(room_id, user_id, tok=token)
|
||||||
|
|
||||||
|
rooms = self.get_success(self.store.get_rooms_for_user(remote_user))
|
||||||
|
self.assertEqual(set(rooms), set())
|
||||||
|
|
||||||
|
def test_room_remote_user_cache_invalidated(self):
|
||||||
|
"""Test that if the server leaves a room the `get_users_in_room` cache
|
||||||
|
is invalidated for remote users.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Set up a room with a local and remote user in it.
|
||||||
|
user_id = self.register_user("user", "pass")
|
||||||
|
token = self.login("user", "pass")
|
||||||
|
|
||||||
|
room_id = self.helper.create_room_as(
|
||||||
|
"user", room_version=RoomVersions.V6.identifier, tok=token
|
||||||
|
)
|
||||||
|
|
||||||
|
body = self.helper.send(room_id, body="Test", tok=token)
|
||||||
|
local_message_event_id = body["event_id"]
|
||||||
|
|
||||||
|
# Fudge a join event for a remote user.
|
||||||
|
remote_user = "@user:other"
|
||||||
|
remote_event_1 = event_from_pdu_json(
|
||||||
|
{
|
||||||
|
"type": EventTypes.Member,
|
||||||
|
"state_key": remote_user,
|
||||||
|
"content": {"membership": Membership.JOIN},
|
||||||
|
"room_id": room_id,
|
||||||
|
"sender": remote_user,
|
||||||
|
"depth": 5,
|
||||||
|
"prev_events": [local_message_event_id],
|
||||||
|
"auth_events": [],
|
||||||
|
"origin_server_ts": self.clock.time_msec(),
|
||||||
|
},
|
||||||
|
RoomVersions.V6,
|
||||||
|
)
|
||||||
|
|
||||||
|
context = self.get_success(self.state.compute_event_context(remote_event_1))
|
||||||
|
self.get_success(self.persistence.persist_event(remote_event_1, context))
|
||||||
|
|
||||||
|
# Call `get_users_in_room` to add the remote user to the cache
|
||||||
|
users = self.get_success(self.store.get_users_in_room(room_id))
|
||||||
|
self.assertEqual(set(users), {user_id, remote_user})
|
||||||
|
|
||||||
|
# Now we have the local server leave the room, and check that calling
|
||||||
|
# `get_user_in_room` for the remote user no longer includes the room.
|
||||||
|
self.helper.leave(room_id, user_id, tok=token)
|
||||||
|
|
||||||
|
users = self.get_success(self.store.get_users_in_room(room_id))
|
||||||
|
self.assertEqual(users, [])
|
||||||
|
Loading…
Reference in New Issue
Block a user