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

Commit e4d622a

Browse files
committed
Implementation of state rollback in /sync
Implementation of SPEC-254: roll back the state dictionary to how it looked at the start of the timeline. Merged PR #373
1 parent fddedd5 commit e4d622a

File tree

2 files changed

+69
-4
lines changed

2 files changed

+69
-4
lines changed

synapse/rest/client/v2_alpha/sync.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
)
2121
from synapse.handlers.sync import SyncConfig
2222
from synapse.types import StreamToken
23+
from synapse.events import FrozenEvent
2324
from synapse.events.utils import (
2425
serialize_event, format_event_for_client_v2_without_event_id,
2526
)
@@ -256,7 +257,13 @@ def encode_room(room, filter, time_now, token_id, joined=True):
256257
:rtype: dict[str, object]
257258
"""
258259
event_map = {}
259-
state_events = filter.filter_room_state(room.state.values())
260+
state_dict = room.state
261+
timeline_events = filter.filter_room_timeline(room.timeline.events)
262+
263+
state_dict = SyncRestServlet._rollback_state_for_timeline(
264+
state_dict, timeline_events)
265+
266+
state_events = filter.filter_room_state(state_dict.values())
260267
state_event_ids = []
261268
for event in state_events:
262269
# TODO(mjark): Respect formatting requirements in the filter.
@@ -266,7 +273,6 @@ def encode_room(room, filter, time_now, token_id, joined=True):
266273
)
267274
state_event_ids.append(event.event_id)
268275

269-
timeline_events = filter.filter_room_timeline(room.timeline.events)
270276
timeline_event_ids = []
271277
for event in timeline_events:
272278
# TODO(mjark): Respect formatting requirements in the filter.
@@ -297,6 +303,63 @@ def encode_room(room, filter, time_now, token_id, joined=True):
297303

298304
return result
299305

306+
@staticmethod
307+
def _rollback_state_for_timeline(state, timeline):
308+
"""
309+
Wind the state dictionary backwards, so that it represents the
310+
state at the start of the timeline, rather than at the end.
311+
312+
:param dict[(str, str), synapse.events.EventBase] state: the
313+
state dictionary. Will be updated to the state before the timeline.
314+
:param list[synapse.events.EventBase] timeline: the event timeline
315+
:return: updated state dictionary
316+
"""
317+
logger.debug("Processing state dict %r; timeline %r", state,
318+
[e.get_dict() for e in timeline])
319+
320+
result = state.copy()
321+
322+
for timeline_event in reversed(timeline):
323+
if not timeline_event.is_state():
324+
continue
325+
326+
event_key = (timeline_event.type, timeline_event.state_key)
327+
328+
logger.debug("Considering %s for removal", event_key)
329+
330+
state_event = result.get(event_key)
331+
if (state_event is None or
332+
state_event.event_id != timeline_event.event_id):
333+
# the event in the timeline isn't present in the state
334+
# dictionary.
335+
#
336+
# the most likely cause for this is that there was a fork in
337+
# the event graph, and the state is no longer valid. Really,
338+
# the event shouldn't be in the timeline. We're going to ignore
339+
# it for now, however.
340+
logger.warn("Found state event %r in timeline which doesn't "
341+
"match state dictionary", timeline_event)
342+
continue
343+
344+
prev_event_id = timeline_event.unsigned.get("replaces_state", None)
345+
logger.debug("Replacing %s with %s in state dict",
346+
timeline_event.event_id, prev_event_id)
347+
348+
if prev_event_id is None:
349+
del result[event_key]
350+
else:
351+
result[event_key] = FrozenEvent({
352+
"type": timeline_event.type,
353+
"state_key": timeline_event.state_key,
354+
"content": timeline_event.unsigned['prev_content'],
355+
"sender": timeline_event.unsigned['prev_sender'],
356+
"event_id": prev_event_id,
357+
"room_id": timeline_event.room_id,
358+
})
359+
logger.debug("New value: %r", result.get(event_key))
360+
361+
return result
362+
300363

301364
def register_servlets(hs, http_server):
302365
SyncRestServlet(hs).register(http_server)

synapse/storage/events.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,8 @@ def _get_event_from_row(self, internal_metadata, js, redacted,
831831
allow_none=True,
832832
)
833833
if prev:
834-
ev.unsigned["prev_content"] = prev.get_dict()["content"]
834+
ev.unsigned["prev_content"] = prev.content
835+
ev.unsigned["prev_sender"] = prev.sender
835836

836837
self._get_event_cache.prefill(
837838
(ev.event_id, check_redacted, get_prev_content), ev
@@ -888,7 +889,8 @@ def _get_event_from_row_txn(self, txn, internal_metadata, js, redacted,
888889
get_prev_content=False,
889890
)
890891
if prev:
891-
ev.unsigned["prev_content"] = prev.get_dict()["content"]
892+
ev.unsigned["prev_content"] = prev.content
893+
ev.unsigned["prev_sender"] = prev.sender
892894

893895
self._get_event_cache.prefill(
894896
(ev.event_id, check_redacted, get_prev_content), ev

0 commit comments

Comments
 (0)