Chapter 13
Syncing group info and members
Ana opens the hiking group. Each message has to show what its sender is called in the group, and typing @ has to list the members. Where does the phone’s copy of the member list come from, and how does it know it changed?
This chapter is a first draft. It will be revised once the first eight chapters are written.
Chapter 12 was about the server: who is in a group, and which stretch each person may read. But Ana’s phone needs a copy too.
When she opens the hiking group, each message shows what its sender is called in the group; typing @ lists the members; and the chat list shows the group’s name and avatar. That takes two sets of data: the group info (name, avatar, notice) and the member list (each member’s group nickname and role). Each person’s own name and avatar are their user profile, a separate matter this chapter leaves aside.
1. Fetch it all on every open
The simplest way: when a group is opened, ask the server for the whole member list. A member is about 40 bytes (user ID, group nickname, role), so the hiking group’s 500 are 20 KB.
Twenty opens a day make 400 KB, more than 7 times the text Ana receives in a day (chapter 11), and the server reads 500 rows each time. Yet that day the members changed only a few times.
Two common ways to save traffic:
- Cache it for an hour and fetch again only when it is older. Less than half the traffic, but changes in between go unseen: a new member cannot be @mentioned, a new group nickname still shows the old one.
- Send a hash of the copy you have, and get “not modified” if it is current. The list is always current, but if one person changed, the whole list comes again: six changes a day in the hiking group are 120 KB.
Here is Ana’s day in three groups; each open is a bar, as tall as what that open downloaded for the list:
downloaded per open (height)used an old lista member change
The three groups downloaded 523.8 KB that day; every open had the current list.
- Whole list: 524 KB for the day.
- Cached 1 h: less than half, but some opens (the red rings) used an old list.
- Send a hash: a tall bar only on the open after a change, 144 KB for the day.
A hash can say “changed or not”, but not “who changed”.
2. The fix: a member version per group
- Server: the group’s row (the one chapter 12 locks to take a seq) gets a member versionmember version成员版本号A per-group number that goes up with every member change (join, leave, group nickname, role), stamped on that member’s row. The phone keeps the member list with its version and sends it when opening the group; the server answers with just the version if nothing changed, otherwise only the changed rows (chapter 13).See the glossary. A join, a leave, a new group nickname or a new role bumps it in the same transaction, and the new version is stamped on that member’s row (rows of those who left stay, chapter 12).
- Phone: keeps the list and the version it is at. On opening the group it sends the version: “I am at 37.”
- Reply: if nothing changed, the current version, 4 bytes; otherwise only the rows with a version above 37, about 44 bytes each. An index on (group, version) means only those rows are read.
Pick “Send my version” in the scene: the same day costs about half a KB across the three groups, and every list is current.
It is the same idea as chapter 11’s record version: that one is per person, stamped on conversation records; this one is per group, stamped on member rows.
3. Group info and “my groups” ride on the conversation records
When the group’s name, avatar or notice changes, the chat list must follow, without waiting for the group to be opened. These change rarely, so they go straight onto every member’s conversation record, bumping the record version as pinning and muting do (chapter 11), and conversation sync brings them to every device. The group also gets a system message for people to read: “Ana renamed the group to ‘Saturday hike’”.
On a new device’s first login, the group’s name and avatar come down with the conversation records (chapter 10).
“The groups I am in” needs no version of its own either. When Ana joins a group she gains a conversation record; when she leaves, that record is marked as left (chapter 11); both bump her record version. The “my groups” list in her contacts is simply the records of the groups she is still in. Deleting a group chat from the chat list only marks the record hidden; she is still in the group.
So there are two versions, each with its own job:
| Version | Kept per | Covers |
|---|---|---|
| Record version (ch. 11) | person | the chat list, my groups, group name, avatar and notice |
| Member version (here) | group | one group’s member list |
Joins and leaves are already system messages (chapter 12), so while the group is open the phone can update its list as they arrive. The phone’s version has not moved, so the next open brings those rows again and they are simply written over. Changes that send no message, such as a new group nickname, are picked up by version on the next open.
4. The numbers
- One open: the whole hiking group, 20 KB; by version, 4 bytes if nothing changed, about 44 bytes per changed member.
- A day: the three groups in the scene, 524 KB whole, 144 KB by hash, about 0.5 KB by version.
- Server: a whole list reads 500 rows each open; by version, only the group’s row when nothing changed.
5. The cost
- The member table gets a column and an index. Each member change also updates that member’s row.
- The phone stores a list per group, but only for groups it has opened.
- Changes that send no message wait. A group nickname changed while the group is open shows only on the next open; to show it at once, the server has to push a signal too.
- Once old rows of leavers are archived, a phone with a very old version cannot tell who left and fetches the whole list once.
6. Other answers
- Fetch it all on every open. Fine for small groups: the family group’s 12 members are 480 bytes.
- Telegram: a version for small groups, a hash for big ones. A basic group’s member list (
chatParticipants) carries a groupversion, and so does each membership update (such asupdateChatParticipantAdd), so clients can drop stale data: the same thing as this chapter’s member version, except that changes are pushed. Supergroups can have hundreds of thousands of members, fetched a page at a time (channels.getParticipants) with a hash of the page the client has; the answer ischannelParticipantsNotModifiedif it is current, and the whole page again if not. - Only the members in view. Matrix can send member information only for the senders of the messages being returned (lazy-loading room members), and the full list when it is needed. Suits very large rooms.
- Push every change to every member. The list is always current, but each change is a push to the whole group, and members who were offline still have to catch up.
- Huge groups. In a group of tens of thousands, the list is never sent whole but paged and searched; that is chapter 40.
7. This chapter’s decision
Server and phone now agree on what goes on in a group. But what about private chats? Can a stranger message Ana, can someone she blocked still reach her, can a buyer message a seller? Every product answers differently. Next: who may message whom.