Skip to content

Commit e217542

Browse files
committed
MSC2775: Lazy loading over federation
A first cut at an MSC to define how to massively speed up joins (and MSC #2444 peeks) by sending irrelevant events after you join rather than up front
1 parent 89a3663 commit e217542

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Lazy loading room membership over federation
2+
3+
## Problem
4+
5+
Joining remote rooms for the first time from your homeserver can be very slow.
6+
This is particularly painful for the first time user experience of a new
7+
homeserver owner.
8+
9+
Causes include:
10+
* Room state can be big. For instance, a /send_join response for Matrix HQ is
11+
currently 24MB of JSON covering 28,188 events, and could easily take tens of
12+
seconds to calculate and send (especially on lower-end hardware).
13+
* All these events have to be verified by the receiving server.
14+
* Your server may have to fetch ths signing keys for all the servers who have
15+
sent state into the room.
16+
17+
This also impacts peeking over federation
18+
([MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444)), which is even
19+
more undesirable, given users expect peeking to have a very snappy UX, letting them
20+
quickly check links to sample rooms etc.
21+
22+
For instance Gitter shows a usable peeked page for a room with 20K
23+
members in under 2 seconds (https://gitter.im/webpack/webpack) including
24+
launching the whole webapp. Similarly Discord loads usable state for a server
25+
with 90K users like https://chat.vuejs.org in around 2s.
26+
27+
## Proposal
28+
29+
The vast majority of state events in Matrix today are `m.room.member` events.
30+
For instance, 99.4% (30661 out of 30856) of Matrix HQ's state is
31+
`m.room.member`s (see Stats section below).
32+
33+
Therefore, in the response to `/send_join` (or a MSC2444 `/peek`), we propose
34+
sending only the following `m.room.member` events if the initiating server
35+
includes `lazy_load_members: true` in their JSON request body.
36+
37+
* the "hero" room members which are needed for clients to display
38+
a summary of the room (based on the
39+
[requirements of the CS API](https://github.com/matrix-org/matrix-doc/blob/1c7a6a9c7fa2b47877ce8790ea5e5c588df5fa90/api/client-server/sync.yaml#L148))
40+
* any members which are in the auth chain for the state events in the response
41+
42+
In addition, we extend the response to `/send_join` and `/peek` to include a
43+
`summary` block, matching that of the CS `/sync` API, giving the local server
44+
the necessary data to support MSC1227 CS API lazy loading.
45+
46+
The joining server can then sync in the remaining membership events by calling
47+
`/state` as of the user's join event. To avoid retrieving duplicate data, we
48+
propose adding a parameter of `lazy_load_members_only: true` to the JSON
49+
request body which would then only return the missing `m.room.member` events.
50+
51+
Clients which are not lazy loading members (by MSC1227) must block returning
52+
the CS API `/join` or `/peek` until this `/state` has completed and been
53+
processed.
54+
55+
Clients which are lazy loading members however may return the initial `/join`
56+
or `/peek` before `/state` has completed. However, we need a way to tell
57+
clients once the server has finished synchronising its local state. For
58+
instance, clients must not let the user send E2EE messages until their server
59+
has acquired the full set of room members for the room, otherwise some of the
60+
users will not have the keys to decrypt the message. We do this by adding an
61+
`syncing: true` field to the room's `state` block in the `/sync` response.
62+
Once this field is missing or false, the client knows it is safe to call
63+
`/members` and get a full list of the room members in order to encrypt
64+
successfully. The field can also be used to advise the client to not
65+
prematurely call `/members` to show an incomplete membership list in its UI
66+
(but show a spinner or similar instead).
67+
68+
While the joining server is busy syncing the remaining room members via
69+
`/state`, it will also need to sync new inbound events to the user (and old
70+
ones if the user calls `/messages`). If these events refer to members we're
71+
not yet aware of (e.g. they're sent by a user our server hasn't lazyloaded
72+
yet) we should separately retrieve their membership event so the server can
73+
include it in the `/sync` response to the client. To do this, we add fields
74+
to `/state` to let our server request a specific `type` and `state_key` from
75+
the target server.
76+
77+
## Alternatives
78+
79+
Rather than making this specific to membership events, we could lazy load all
80+
state by default. However, it's challenging to know which events the server
81+
(and clients) need up front in order to correctly handle the room - plus this
82+
list may well change over time. For instance, do we need to know the
83+
`uk.half-shot.bridge` event in the Stats section up front?
84+
85+
Rather than reactively pulling in missing membership events as needed while
86+
the room is syncing in the background, we could require the server we're
87+
joining via to proactively push us member events it knows we don't know about
88+
yet, and save a roundtrip. This feels more fiddly though; we can optimise this
89+
edge case if it's actually needed.
90+
91+
## Related
92+
93+
MSC1228 (and future variants) also will help speed up joining rooms
94+
significantly, as you no longer have to query for server keys given the room
95+
ID becomes a server's public key.
96+
97+
## Stats
98+
99+
```
100+
matrix=> select type, count(*) from matrix.state_events where room_id='!OGEhHVWSdvArJzumhm:matrix.org' group by type order by count(*) desc;
101+
type | count
102+
---------------------------+-------
103+
m.room.member | 30661
104+
m.room.aliases | 141
105+
m.room.server_acl | 23
106+
m.room.join_rules | 9
107+
m.room.guest_access | 6
108+
m.room.power_levels | 5
109+
m.room.history_visibility | 3
110+
m.room.name | 1
111+
m.room.related_groups | 1
112+
m.room.avatar | 1
113+
m.room.topic | 1
114+
m.room.create | 1
115+
uk.half-shot.bridge | 1
116+
m.room.canonical_alias | 1
117+
m.room.bot.options | 1
118+
```

0 commit comments

Comments
 (0)