Make hash and checkpoint ID type parameters associated types of `ShardStore`

This commit is contained in:
Kris Nuttycombe 2023-05-11 12:04:37 -06:00
parent 666e72482a
commit dbb2a8f9c5
1 changed files with 55 additions and 44 deletions

View File

@ -1,7 +1,6 @@
use bitflags::bitflags; use bitflags::bitflags;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt::{self, Debug}; use core::fmt::{self, Debug};
use core::marker::PhantomData;
use core::ops::{Deref, Range}; use core::ops::{Deref, Range};
use either::Either; use either::Either;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
@ -1417,20 +1416,22 @@ impl Checkpoint {
/// A capability for storage of fragment subtrees of the `ShardTree` type. /// A capability for storage of fragment subtrees of the `ShardTree` type.
/// ///
/// All fragment subtrees must have roots at level `SHARD_HEIGHT - 1` /// All fragment subtrees must have roots at level `SHARD_HEIGHT - 1`
pub trait ShardStore<H, C> { pub trait ShardStore {
type H;
type CheckpointId;
type Error; type Error;
/// Returns the subtree at the given root address, if any such subtree exists. /// Returns the subtree at the given root address, if any such subtree exists.
fn get_shard(&self, shard_root: Address) -> Option<&LocatedPrunableTree<H>>; fn get_shard(&self, shard_root: Address) -> Option<&LocatedPrunableTree<Self::H>>;
/// Returns the subtree containing the maximum inserted leaf position. /// Returns the subtree containing the maximum inserted leaf position.
fn last_shard(&self) -> Option<&LocatedPrunableTree<H>>; fn last_shard(&self) -> Option<&LocatedPrunableTree<Self::H>>;
/// Inserts or replaces the subtree having the same root address as the provided tree. /// Inserts or replaces the subtree having the same root address as the provided tree.
/// ///
/// Implementations of this method MUST enforce the constraint that the root address /// Implementations of this method MUST enforce the constraint that the root address
/// of the provided subtree has level `SHARD_HEIGHT - 1`. /// of the provided subtree has level `SHARD_HEIGHT - 1`.
fn put_shard(&mut self, subtree: LocatedPrunableTree<H>) -> Result<(), Self::Error>; fn put_shard(&mut self, subtree: LocatedPrunableTree<Self::H>) -> Result<(), Self::Error>;
/// Returns the vector of addresses corresponding to the roots of subtrees stored in this /// Returns the vector of addresses corresponding to the roots of subtrees stored in this
/// store. /// store.
@ -1450,15 +1451,15 @@ pub trait ShardStore<H, C> {
// cap_cache: Tree<Option<Rc<H>>, ()> // cap_cache: Tree<Option<Rc<H>>, ()>
/// Returns the identifier for the checkpoint with the lowest associated position value. /// Returns the identifier for the checkpoint with the lowest associated position value.
fn min_checkpoint_id(&self) -> Option<&C>; fn min_checkpoint_id(&self) -> Option<&Self::CheckpointId>;
/// Returns the identifier for the checkpoint with the highest associated position value. /// Returns the identifier for the checkpoint with the highest associated position value.
fn max_checkpoint_id(&self) -> Option<&C>; fn max_checkpoint_id(&self) -> Option<&Self::CheckpointId>;
/// Adds a checkpoint to the data store. /// Adds a checkpoint to the data store.
fn add_checkpoint( fn add_checkpoint(
&mut self, &mut self,
checkpoint_id: C, checkpoint_id: Self::CheckpointId,
checkpoint: Checkpoint, checkpoint: Checkpoint,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
@ -1468,13 +1469,16 @@ pub trait ShardStore<H, C> {
/// Returns the position of the checkpoint, if any, along with the number of subsequent /// Returns the position of the checkpoint, if any, along with the number of subsequent
/// checkpoints at the same position. Returns `None` if `checkpoint_depth == 0` or if /// checkpoints at the same position. Returns `None` if `checkpoint_depth == 0` or if
/// insufficient checkpoints exist to seek back to the requested depth. /// insufficient checkpoints exist to seek back to the requested depth.
fn get_checkpoint_at_depth(&self, checkpoint_depth: usize) -> Option<(&C, &Checkpoint)>; fn get_checkpoint_at_depth(
&self,
checkpoint_depth: usize,
) -> Option<(&Self::CheckpointId, &Checkpoint)>;
/// Iterates in checkpoint ID order over the first `limit` checkpoints, applying the /// Iterates in checkpoint ID order over the first `limit` checkpoints, applying the
/// given callback to each. /// given callback to each.
fn with_checkpoints<F>(&mut self, limit: usize, callback: F) -> Result<(), Self::Error> fn with_checkpoints<F>(&mut self, limit: usize, callback: F) -> Result<(), Self::Error>
where where
F: FnMut(&C, &Checkpoint) -> Result<(), Self::Error>; F: FnMut(&Self::CheckpointId, &Checkpoint) -> Result<(), Self::Error>;
/// Update the checkpoint having the given identifier by mutating it with the provided /// Update the checkpoint having the given identifier by mutating it with the provided
/// function, and persist the updated checkpoint to the data store. /// function, and persist the updated checkpoint to the data store.
@ -1483,31 +1487,36 @@ pub trait ShardStore<H, C> {
/// provided identifier exists in the data store, or an error if a storage error occurred. /// provided identifier exists in the data store, or an error if a storage error occurred.
fn update_checkpoint_with<F>( fn update_checkpoint_with<F>(
&mut self, &mut self,
checkpoint_id: &C, checkpoint_id: &Self::CheckpointId,
update: F, update: F,
) -> Result<bool, Self::Error> ) -> Result<bool, Self::Error>
where where
F: Fn(&mut Checkpoint) -> Result<(), Self::Error>; F: Fn(&mut Checkpoint) -> Result<(), Self::Error>;
/// Removes a checkpoint from the data store. /// Removes a checkpoint from the data store.
fn remove_checkpoint(&mut self, checkpoint_id: &C) -> Result<(), Self::Error>; fn remove_checkpoint(&mut self, checkpoint_id: &Self::CheckpointId) -> Result<(), Self::Error>;
/// Removes checkpoints with identifiers greater than or equal to the given identifier /// Removes checkpoints with identifiers greater than or equal to the given identifier
fn truncate_checkpoints(&mut self, checkpoint_id: &C) -> Result<(), Self::Error>; fn truncate_checkpoints(
&mut self,
checkpoint_id: &Self::CheckpointId,
) -> Result<(), Self::Error>;
} }
impl<H, C, S: ShardStore<H, C>> ShardStore<H, C> for &mut S { impl<S: ShardStore> ShardStore for &mut S {
type H = S::H;
type CheckpointId = S::CheckpointId;
type Error = S::Error; type Error = S::Error;
fn get_shard(&self, shard_root: Address) -> Option<&LocatedPrunableTree<H>> { fn get_shard(&self, shard_root: Address) -> Option<&LocatedPrunableTree<Self::H>> {
S::get_shard(*self, shard_root) S::get_shard(*self, shard_root)
} }
fn last_shard(&self) -> Option<&LocatedPrunableTree<H>> { fn last_shard(&self) -> Option<&LocatedPrunableTree<Self::H>> {
S::last_shard(*self) S::last_shard(*self)
} }
fn put_shard(&mut self, subtree: LocatedPrunableTree<H>) -> Result<(), Self::Error> { fn put_shard(&mut self, subtree: LocatedPrunableTree<Self::H>) -> Result<(), Self::Error> {
S::put_shard(*self, subtree) S::put_shard(*self, subtree)
} }
@ -1519,17 +1528,17 @@ impl<H, C, S: ShardStore<H, C>> ShardStore<H, C> for &mut S {
S::truncate(*self, from) S::truncate(*self, from)
} }
fn min_checkpoint_id(&self) -> Option<&C> { fn min_checkpoint_id(&self) -> Option<&Self::CheckpointId> {
S::min_checkpoint_id(self) S::min_checkpoint_id(self)
} }
fn max_checkpoint_id(&self) -> Option<&C> { fn max_checkpoint_id(&self) -> Option<&Self::CheckpointId> {
S::max_checkpoint_id(self) S::max_checkpoint_id(self)
} }
fn add_checkpoint( fn add_checkpoint(
&mut self, &mut self,
checkpoint_id: C, checkpoint_id: Self::CheckpointId,
checkpoint: Checkpoint, checkpoint: Checkpoint,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
S::add_checkpoint(self, checkpoint_id, checkpoint) S::add_checkpoint(self, checkpoint_id, checkpoint)
@ -1539,20 +1548,23 @@ impl<H, C, S: ShardStore<H, C>> ShardStore<H, C> for &mut S {
S::checkpoint_count(self) S::checkpoint_count(self)
} }
fn get_checkpoint_at_depth(&self, checkpoint_depth: usize) -> Option<(&C, &Checkpoint)> { fn get_checkpoint_at_depth(
&self,
checkpoint_depth: usize,
) -> Option<(&Self::CheckpointId, &Checkpoint)> {
S::get_checkpoint_at_depth(self, checkpoint_depth) S::get_checkpoint_at_depth(self, checkpoint_depth)
} }
fn with_checkpoints<F>(&mut self, limit: usize, callback: F) -> Result<(), Self::Error> fn with_checkpoints<F>(&mut self, limit: usize, callback: F) -> Result<(), Self::Error>
where where
F: FnMut(&C, &Checkpoint) -> Result<(), Self::Error>, F: FnMut(&Self::CheckpointId, &Checkpoint) -> Result<(), Self::Error>,
{ {
S::with_checkpoints(self, limit, callback) S::with_checkpoints(self, limit, callback)
} }
fn update_checkpoint_with<F>( fn update_checkpoint_with<F>(
&mut self, &mut self,
checkpoint_id: &C, checkpoint_id: &Self::CheckpointId,
update: F, update: F,
) -> Result<bool, Self::Error> ) -> Result<bool, Self::Error>
where where
@ -1561,11 +1573,14 @@ impl<H, C, S: ShardStore<H, C>> ShardStore<H, C> for &mut S {
S::update_checkpoint_with(self, checkpoint_id, update) S::update_checkpoint_with(self, checkpoint_id, update)
} }
fn remove_checkpoint(&mut self, checkpoint_id: &C) -> Result<(), Self::Error> { fn remove_checkpoint(&mut self, checkpoint_id: &Self::CheckpointId) -> Result<(), Self::Error> {
S::remove_checkpoint(self, checkpoint_id) S::remove_checkpoint(self, checkpoint_id)
} }
fn truncate_checkpoints(&mut self, checkpoint_id: &C) -> Result<(), Self::Error> { fn truncate_checkpoints(
&mut self,
checkpoint_id: &Self::CheckpointId,
) -> Result<(), Self::Error> {
S::truncate_checkpoints(self, checkpoint_id) S::truncate_checkpoints(self, checkpoint_id)
} }
} }
@ -1585,7 +1600,9 @@ impl<H, C: Ord> MemoryShardStore<H, C> {
} }
} }
impl<H, C: Ord> ShardStore<H, C> for MemoryShardStore<H, C> { impl<H, C: Ord> ShardStore for MemoryShardStore<H, C> {
type H = H;
type CheckpointId = C;
type Error = InsertionError; type Error = InsertionError;
fn get_shard(&self, shard_root: Address) -> Option<&LocatedPrunableTree<H>> { fn get_shard(&self, shard_root: Address) -> Option<&LocatedPrunableTree<H>> {
@ -1699,22 +1716,20 @@ impl<H, C: Ord> ShardStore<H, C> for MemoryShardStore<H, C> {
/// front of the tree, that are maintained such that it's possible to truncate nodes to the right /// front of the tree, that are maintained such that it's possible to truncate nodes to the right
/// of the specified position. /// of the specified position.
#[derive(Debug)] #[derive(Debug)]
pub struct ShardTree<H, C, S: ShardStore<H, C>, const DEPTH: u8, const SHARD_HEIGHT: u8> { pub struct ShardTree<S: ShardStore, const DEPTH: u8, const SHARD_HEIGHT: u8> {
/// The vector of tree shards. /// The vector of tree shards.
store: S, store: S,
/// The maximum number of checkpoints to retain before pruning. /// The maximum number of checkpoints to retain before pruning.
max_checkpoints: usize, max_checkpoints: usize,
_hash_type: PhantomData<H>,
_checkpoint_id_type: PhantomData<C>,
} }
impl< impl<
H: Hashable + Clone + PartialEq, H: Hashable + Clone + PartialEq,
C: Clone + Ord, C: Clone + Ord,
S: ShardStore<H, C>, S: ShardStore<H = H, CheckpointId = C>,
const DEPTH: u8, const DEPTH: u8,
const SHARD_HEIGHT: u8, const SHARD_HEIGHT: u8,
> ShardTree<H, C, S, DEPTH, SHARD_HEIGHT> > ShardTree<S, DEPTH, SHARD_HEIGHT>
{ {
/// Creates a new empty tree and establishes a checkpoint for the empty tree at the given /// Creates a new empty tree and establishes a checkpoint for the empty tree at the given
/// checkpoint identifier. /// checkpoint identifier.
@ -1726,8 +1741,6 @@ impl<
let mut result = Self { let mut result = Self {
store, store,
max_checkpoints, max_checkpoints,
_hash_type: PhantomData,
_checkpoint_id_type: PhantomData,
}; };
result result
.store .store
@ -1740,8 +1753,6 @@ impl<
Self { Self {
store, store,
max_checkpoints, max_checkpoints,
_hash_type: PhantomData,
_checkpoint_id_type: PhantomData,
} }
} }
@ -2770,7 +2781,7 @@ mod tests {
#[test] #[test]
fn shardtree_insertion() { fn shardtree_insertion() {
let mut tree: ShardTree<String, usize, MemoryShardStore<String, usize>, 4, 3> = let mut tree: ShardTree<MemoryShardStore<String, usize>, 4, 3> =
ShardTree::empty(MemoryShardStore::empty(), 100, 0).unwrap(); ShardTree::empty(MemoryShardStore::empty(), 100, 0).unwrap();
assert_matches!( assert_matches!(
tree.batch_insert( tree.batch_insert(
@ -2862,10 +2873,10 @@ mod tests {
impl< impl<
H: Hashable + Ord + Clone, H: Hashable + Ord + Clone,
C: Clone + Ord + core::fmt::Debug, C: Clone + Ord + core::fmt::Debug,
S: ShardStore<H, C>, S: ShardStore<H = H, CheckpointId = C>,
const DEPTH: u8, const DEPTH: u8,
const SHARD_HEIGHT: u8, const SHARD_HEIGHT: u8,
> testing::Tree<H, C> for ShardTree<H, C, S, DEPTH, SHARD_HEIGHT> > testing::Tree<H, C> for ShardTree<S, DEPTH, SHARD_HEIGHT>
where where
S::Error: core::fmt::Debug + From<InsertionError>, S::Error: core::fmt::Debug + From<InsertionError>,
{ {
@ -2919,7 +2930,7 @@ mod tests {
#[test] #[test]
fn append() { fn append() {
check_append(|m| { check_append(|m| {
ShardTree::<String, usize, MemoryShardStore<String, usize>, 4, 3>::empty( ShardTree::<MemoryShardStore<String, usize>, 4, 3>::empty(
MemoryShardStore::empty(), MemoryShardStore::empty(),
m, m,
0, 0,
@ -2931,7 +2942,7 @@ mod tests {
#[test] #[test]
fn root_hashes() { fn root_hashes() {
check_root_hashes(|m| { check_root_hashes(|m| {
ShardTree::<String, usize, MemoryShardStore<String, usize>, 4, 3>::empty( ShardTree::<MemoryShardStore<String, usize>, 4, 3>::empty(
MemoryShardStore::empty(), MemoryShardStore::empty(),
m, m,
0, 0,
@ -2943,7 +2954,7 @@ mod tests {
#[test] #[test]
fn witnesses() { fn witnesses() {
check_witnesses(|m| { check_witnesses(|m| {
ShardTree::<String, usize, MemoryShardStore<String, usize>, 4, 3>::empty( ShardTree::<MemoryShardStore<String, usize>, 4, 3>::empty(
MemoryShardStore::empty(), MemoryShardStore::empty(),
m, m,
0, 0,
@ -2955,7 +2966,7 @@ mod tests {
#[test] #[test]
fn checkpoint_rewind() { fn checkpoint_rewind() {
check_checkpoint_rewind(|m| { check_checkpoint_rewind(|m| {
ShardTree::<String, usize, MemoryShardStore<String, usize>, 4, 3>::empty( ShardTree::<MemoryShardStore<String, usize>, 4, 3>::empty(
MemoryShardStore::empty(), MemoryShardStore::empty(),
m, m,
0, 0,
@ -2967,7 +2978,7 @@ mod tests {
#[test] #[test]
fn rewind_remove_mark() { fn rewind_remove_mark() {
check_rewind_remove_mark(|m| { check_rewind_remove_mark(|m| {
ShardTree::<String, usize, MemoryShardStore<String, usize>, 4, 3>::empty( ShardTree::<MemoryShardStore<String, usize>, 4, 3>::empty(
MemoryShardStore::empty(), MemoryShardStore::empty(),
m, m,
0, 0,
@ -2984,7 +2995,7 @@ mod tests {
H, H,
usize, usize,
CompleteTree<H, usize, 4>, CompleteTree<H, usize, 4>,
ShardTree<H, usize, MemoryShardStore<H, usize>, 4, 3>, ShardTree<MemoryShardStore<H, usize>, 4, 3>,
> { > {
CombinedTree::new( CombinedTree::new(
CompleteTree::new(max_checkpoints, 0), CompleteTree::new(max_checkpoints, 0),