Skip to content

Conversation

MadLittleMods
Copy link
Contributor

@MadLittleMods MadLittleMods commented Aug 29, 2025

Implements MSC3871: Gappy timelines

  • Add the gaps field to the /messages endpoint

Complement tests: matrix-org/complement#801

Testing strategy

  1. Clone synapse
  2. Checkout the correct branch: git checkout madlittlemods/msc3871-gappy-timeline (this PR)
  3. Install Synapse's dependencies: poetry install
  4. Clone complement next to synapse as a sibling
  5. Checkout the correct branch: git checkout madlittlemods/msc3871-gappy-timeline (Tests for MSC3871: Gappy timelines matrix-org/complement#801)

In order to manually test with a real Matrix client:

  1. In complement, uncomment the sleep call in TestRoomMessagesGaps
  2. Start the Complement tests: COMPLEMENT_DIR=../complement ./scripts-dev/complement.sh -run TestRoomMessagesGaps
  3. Find which port hs3 is running on: docker ps -f name=complement_ (ex. 0.0.0.0:33413->8008/tcp)
  4. Configure your Matrix client with that homeserver URL: http://localhost:33413
  5. Register a new user
  6. Join the room from the test (in the log output)
  7. Back paginate in the room: /messages?dir=b&backfill=false and notice the gaps in the room
  8. To fill in gaps: /messages?dir=b&backfill=true&from=<prev_pagination_token>

Reference: Complement docs on how to hook up a Matrix client

Dev notes

Document how to hook up Element to the resultant homeservers from Complement: matrix-org/complement#164

matrix-org/complement -> ONBOARDING.md -> How do I hook up a Matrix client like Element to the homeservers spun up by Complement after a test runs?

Todo

  • Put the behavior behind a experimental feature flag
  • Add test_gaps_going_forwards
  • Add some Complement tests
  • Separate out the /messages?backfill=true/false changes (simplified version of MSC4282)

Pull Request Checklist

  • Pull request is based on the develop branch
  • Pull request includes a changelog file. The entry should:
    • Be a short description of your change which makes sense to users. "Fixed a bug that prevented receiving messages from other servers." instead of "Moved X method from EventStore to EventWorkerStore.".
    • Use markdown where necessary, mostly for code blocks.
    • End with either a period (.) or an exclamation mark (!).
    • Start with a capital letter.
    • Feel free to credit yourself, by adding a sentence "Contributed by @github_username." or "Contributed by [Your Name]." to the end of the entry.
  • Code style is correct (run the linters)

To try out the flow:

 - **Default to fast responses with gaps**: As a default, we can always
     respond quickly and indicate gaps ([MSC3871]
     (matrix-org/matrix-spec-proposals#3871)) for
     clients to paginate at their leisure.
 - **Fast back-pagination**: Clients back-paginate with
     `/messages?dir=b&backfill=false`, and Synapse skips backfilling
     entirely, returning only local history with gaps as necessary.
 - **Explicit gap filling**: To fill in gaps, clients use
     `/messages?dir=b&backfill=true` which works just like today to do a best
     effort backfill.

This allows the client to back-paginate the history we already have without
delay. And can fill in the gaps as they see fit.

This is basically a simplified version of [MSC4282]
(matrix-org/matrix-spec-proposals#4282).
Comment on lines -830 to -836
def get_stream_pos_for_instance(self, instance_name: str) -> int:
"""Get the stream position that the given writer was at at this token.
def is_before_or_eq(self, other_token: Self) -> bool:
is_before_or_eq_stream_ordering = super().is_before_or_eq(other_token)
if not is_before_or_eq_stream_ordering:
return False

This only makes sense for "live" tokens that may have a vector clock
component, and so asserts that this is a "live" token.
"""
assert self.topological is None
Copy link
Contributor Author

@MadLittleMods MadLittleMods Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed get_stream_pos_for_instance because there is no need to have this specialized version that only allows stream-based tokens. We will fallback to the super() version which is the same but without the topological restriction.

While only "live" tokens may have a vector clock component, historical topological tokens still include a stream position (t426-2633508) and it makes sense for this to still work.

Historic tokens start with a "t" followed by the `depth`
(`topological_ordering` in the event graph) of the event that comes before
the position of the token, followed by "-", followed by the
`stream_ordering` of the event that comes before the position of the token.
An example token is:
t426-2633508

Comment on lines +1222 to +1223
It's best to pad the `current_depth` by the number of messages you plan to
backfill from these points.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good useful change that we could ship outside of this PR.

Noting in case this PR goes stale

Comment on lines +89 to +91
# from synapse.storage.databases.main.stream import (
# generate_next_token,
# )
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# from synapse.storage.databases.main.stream import (
# generate_next_token,
# )

Comment on lines +2369 to +2370
ignore_gap_after_latest: Whether the gap after the latest events (forward
extremeties) in the room should be considered as an actual gap.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per matrix-org/matrix-spec-proposals#3871 (comment), we should revert the ignore_gap_after_latest change.

The default of "omit the gap after the latest messages in the room" is the correct choice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant