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

User directory: use calculated room membership state instead #9821

Merged
merged 2 commits into from
Apr 16, 2021
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/9821.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reduce CPU usage of the user directory by reusing existing calculated room membership.
15 changes: 8 additions & 7 deletions synapse/handlers/user_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ def __init__(self, hs: "HomeServer"):
super().__init__(hs)

self.store = hs.get_datastore()
self.state = hs.get_state_handler()
self.server_name = hs.hostname
self.clock = hs.get_clock()
self.notifier = hs.get_notifier()
Expand Down Expand Up @@ -302,10 +301,12 @@ async def _handle_room_publicity_change(
# ignore the change
return

users_with_profile = await self.state.get_current_users_in_room(room_id)
other_users_in_room_with_profiles = (
await self.store.get_users_in_room_with_profiles(room_id)
)

# Remove every user from the sharing tables for that room.
for user_id in users_with_profile.keys():
for user_id in other_users_in_room_with_profiles.keys():
await self.store.remove_user_who_share_room(user_id, room_id)

# Then, re-add them to the tables.
Expand All @@ -314,7 +315,7 @@ async def _handle_room_publicity_change(
# which when ran over an entire room, will result in the same values
# being added multiple times. The batching upserts shouldn't make this
# too bad, though.
for user_id, profile in users_with_profile.items():
for user_id, profile in other_users_in_room_with_profiles.items():
await self._handle_new_user(room_id, user_id, profile)

async def _handle_new_user(
Expand All @@ -336,7 +337,7 @@ async def _handle_new_user(
room_id
)
# Now we update users who share rooms with users.
users_with_profile = await self.state.get_current_users_in_room(room_id)
other_users_in_room = await self.store.get_users_in_room(room_id)

if is_public:
await self.store.add_users_in_public_rooms(room_id, (user_id,))
Expand All @@ -352,14 +353,14 @@ async def _handle_new_user(

# We don't care about appservice users.
if not is_appservice:
for other_user_id in users_with_profile:
for other_user_id in other_users_in_room:
if user_id == other_user_id:
continue

to_insert.add((user_id, other_user_id))

# Next we need to update for every local user in the room
for other_user_id in users_with_profile:
for other_user_id in other_users_in_room:
if user_id == other_user_id:
continue

Expand Down
27 changes: 27 additions & 0 deletions synapse/storage/databases/main/roommember.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,33 @@ def get_users_in_room_txn(self, txn, room_id: str) -> List[str]:
txn.execute(sql, (room_id, Membership.JOIN))
return [r[0] for r in txn]

@cached(max_entries=100000, iterable=True)
async def get_users_in_room_with_profiles(
self, room_id: str
) -> Dict[str, ProfileInfo]:
"""Get a mapping from user ID to profile information for all users in a given room.
Args:
room_id: The ID of the room to retrieve the users of.
Returns:
A mapping from user ID to ProfileInfo.
"""

def _get_users_in_room_with_profiles(txn) -> Dict[str, ProfileInfo]:
sql = """
SELECT user_id, display_name, avatar_url FROM room_memberships
WHERE room_id = ? AND membership = ?
"""
txn.execute(sql, (room_id, Membership.JOIN))

return {r[0]: ProfileInfo(display_name=r[1], avatar_url=r[2]) for r in txn}

return await self.db_pool.runInteraction(
"get_users_in_room_with_profiles",
_get_users_in_room_with_profiles,
)

@cached(max_entries=100000)
async def get_room_summary(self, room_id: str) -> Dict[str, MemberSummary]:
"""Get the details of a room roughly suitable for use by the room
Expand Down