Skip to content

Commit c0787d1

Browse files
committed
fix(base): Check the lazy_previous of the first chunk matches the new first chunk.
This patch adds a new check when inserting a new first chunk. It makes some tests to fail but because they were not realistic. This patch then updates these tests.
1 parent 914b712 commit c0787d1

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

crates/matrix-sdk-base/src/event_cache/store/integration_tests.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
459459
// A unique chunk.
460460
assert_matches!(rchunks.next(), Some(chunk) => {
461461
assert_eq!(chunk.identifier(), 2);
462+
assert_eq!(chunk.lazy_previous(), Some(CId::new(1)));
462463

463464
assert_matches!(chunk.content(), ChunkContent::Items(events) => {
464465
assert_eq!(events.len(), 3);
@@ -476,19 +477,17 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
476477
// Load the previous chunk: this is a gap.
477478
{
478479
let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
479-
let mut previous_chunk =
480+
let previous_chunk =
480481
self.load_previous_chunk(room_id, first_chunk).await.unwrap().unwrap();
481482

482-
// Pretend it's the first chunk.
483-
previous_chunk.previous = None;
484-
485483
let _ = lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
486484

487485
let mut rchunks = linked_chunk.rchunks();
488486

489487
// The last chunk.
490488
assert_matches!(rchunks.next(), Some(chunk) => {
491489
assert_eq!(chunk.identifier(), 2);
490+
assert!(chunk.lazy_previous().is_none());
492491

493492
// Already asserted, but let's be sure nothing breaks.
494493
assert_matches!(chunk.content(), ChunkContent::Items(events) => {
@@ -502,6 +501,7 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
502501
// The new chunk.
503502
assert_matches!(rchunks.next(), Some(chunk) => {
504503
assert_eq!(chunk.identifier(), 1);
504+
assert_eq!(chunk.lazy_previous(), Some(CId::new(0)));
505505

506506
assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
507507
assert_eq!(gap.prev_token, "morbier");
@@ -524,6 +524,7 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
524524
// The last chunk.
525525
assert_matches!(rchunks.next(), Some(chunk) => {
526526
assert_eq!(chunk.identifier(), 2);
527+
assert!(chunk.lazy_previous().is_none());
527528

528529
// Already asserted, but let's be sure nothing breaks.
529530
assert_matches!(chunk.content(), ChunkContent::Items(events) => {
@@ -537,6 +538,7 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
537538
// Its previous chunk.
538539
assert_matches!(rchunks.next(), Some(chunk) => {
539540
assert_eq!(chunk.identifier(), 1);
541+
assert!(chunk.lazy_previous().is_none());
540542

541543
// Already asserted, but let's be sure nothing breaks.
542544
assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
@@ -547,6 +549,7 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
547549
// The new chunk.
548550
assert_matches!(rchunks.next(), Some(chunk) => {
549551
assert_eq!(chunk.identifier(), 0);
552+
assert!(chunk.lazy_previous().is_none());
550553

551554
assert_matches!(chunk.content(), ChunkContent::Items(events) => {
552555
assert_eq!(events.len(), 2);
@@ -574,6 +577,7 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
574577
// The first chunk.
575578
assert_matches!(chunks.next(), Some(chunk) => {
576579
assert_eq!(chunk.identifier(), 0);
580+
assert!(chunk.lazy_previous().is_none());
577581

578582
assert_matches!(chunk.content(), ChunkContent::Items(events) => {
579583
assert_eq!(events.len(), 2);
@@ -585,6 +589,7 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
585589
// The second chunk.
586590
assert_matches!(chunks.next(), Some(chunk) => {
587591
assert_eq!(chunk.identifier(), 1);
592+
assert!(chunk.lazy_previous().is_none());
588593

589594
assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
590595
assert_eq!(gap.prev_token, "morbier");
@@ -594,6 +599,7 @@ impl EventCacheStoreIntegrationTests for DynEventCacheStore {
594599
// The third and last chunk.
595600
assert_matches!(chunks.next(), Some(chunk) => {
596601
assert_eq!(chunk.identifier(), 2);
602+
assert!(chunk.lazy_previous().is_none());
597603

598604
assert_matches!(chunk.content(), ChunkContent::Items(events) => {
599605
assert_eq!(events.len(), 3);

crates/matrix-sdk-common/src/linked_chunk/lazy_loader.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ where
9696
}
9797
}
9898

99-
let expected_next_chunk = linked_chunk.links.first_chunk().identifier();
99+
let first_chunk = linked_chunk.links.first_chunk();
100+
let expected_next_chunk = first_chunk.identifier();
100101

101102
// New chunk has a next chunk.
102103
let Some(next_chunk) = new_first_chunk.next else {
@@ -111,15 +112,25 @@ where
111112
});
112113
}
113114

115+
// Same check as before, but in reverse: the first chunk has a `lazy_previous`
116+
// to the new first chunk.
117+
if first_chunk.lazy_previous() != Some(new_first_chunk.identifier) {
118+
return Err(LazyLoaderError::CannotConnectTwoChunks {
119+
new_chunk: first_chunk.identifier,
120+
with_chunk: new_first_chunk.identifier,
121+
});
122+
}
123+
114124
// Alright. All checks are made.
115125
}
116126

117127
// Insert the new first chunk.
118128
{
119129
// Transform the `RawChunk` into a `Chunk`.
120130
let lazy_previous = new_first_chunk.previous.take();
131+
let new_first_chunk_identifier = new_first_chunk.identifier;
121132
let mut new_first_chunk =
122-
Chunk::new_leaked(new_first_chunk.identifier, new_first_chunk.content);
133+
Chunk::new_leaked(new_first_chunk_identifier, new_first_chunk.content);
123134

124135
let links = &mut linked_chunk.links;
125136

@@ -524,6 +535,26 @@ mod tests {
524535
});
525536
}
526537

538+
#[test]
539+
fn test_insert_new_first_chunk_err_cannot_connect_two_chunks_before_no_lazy_previous() {
540+
let new_first_chunk = RawChunk {
541+
previous: None,
542+
identifier: ChunkIdentifier::new(1),
543+
next: Some(ChunkIdentifier::new(0)),
544+
content: ChunkContent::Gap(()),
545+
};
546+
547+
let mut linked_chunk = LinkedChunk::<2, char, ()>::new();
548+
linked_chunk.push_gap_back(());
549+
550+
let result = insert_new_first_chunk(&mut linked_chunk, new_first_chunk);
551+
552+
assert_matches!(result, Err(LazyLoaderError::CannotConnectTwoChunks { new_chunk, with_chunk }) => {
553+
assert_eq!(new_chunk, 0);
554+
assert_eq!(with_chunk, 1);
555+
});
556+
}
557+
527558
#[test]
528559
fn test_insert_new_first_chunk_gap() {
529560
let new_first_chunk = RawChunk {
@@ -535,6 +566,7 @@ mod tests {
535566

536567
let mut linked_chunk = LinkedChunk::<5, char, ()>::new_with_update_history();
537568
linked_chunk.push_items_back(vec!['a', 'b']);
569+
linked_chunk.links.first_chunk_mut().lazy_previous = Some(ChunkIdentifier::new(1));
538570

539571
// Drain initial updates.
540572
let _ = linked_chunk.updates().unwrap().take();
@@ -593,6 +625,7 @@ mod tests {
593625

594626
let mut linked_chunk = LinkedChunk::<5, char, ()>::new_with_update_history();
595627
linked_chunk.push_items_back(vec!['a', 'b']);
628+
linked_chunk.links.first_chunk_mut().lazy_previous = Some(ChunkIdentifier::new(1));
596629

597630
// Drain initial updates.
598631
let _ = linked_chunk.updates().unwrap().take();

0 commit comments

Comments
 (0)