-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Update get_pdu
to return the original, pristine EventBase
#13320
Changes from 7 commits
ee236ca
79a1b72
bfd35fd
e0e20a5
22410f2
09c411b
6029b42
09167b1
eb6a291
1c4e57c
488f5ed
29a5269
2688e44
24913e7
0e6dd5a
5bc75ed
dea7669
72e65a5
86fe0dc
fd879bb
354678f
233077c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fix `FederationClient.get_pdu()` returning events from the cache as `outliers` instead of original events we saw over federation. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,7 +53,7 @@ | |
RoomVersion, | ||
RoomVersions, | ||
) | ||
from synapse.events import EventBase, builder | ||
from synapse.events import EventBase, builder, make_event_from_dict | ||
from synapse.federation.federation_base import ( | ||
FederationBase, | ||
InvalidEventSignatureError, | ||
|
@@ -309,7 +309,7 @@ async def get_pdu_from_destination_raw( | |
) | ||
|
||
logger.debug( | ||
"retrieved event id %s from %s: %r", | ||
"get_pdu_from_destination_raw: retrieved event id %s from %s: %r", | ||
event_id, | ||
destination, | ||
transaction_data, | ||
|
@@ -358,11 +358,33 @@ async def get_pdu( | |
The requested PDU, or None if we were unable to find it. | ||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I like the idea of having it be immutable 👍
But needing to pass in We can tackle this in another potential PR though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, there's definitely a balance of two evils here. I'm happy to punt this for now at least. |
||
|
||
logger.debug( | ||
"get_pdu: event_id=%s from destinations=%s", event_id, destinations | ||
) | ||
|
||
# TODO: Rate limit the number of times we try and get the same event. | ||
|
||
ev = self._get_pdu_cache.get(event_id) | ||
if ev: | ||
return ev | ||
event_copy = None | ||
event_from_cache = self._get_pdu_cache.get(event_id) | ||
MadLittleMods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if event_from_cache: | ||
logger.debug("get_pdu: found event_from_cache=%s", event_from_cache) | ||
assert not event_from_cache.internal_metadata.outlier, ( | ||
MadLittleMods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"Event from cache unexpectedly an `outlier` when it should be pristine and untouched without metadata set. " | ||
MadLittleMods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"We are probably not be returning a copy of the event because downstream callers are modifying the event reference we have in the cache." | ||
MadLittleMods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
|
||
# Make sure to return a copy because downstream callers will use | ||
# this event reference directly and change our original, pristine, | ||
# untouched PDU. For example when people mark the event as an | ||
# `outlier` (`event.internal_metadata.outlier = true`), we don't | ||
# want that to propagate back into the cache. | ||
event_copy = make_event_from_dict( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we're going to build a new EventBase on each call, why not just cache the raw json? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would work. But we would have to convert the |
||
event_from_cache.get_pdu_json(), | ||
event_from_cache.room_version, | ||
internal_metadata_dict=None, | ||
MadLittleMods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
|
||
return event_copy | ||
|
||
pdu_attempts = self.pdu_destination_tried.setdefault(event_id, {}) | ||
|
||
|
@@ -371,6 +393,13 @@ async def get_pdu( | |
now = self._clock.time_msec() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wait... does this loop always try all the destinations, even if the first one works? that would be a substantial bug, if it was ever called with more than one destination, which I don't think it is... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like it is bugged. I can add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Followed up in #13346 |
||
last_attempt = pdu_attempts.get(destination, 0) | ||
if last_attempt + PDU_RETRY_TIME_MS > now: | ||
logger.debug( | ||
"get_pdu: skipping destination=%s because we tried it recently last_attempt=%s and we only check every %s (now=%s)", | ||
destination, | ||
last_attempt, | ||
PDU_RETRY_TIME_MS, | ||
now, | ||
) | ||
continue | ||
|
||
try: | ||
|
@@ -403,9 +432,24 @@ async def get_pdu( | |
continue | ||
|
||
if signed_pdu: | ||
MadLittleMods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self._get_pdu_cache[event_id] = signed_pdu | ||
self._get_pdu_cache[signed_pdu.event_id] = signed_pdu | ||
|
||
# Make sure to return a copy because downstream callers will use this | ||
# event reference directly and change our original, pristine, untouched | ||
# PDU. For example when people mark the event as an `outlier` | ||
# (`event.internal_metadata.outlier = true`), we don't want that to | ||
# propagate back into the cache. | ||
# | ||
# We could get away with only making a new copy of the event when | ||
# pulling from cache but it's probably better to have good hygiene and | ||
# not dirty the cache in the first place as well. | ||
event_copy = make_event_from_dict( | ||
signed_pdu.get_pdu_json(), | ||
signed_pdu.room_version, | ||
internal_metadata_dict=None, | ||
) | ||
MadLittleMods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return signed_pdu | ||
return event_copy | ||
|
||
async def get_room_state_ids( | ||
self, destination: str, room_id: str, event_id: str | ||
|
Uh oh!
There was an error while loading. Please reload this page.