summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Eastwood <erice@element.io>2022-05-23 20:43:37 -0500
committerGitHub <noreply@github.com>2022-05-23 20:43:37 -0500
commit7c2a78bb3bd2091439722e9f1e4601837bcb8fc4 (patch)
treecd594ff5e93fbbd42cf0b406d46c4bc52bb97951
parentUniformize spam-checker API, part 2: check_event_for_spam (#12808) (diff)
downloadsynapse-7c2a78bb3bd2091439722e9f1e4601837bcb8fc4.tar.xz
Marker events as state - MSC2716 (#12718)
Sending marker events as state now so they are always able to be seen by homeservers (not lost in some timeline gap).

Part of [MSC2716](https://github.com/matrix-org/matrix-spec-proposals/pull/2716)

Complement tests: https://github.com/matrix-org/complement/pull/371

As initially discussed at https://github.com/matrix-org/matrix-spec-proposals/pull/2716#discussion_r782629097 and https://github.com/matrix-org/matrix-spec-proposals/pull/2716#discussion_r876684431

When someone joins a room, process all of the marker events we see in the current state. Marker events should be sent with a unique `state_key` so that they can all resolve in the current state to easily be discovered. Marker events as state

 - If we re-use the same `state_key` (like `""`), then we would have to fetch previous snapshots of state up through time to find all of the marker events. This way we can avoid all of that. This PR was originally doing this but then thought of the smarter way to tackle in an [out of band discussion with @erikjohnston](https://docs.google.com/document/d/1JJDuPfcPNX75fprdTWlxlaKjWOdbdJylbpZ03hzo638/edit#bookmark=id.sm92fqyq7vpp).
 - Also avoids state resolution conflicts where only one of the marker events win

As a homeserver, when we see new marker state, we know there is new history imported somewhere back in time and should process it to fetch the insertion event where the historical messages are and set it as an insertion extremity. This way we know where to backfill more messages when someone asks for scrollback.
-rw-r--r--changelog.d/12718.feature1
-rw-r--r--synapse/handlers/federation_event.py26
2 files changed, 26 insertions, 1 deletions
diff --git a/changelog.d/12718.feature b/changelog.d/12718.feature
new file mode 100644
index 0000000000..1056f519a4
--- /dev/null
+++ b/changelog.d/12718.feature
@@ -0,0 +1 @@
+Update [MSC2716](https://github.com/matrix-org/matrix-spec-proposals/pull/2716) implementation to process marker events from the current state to avoid markers being lost in timeline gaps for federated servers which would cause the imported history to be undiscovered.
diff --git a/synapse/handlers/federation_event.py b/synapse/handlers/federation_event.py
index 05c122f224..ca82df8a6d 100644
--- a/synapse/handlers/federation_event.py
+++ b/synapse/handlers/federation_event.py
@@ -477,7 +477,23 @@ class FederationEventHandler:
             # and discover that we do not have it.
             event.internal_metadata.proactively_send = False
 
-            return await self.persist_events_and_notify(room_id, [(event, context)])
+            stream_id_after_persist = await self.persist_events_and_notify(
+                room_id, [(event, context)]
+            )
+
+            # If we're joining the room again, check if there is new marker
+            # state indicating that there is new history imported somewhere in
+            # the DAG. Multiple markers can exist in the current state with
+            # unique state_keys.
+            #
+            # Do this after the state from the remote join was persisted (via
+            # `persist_events_and_notify`). Otherwise we can run into a
+            # situation where the create event doesn't exist yet in the
+            # `current_state_events`
+            for e in state:
+                await self._handle_marker_event(origin, e)
+
+            return stream_id_after_persist
 
     async def update_state_for_partial_state_event(
         self, destination: str, event: EventBase
@@ -1230,6 +1246,14 @@ class FederationEventHandler:
             # Nothing to retrieve then (invalid marker)
             return
 
+        already_seen_insertion_event = await self._store.have_seen_event(
+            marker_event.room_id, insertion_event_id
+        )
+        if already_seen_insertion_event:
+            # No need to process a marker again if we have already seen the
+            # insertion event that it was pointing to
+            return
+
         logger.debug(
             "_handle_marker_event: backfilling insertion event %s", insertion_event_id
         )