Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Handle missing previous read marker event #15464

Merged
1 change: 1 addition & 0 deletions changelog.d/15464.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Don't fail moving read marker if current set to a missing event. Contributed by Nick @ Beeper (@fizzadar).
Fizzadar marked this conversation as resolved.
Show resolved Hide resolved
18 changes: 14 additions & 4 deletions synapse/handlers/read_marker.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import logging
from typing import TYPE_CHECKING

from synapse.api.errors import SynapseError
from synapse.util.async_helpers import Linearizer

if TYPE_CHECKING:
Expand Down Expand Up @@ -46,12 +47,21 @@ async def received_client_read_marker(
)

should_update = True
# Get event ordering, this also ensures we know about the event
event_ordering = await self.store.get_event_ordering(event_id)

if existing_read_marker:
# Only update if the new marker is ahead in the stream
should_update = await self.store.is_event_after(
event_id, existing_read_marker["event_id"]
)
try:
old_event_ordering = await self.store.get_event_ordering(
existing_read_marker["event_id"]
)
except SynapseError:
# Old event no longer exists, assume new is ahead. This may
# happen if the old event was removed due to retention.
pass
clokep marked this conversation as resolved.
Show resolved Hide resolved
else:
# Only update if the new marker is ahead in the stream
should_update = event_ordering > old_event_ordering

if should_update:
content = {"event_id": event_id}
Expand Down
6 changes: 0 additions & 6 deletions synapse/storage/databases/main/events_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1976,12 +1976,6 @@ def get_deltas_for_stream_id_txn(

return rows, to_token, True

async def is_event_after(self, event_id1: str, event_id2: str) -> bool:
"""Returns True if event_id1 is after event_id2 in the stream"""
to_1, so_1 = await self.get_event_ordering(event_id1)
to_2, so_2 = await self.get_event_ordering(event_id2)
return (to_1, so_1) > (to_2, so_2)

@cached(max_entries=5000)
async def get_event_ordering(self, event_id: str) -> Tuple[int, int]:
res = await self.db_pool.simple_select_one(
Expand Down