refactor(event cache): add a way to know if we deduplicated all events (at least one)

This commit is contained in:
Benjamin Bouvier
2024-12-17 16:15:11 +01:00
parent d89194f071
commit 3f0712010f
2 changed files with 60 additions and 17 deletions

View File

@@ -185,7 +185,7 @@ impl RoomPagination {
let first_event_pos = room_events.events().next().map(|(item_pos, _)| item_pos);
// First, insert events.
let insert_new_gap_pos = if let Some(gap_id) = prev_gap_id {
let (add_event_report, insert_new_gap_pos) = if let Some(gap_id) = prev_gap_id {
// There is a prior gap, let's replace it by new events!
trace!("replaced gap with new events from backpagination");
room_events
@@ -195,16 +195,17 @@ impl RoomPagination {
// No prior gap, but we had some events: assume we need to prepend events
// before those.
trace!("inserted events before the first known event");
room_events
let report = room_events
.insert_events_at(sync_events, pos)
.expect("pos is a valid position we just read above");
Some(pos)
(report, Some(pos))
} else {
// No prior gap, and no prior events: push the events.
trace!("pushing events received from back-pagination");
room_events.push_events(sync_events);
let report = room_events.push_events(sync_events);
// A new gap may be inserted before the new events, if there are any.
room_events.events().next().map(|(item_pos, _)| item_pos)
let next_pos = room_events.events().next().map(|(item_pos, _)| item_pos);
(report, next_pos)
};
// And insert the new gap if needs be.

View File

@@ -95,13 +95,18 @@ impl RoomEvents {
/// Push events after all events or gaps.
///
/// The last event in `events` is the most recent one.
pub fn push_events<I>(&mut self, events: I)
pub fn push_events<I>(&mut self, events: I) -> AddEventReport
where
I: IntoIterator<Item = Event>,
{
let (unique_events, duplicated_event_ids) =
self.filter_duplicated_events(events.into_iter());
let report = AddEventReport {
num_new_unique: unique_events.len(),
num_duplicated: duplicated_event_ids.len(),
};
// Remove the _old_ duplicated events!
//
// We don't have to worry the removals can change the position of the existing
@@ -110,6 +115,8 @@ impl RoomEvents {
// Push new `events`.
self.chunks.push_items_back(unique_events);
report
}
/// Push a gap after all events or gaps.
@@ -118,13 +125,22 @@ impl RoomEvents {
}
/// Insert events at a specified position.
pub fn insert_events_at<I>(&mut self, events: I, mut position: Position) -> Result<(), Error>
pub fn insert_events_at<I>(
&mut self,
events: I,
mut position: Position,
) -> Result<AddEventReport, Error>
where
I: IntoIterator<Item = Event>,
{
let (unique_events, duplicated_event_ids) =
self.filter_duplicated_events(events.into_iter());
let report = AddEventReport {
num_new_unique: unique_events.len(),
num_duplicated: duplicated_event_ids.len(),
};
// Remove the _old_ duplicated events!
//
// We **have to worry* the removals can change the position of the
@@ -132,7 +148,9 @@ impl RoomEvents {
// argument value for each removal.
self.remove_events_and_update_insert_position(duplicated_event_ids, &mut position);
self.chunks.insert_items_at(unique_events, position)
self.chunks.insert_items_at(unique_events, position)?;
Ok(report)
}
/// Insert a gap at a specified position.
@@ -145,19 +163,24 @@ impl RoomEvents {
/// Because the `gap_identifier` can represent non-gap chunk, this method
/// returns a `Result`.
///
/// This method returns either the position of the first chunk that's been
/// created, or the next insert position if the chunk has been removed.
/// This method returns a reference to the (first if many) newly created
/// `Chunk` that contains the `items`.
pub fn replace_gap_at<I>(
&mut self,
events: I,
gap_identifier: ChunkIdentifier,
) -> Result<Option<Position>, Error>
) -> Result<(AddEventReport, Option<Position>), Error>
where
I: IntoIterator<Item = Event>,
{
let (unique_events, duplicated_event_ids) =
self.filter_duplicated_events(events.into_iter());
let report = AddEventReport {
num_new_unique: unique_events.len(),
num_duplicated: duplicated_event_ids.len(),
};
// Remove the _old_ duplicated events!
//
// We don't have to worry the removals can change the position of the existing
@@ -165,14 +188,15 @@ impl RoomEvents {
// because of the removals.
self.remove_events(duplicated_event_ids);
if unique_events.is_empty() {
let next_pos = if unique_events.is_empty() {
// There are no new events, so there's no need to create a new empty items
// chunk; instead, remove the gap.
self.chunks.remove_gap_at(gap_identifier)
self.chunks.remove_gap_at(gap_identifier)?
} else {
// Replace the gap by new events.
Ok(Some(self.chunks.replace_gap_at(unique_events, gap_identifier)?.first_position()))
}
Some(self.chunks.replace_gap_at(unique_events, gap_identifier)?.first_position())
};
Ok((report, next_pos))
}
/// Search for a chunk, and return its identifier.
@@ -398,6 +422,20 @@ impl RoomEvents {
}
}
pub(in crate::event_cache) struct AddEventReport {
/// Number of new unique events that have been added.
num_new_unique: usize,
/// Number of events which have been deduplicated.
num_duplicated: usize,
}
impl AddEventReport {
/// Were all the events (at least one) we added already known?
pub fn deduplicated_all_new_events(&self) -> bool {
self.num_new_unique > 0 && self.num_new_unique == self.num_duplicated
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
@@ -814,8 +852,10 @@ mod tests {
.unwrap();
// The next insert position is the next chunk's start.
let pos = room_events.replace_gap_at([], first_gap_id).unwrap();
let (report, pos) = room_events.replace_gap_at([], first_gap_id).unwrap();
assert_eq!(pos, Some(Position::new(ChunkIdentifier::new(2), 0)));
assert_eq!(report.num_new_unique, 0);
assert_eq!(report.num_duplicated, 0);
// Remove the second gap.
let second_gap_id = room_events
@@ -824,8 +864,10 @@ mod tests {
.unwrap();
// No next insert position.
let pos = room_events.replace_gap_at([], second_gap_id).unwrap();
let (report, pos) = room_events.replace_gap_at([], second_gap_id).unwrap();
assert!(pos.is_none());
assert_eq!(report.num_new_unique, 0);
assert_eq!(report.num_duplicated, 0);
}
#[test]