perf(sync): skip per-room build for quiet rooms on incremental sync#241
Merged
Conversation
the joined-room loop built every room's full sync payload (timeline, state delta, receipts + unread scans, member counts) and only then discarded quiet rooms via room_is_unchanged — so an incremental poll did work proportional to ALL joined rooms even when nothing changed. pre-gate the loop with a few point-gets (room's latest timeline pos, receipts max pos, per-(user,room) account-data max pos, in-memory typing pos) vs the caller's cursor, and skip the build entirely when none advanced. conservative: any doubt or DB error builds, and the authoritative room_is_unchanged gate still runs for whatever passes, so this can only save work, never drop an update.
new advisory (invalid pointer deref in the fmt::Pointer impl for Atomic/Shared) fixed in 0.9.20. transitive via moka + metrics-util; the buggy path (Debug-formatting an invalid crossbeam pointer) isn't reached by vela, but it fails `cargo deny` on main so bump it. lockfile-only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First of a performance series. Profiling
/sync(the highest-volume endpoint) showed the joined-room loop builds every room's full payload — timeline, state delta, receipt + unread scans, member counts — and only then discards quiet rooms viaroom_is_unchanged. So an incremental poll does work proportional to all joined rooms even when nothing changed.Fix: pre-gate the loop with a few cheap point-gets (the room's latest timeline pos, receipts max pos, per-(user,room) account-data max pos, and the in-memory typing pos) against the caller's cursor, and skip the build entirely when none advanced past it. This turns a quiet incremental poll from O(rooms × full-build) into O(rooms × a few point-gets).
Correctness is the whole risk (a wrong skip drops an update or busy-loops the client). It's conservative — any doubt or DB error falls through to the build — and the authoritative
room_is_unchangedgate still runs for whatever passes, so it can only save work, never drop an update. A review pass confirmed the invariant (room_has_changes_since= false ⟹room_is_unchanged= true): every sectionroom_is_unchangedchecks (timeline/state/state_after/ephemeral/account_data) maps onto one of the four positions, all in the samestream_counterspace assince, and Live state events carry a timeline stream_pos so state-only changes are covered.Test (
tests/sync_quiet_room_pregate.rs): a quiet room is omitted, and a room whose only change is a receipt, account-data, state-only, or typing update still surfaces.Initial sync is unchanged; this cuts incremental-sync CPU for the common case (most joined rooms quiet on any given poll).
Also includes a drive-by lockfile bump: crossbeam-epoch 0.9.18 → 0.9.20 for the just-published RUSTSEC-2026-0204 (invalid pointer deref in
fmt::PointerforAtomic/Shared). Transitive via moka/metrics-util; the buggy path isn't reached by vela, but it failscargo denyon main. Lockfile-only, folded in here to avoid a separate PR + rebase.