Fix timeline beacon info replacement path#6596
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #6596 +/- ##
==========================================
+ Coverage 89.94% 89.97% +0.02%
==========================================
Files 382 382
Lines 108012 108107 +95
Branches 108012 108107 +95
==========================================
+ Hits 97152 97267 +115
+ Misses 7188 7171 -17
+ Partials 3672 3669 -3 ☔ View full report in Codecov by Harness. |
andybalaam
left a comment
There was a problem hiding this comment.
Thank you for working on this! I am not very familiar with this code, so it took me a long time to work out what it was doing. It would help me if it used smaller commits, and gave more detail in the commit descriptions. E.g.:
- Make TimelineEventHandler hold TimelineEventContext as a reference
- Return a Vec from TimelineAction::from_event so that (later) we can return multiple actions to stop and start beacons
- Hold own_id inside BeaconStop so that ... SOMETHING? ...
- Simplify TimelineEventHandler::handle_event by factoring out methods
- Stop an existing live beacon if we receive a new one
I also have 3 more general questions:
-
With this implementation does the stop item appear in the timeline below the new one? Is that OK, or should it appear above?
-
Are we certain of the order in which we receive these two beacon events? Could some clients see them in different orders?
-
(Probably for @poljar): do we think that adding 2 timeline items for a single beacon, simulating a stop of the old one, and the creation of the new one? I.e. is the timeline the right place to do this? Or e.g. should the underlying code simply understand a new beacon as implicitly meaning the old one is stopped?
| let has_add_item = | ||
| timeline_actions.iter().any(|action| matches!(action, TimelineAction::AddItem { .. })); | ||
| let should_add_new_items = has_add_item | ||
| && matches!(position, TimelineItemPosition::UpdateAt { .. }) |
There was a problem hiding this comment.
Why is there a repeat of matches! here and the next line?
There was a problem hiding this comment.
Not sure to follow the question, this is not the same match?
There was a problem hiding this comment.
There are 2 lines that do:
&& matches!(position, TimelineItemPosition::UpdateAt { .. })
so I think the first one is useless - it is just the same as the second one, but without the trailing if.
There was a problem hiding this comment.
Ah yes sorry, I might have messed up with git
| // working from `handle_remote_aggregations()`. | ||
| let has_add_item = | ||
| timeline_actions.iter().any(|action| matches!(action, TimelineAction::AddItem { .. })); | ||
| let should_add_new_items = has_add_item |
There was a problem hiding this comment.
Can you add a comment explaining what this does please?
There was a problem hiding this comment.
Something like (please correct if wrong): "If we are adding an item at a position that currently contains a UTD, we should add new items."
| == 1; | ||
|
|
||
| if recycled_timeline_id.is_some() && !can_recycle_timeline_id { | ||
| warn!("Multiple TimelineAction::AddItem detected, can't recycle timeline id"); |
There was a problem hiding this comment.
This doesn't seem like a warning to me. Isn't it quite normal?
There was a problem hiding this comment.
Honestly I'm not sure about this recycled_timeline_id thing, I'd need eye from rust expert
There was a problem hiding this comment.
Yeah, this would happen every time a beacon is received, so a trace!() or at best debug!() call should be fine.
| None | ||
| } | ||
| }; | ||
| item_added |= TimelineEventHandler::new(self, &ctx) |
There was a problem hiding this comment.
I don't think it exists? But I might be wrong
There was a problem hiding this comment.
Yeah you're right, but |= is bitwise OR, which is not right, so you should do
item_added = TimelineEventHandler::new(self, &ctx) || item_added
(note the order, so that the ::new always gets called, even if item_added is true.
| }, | ||
| should_add_new_items: should_add, | ||
| }; | ||
| let can_recycle_timeline_id = timeline_actions |
There was a problem hiding this comment.
So we only recycle the ID when there is exactly 1 add. Why can't we recycle it for the first add, even if there are more?
There was a problem hiding this comment.
@poljar do you have an idea how to manage this properly? For now we are not getting more than one TimelineAction::AddItem
There was a problem hiding this comment.
That's probably correct, turning off the beacon should be able to reuse the ID, while the addition of the new beacon should create a new one.
Though I don't think it's worth the complexity and it would really special case the logic for the beacon updates.
Perhaps we can simplify this even further instead, to disallow the recycling as soon as there's multiple actions:
let recycled_timeline_id = recycled_timeline_id.take_if(timeline_actions.len() == 1);There was a problem hiding this comment.
We should also extensively comment on why we're doing this.
| Ok(None) | ||
| } | ||
| [_, _, ..] => { | ||
| warn!("Multiple actions for an embedded event"); |
There was a problem hiding this comment.
So for this first commit, we never actually return >1 action, right?
There was a problem hiding this comment.
If we should never get to this code, it would be good to explain why in a comment here.
|
|
||
| let timeline_action = TimelineAction::from_content(content, in_reply_to, thread_root, None); | ||
| TimelineEventHandler::new(&mut txn, ctx) | ||
| TimelineEventHandler::new(&mut txn, &ctx) |
There was a problem hiding this comment.
Changing this to a reference would have made a very nice, small, understandable separate commit.
| } | ||
|
|
||
| /// A new live `beacon_info` replacing a previous live session should implicitly | ||
| /// stop the previous timeline item, even if no explicit stop event was sent. |
There was a problem hiding this comment.
This test description would make a good commit message. I find it much easier to understand than the current commit message.
| ); | ||
| Self::HandleAggregation { | ||
| related_event: ev.event_id.clone(), | ||
| kind: HandleAggregationKind::BeaconStop { |
There was a problem hiding this comment.
Will this stop the previous beacon even if it was already stopped?
There was a problem hiding this comment.
Thats a good point, I guess it'll try but won't find a live version matching
There was a problem hiding this comment.
I don't think we should add a stop timeline item every time: we should check whether there is a live beacon and only add a stop timeline item if so.
There was a problem hiding this comment.
The code here is not adding a stop item, it's mutating another item. If the item is not found then it does nothing.
| } | ||
| }); | ||
| let mut actions = vec![add_item_action]; | ||
| actions.extend(handle_aggregation_action); |
There was a problem hiding this comment.
Does this add a None to actions if the beacon has no prev_content?
There was a problem hiding this comment.
I don't think so, AFAIK it should just ignore the None
There was a problem hiding this comment.
What should ignore the None? This line of code will certainly add an None if handle_aggregation_action is None.
There was a problem hiding this comment.
The Option is passed as an Iterator and should ignore None if I'm not mistaken
There was a problem hiding this comment.
Ah, I missed that you were using extend - sorry, you're right.
|
Thanks for the initial review. The PR was created for further discussion, especially with @poljar as we initially started to talk about this in the Live Location Sharing room.
So this code won't add a new stop item by itself, it'll only makes sure the previous live is correctly seen as stop when loaded. If the previous live is not loaded, it will just store the aggregation in memory waiting for the prev event to be loaded. My response should probably answer your other questions too ^ |
poljar
left a comment
There was a problem hiding this comment.
I think @andybalaam raised some great questions and suggestions.
Beside his remarks, what furthermore worries me is that no test has raised a fuss on the |= mistake on the item_added update logic.
Regarding |
b14e40f to
a5e515c
Compare
|
@poljar I've addressed most of the remarks I think. I'll rewrite the history if you prefer, but when the PR will be ready to be approved. On the UTD hack thing, I'm wondering if it's still necessary, as the linked issue seems closed. |
Right, I latched on to the conclusion in this thread, which indeed is wrong.
Feel free to rewrite the history now.
There are tests for this so we can try to remove the hack, though I'm not sure if that'll work as we still need to filter out all of the |
poljar
left a comment
There was a problem hiding this comment.
I think this is fine now.
Could you just handle the lint issue. Either add a clippy exception, or even better add a struct for the a function arguments.
This updates the timeline action flow to support multi-action event handling and fixes the m.beacon_info replacement path.
Replacing a live m.beacon_info session now correctly adds the new timeline item while marking the previous one as stopped.
Fix https://github.com/element-hq/element-internal/issues/714
(see Writing changelog entries).
Signed-off-by: