Skip to content

Commit

Permalink
task(linked chunk): make error reporting deterministic in `LinkedChun…
Browse files Browse the repository at this point in the history
…kBuilder::build`

By using a deterministic iteration ordering.
  • Loading branch information
bnjbvr committed Nov 25, 2024
1 parent 8d52402 commit 68ffe87
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 29 deletions.
37 changes: 9 additions & 28 deletions crates/matrix-sdk-common/src/linked_chunk/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{collections::HashMap, marker::PhantomData, ptr::NonNull};
use std::{collections::BTreeMap, marker::PhantomData, ptr::NonNull};

use super::{
Chunk, ChunkContent, ChunkIdentifier, ChunkIdentifierGenerator, Ends, LinkedChunk,
Expand All @@ -37,7 +37,7 @@ struct TemporaryChunk<Item, Gap> {
#[allow(missing_debug_implementations)]
pub struct LinkedChunkBuilder<const CAP: usize, Item, Gap> {
/// Work-in-progress chunks.
chunks: HashMap<ChunkIdentifier, TemporaryChunk<Item, Gap>>,
chunks: BTreeMap<ChunkIdentifier, TemporaryChunk<Item, Gap>>,

/// Is the final `LinkedChunk` expected to be observable, as if it were
/// created with [`LinkedChunk::new_with_update_history`]?
Expand Down Expand Up @@ -214,8 +214,8 @@ impl<const CAP: usize, Item, Gap> LinkedChunkBuilder<CAP, Item, Gap> {
return Err(LinkedChunkBuilderError::MultipleConnectedComponents { chunks: remaining });
}

// SAFETY: if this unwrap fails, it means we had no chunks in the stash, so we
// should have returned early.
// SAFETY: if one of these unwrap fails, it means we had no chunks in the stash,
// so we should have returned early.
let first = first_chunk_ptr.unwrap();
let last = prev_chunk_ptr.unwrap();
let links = Ends { first, last: Some(last) };
Expand Down Expand Up @@ -389,11 +389,7 @@ mod tests {

let err = lcb.build().unwrap_err();
assert_matches!(err, LinkedChunkBuilderError::Cycle { path } => {
assert_eq!(path.len(), 3);
// Order is not guaranteed.
assert!(path.contains(&cid0));
assert!(path.contains(&cid1));
assert!(path.contains(&cid2));
assert_eq!(path, vec![cid0, cid2, cid1]);
});
}

Expand All @@ -413,15 +409,7 @@ mod tests {

let err = lcb.build().unwrap_err();
assert_matches!(err, LinkedChunkBuilderError::MultipleConnectedComponents { chunks } => {
// Order of iteration is not guaranteed, so the error either tells that cid0 and cid1
// are an isolated component, or that cid2 is.
if chunks.len() == 1 {
assert_eq!(chunks, [cid2]);
} else {
assert_eq!(chunks.len(), 2);
assert!(chunks.contains(&cid0));
assert!(chunks.contains(&cid1));
}
assert_eq!(chunks, [cid2]);
});
}

Expand All @@ -443,16 +431,9 @@ mod tests {
assert_matches!(err, LinkedChunkBuilderError::InconsistentLinks {
chunk, declared_prev, actual_prev
} => {
// Since the order of traversal is undefined, the target chunk may be cid0 or cid1.
// Let's account for both.
if chunk == cid0 {
assert!(declared_prev.is_none());
assert_eq!(actual_prev, Some(cid1));
} else {
assert_eq!(chunk, cid1);
assert!(declared_prev.is_none());
assert_eq!(actual_prev, Some(cid0));
}
assert_eq!(chunk, cid1);
assert!(declared_prev.is_none());
assert_eq!(actual_prev, Some(cid0));
});
}
}
2 changes: 1 addition & 1 deletion crates/matrix-sdk-common/src/linked_chunk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ impl ChunkIdentifierGenerator {
/// It is not the position of the chunk, just its unique identifier.
///
/// Learn more with [`ChunkIdentifierGenerator`].
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct ChunkIdentifier(u64);

Expand Down

0 comments on commit 68ffe87

Please sign in to comment.