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

Commit 2186ebe

Browse files
author
David Robertson
authored
Fetch fewer events when getting hosts in room (#14962)
1 parent f398886 commit 2186ebe

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

changelog.d/14962.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve performance when joining or sending an event large rooms.

synapse/storage/databases/main/roommember.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
import logging
16+
from itertools import chain
1617
from typing import (
1718
TYPE_CHECKING,
1819
AbstractSet,
@@ -1131,12 +1132,33 @@ async def _get_joined_hosts(
11311132
else:
11321133
# The cache doesn't match the state group or prev state group,
11331134
# so we calculate the result from first principles.
1135+
#
1136+
# We need to fetch all hosts joined to the room according to `state` by
1137+
# inspecting all join memberships in `state`. However, if the `state` is
1138+
# relatively recent then many of its events are likely to be held in
1139+
# the current state of the room, which is easily available and likely
1140+
# cached.
1141+
#
1142+
# We therefore compute the set of `state` events not in the
1143+
# current state and only fetch those.
1144+
current_memberships = (
1145+
await self._get_approximate_current_memberships_in_room(room_id)
1146+
)
1147+
unknown_state_events = {}
1148+
joined_users_in_current_state = []
1149+
1150+
for (type, state_key), event_id in state.items():
1151+
if event_id not in current_memberships:
1152+
unknown_state_events[type, state_key] = event_id
1153+
elif current_memberships[event_id] == Membership.JOIN:
1154+
joined_users_in_current_state.append(state_key)
1155+
11341156
joined_user_ids = await self.get_joined_user_ids_from_state(
1135-
room_id, state
1157+
room_id, unknown_state_events
11361158
)
11371159

11381160
cache.hosts_to_joined_users = {}
1139-
for user_id in joined_user_ids:
1161+
for user_id in chain(joined_user_ids, joined_users_in_current_state):
11401162
host = intern_string(get_domain_from_id(user_id))
11411163
cache.hosts_to_joined_users.setdefault(host, set()).add(user_id)
11421164

@@ -1147,6 +1169,26 @@ async def _get_joined_hosts(
11471169

11481170
return frozenset(cache.hosts_to_joined_users)
11491171

1172+
async def _get_approximate_current_memberships_in_room(
1173+
self, room_id: str
1174+
) -> Mapping[str, Optional[str]]:
1175+
"""Build a map from event id to membership, for all events in the current state.
1176+
1177+
The event ids of non-memberships events (e.g. `m.room.power_levels`) are present
1178+
in the result, mapped to values of `None`.
1179+
1180+
The result is approximate for partially-joined rooms. It is fully accurate
1181+
for fully-joined rooms.
1182+
"""
1183+
1184+
rows = await self.db_pool.simple_select_list(
1185+
"current_state_events",
1186+
keyvalues={"room_id": room_id},
1187+
retcols=("event_id", "membership"),
1188+
desc="has_completed_background_updates",
1189+
)
1190+
return {row["event_id"]: row["membership"] for row in rows}
1191+
11501192
@cached(max_entries=10000)
11511193
def _get_joined_hosts_cache(self, room_id: str) -> "_JoinedHostsCache":
11521194
return _JoinedHostsCache()

0 commit comments

Comments
 (0)