diff --git a/Cargo.toml b/Cargo.toml index 928c547..b023b99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "orderwal" -version = "0.4.0" +version = "0.4.1" edition = "2021" repository = "https://github.com/al8n/orderwal" homepage = "https://github.com/al8n/orderwal" @@ -29,6 +29,7 @@ tracing = ["dep:tracing", "dbutils/tracing"] among = { version = "0.1", default-features = false, features = ["either"] } bitflags = { version = "1", default-features = false } dbutils = { version = "0.4", default-features = false, features = ["crc32fast"] } +ref-cast = "1" rarena-allocator = { version = "0.4", default-features = false, features = ["memmap"] } crossbeam-skiplist = { version = "0.1", default-features = false, package = "crossbeam-skiplist-pr1132" } paste = "1" diff --git a/examples/generic_not_sized.rs b/examples/generic_not_sized.rs new file mode 100644 index 0000000..f328e4d --- /dev/null +++ b/examples/generic_not_sized.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/examples/zero_cost.rs b/examples/zero_cost.rs index f73d55e..cdefc05 100644 --- a/examples/zero_cost.rs +++ b/examples/zero_cost.rs @@ -154,12 +154,23 @@ fn main() { let people = people.clone(); spawn(move || loop { let (person, hello) = &people[i]; - if let Some(p) = reader.get(&people[i].0) { + let person_ref = PersonRef { + id: person.id, + name: &person.name, + }; + if let Some(p) = reader.get(person) { assert_eq!(p.key().id, person.id); assert_eq!(p.key().name, person.name); assert_eq!(p.value(), hello); break; } + + if let Some(p) = reader.get(&person_ref) { + assert_eq!(p.key().id, person.id); + assert_eq!(p.key().name, person.name); + assert_eq!(p.value(), hello); + break; + }; }) }); diff --git a/src/entry.rs b/src/entry.rs index e5a6b86..65599ef 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,7 +1,10 @@ use core::borrow::Borrow; use crossbeam_skiplist::set::Entry as SetEntry; -use dbutils::traits::{Type, TypeRef}; +use dbutils::{ + equivalent::{Comparable, Equivalent}, + traits::{KeyRef, Type, TypeRef}, +}; use rarena_allocator::either::Either; use super::{ @@ -98,20 +101,20 @@ impl Entry { } /// An entry builder which can build an [`Entry`] to be inserted into the [`Wal`](crate::wal::Wal). -pub struct EntryWithKeyBuilder { +pub struct EntryWithKeyBuilder { pub(crate) kb: KeyBuilder, pub(crate) value: V, - pub(crate) pointer: Option>, + pub(crate) pointer: Option

, pub(crate) meta: BatchEncodedEntryMeta, } -impl EntryWithKeyBuilder +impl EntryWithKeyBuilder where V: Borrow<[u8]>, { /// Returns the length of the value. #[inline] - pub fn value_len(&self) -> usize { + pub(crate) fn value_len(&self) -> usize { self.value.borrow().len() } } @@ -154,10 +157,10 @@ impl EntryWithKeyBuilder { } /// An entry builder which can build an [`Entry`] to be inserted into the [`Wal`](crate::wal::Wal). -pub struct EntryWithValueBuilder { +pub struct EntryWithValueBuilder { pub(crate) key: K, pub(crate) vb: ValueBuilder, - pub(crate) pointer: Option>, + pub(crate) pointer: Option

, pub(crate) meta: BatchEncodedEntryMeta, } @@ -167,12 +170,12 @@ where { /// Returns the length of the key. #[inline] - pub fn key_len(&self) -> usize { + pub(crate) fn key_len(&self) -> usize { self.key.borrow().len() } } -impl EntryWithValueBuilder { +impl EntryWithValueBuilder { /// Creates a new entry. #[inline] pub const fn new(key: K, vb: ValueBuilder) -> Self { @@ -209,74 +212,117 @@ impl EntryWithValueBuilder { } } -/// An entry builder which can build an [`Entry`] to be inserted into the [`Wal`](crate::wal::Wal). -pub struct EntryWithBuilders { - pub(crate) kb: KeyBuilder, - pub(crate) vb: ValueBuilder, - pub(crate) pointer: Option>, - pub(crate) meta: BatchEncodedEntryMeta, +/// A wrapper around a generic type that can be used to construct a [`GenericEntry`]. +#[repr(transparent)] +pub struct Generic<'a, T: ?Sized> { + data: Either<&'a T, &'a [u8]>, } -impl EntryWithBuilders { - /// Creates a new entry. +impl<'a, T: 'a> PartialEq for Generic<'a, T> +where + T: ?Sized + PartialEq + Type + for<'b> Equivalent>, +{ #[inline] - pub const fn new(kb: KeyBuilder, vb: ValueBuilder) -> Self { - Self { - kb, - vb, - pointer: None, - meta: BatchEncodedEntryMeta::zero(), + fn eq(&self, other: &T) -> bool { + match &self.data { + Either::Left(val) => (*val).eq(other), + Either::Right(val) => { + let ref_ = unsafe { as TypeRef<'_>>::from_slice(val) }; + other.equivalent(&ref_) + } } } +} - /// Returns the value builder. +impl<'a, T: 'a> PartialEq for Generic<'a, T> +where + T: ?Sized + PartialEq + Type + for<'b> Equivalent>, +{ #[inline] - pub const fn value_builder(&self) -> &ValueBuilder { - &self.vb + fn eq(&self, other: &Self) -> bool { + match (&self.data, &other.data) { + (Either::Left(val), Either::Left(other_val)) => val.eq(other_val), + (Either::Right(val), Either::Right(other_val)) => val.eq(other_val), + (Either::Left(val), Either::Right(other_val)) => { + let ref_ = unsafe { as TypeRef<'_>>::from_slice(other_val) }; + val.equivalent(&ref_) + } + (Either::Right(val), Either::Left(other_val)) => { + let ref_ = unsafe { as TypeRef<'_>>::from_slice(val) }; + other_val.equivalent(&ref_) + } + } } +} - /// Returns the key builder. - #[inline] - pub const fn key_builder(&self) -> &KeyBuilder { - &self.kb - } +impl<'a, T: 'a> Eq for Generic<'a, T> where T: ?Sized + Eq + Type + for<'b> Equivalent> {} - /// Returns the length of the key. +impl<'a, T: 'a> PartialOrd for Generic<'a, T> +where + T: ?Sized + Ord + Type + for<'b> Comparable>, + for<'b> T::Ref<'b>: Comparable + Ord, +{ #[inline] - pub const fn key_len(&self) -> usize { - self.kb.size() as usize + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } +} - /// Returns the length of the value. +impl<'a, T: 'a> PartialOrd for Generic<'a, T> +where + T: ?Sized + PartialOrd + Type + for<'b> Comparable>, +{ #[inline] - pub const fn value_len(&self) -> usize { - self.vb.size() as usize + fn partial_cmp(&self, other: &T) -> Option { + match &self.data { + Either::Left(val) => (*val).partial_cmp(other), + Either::Right(val) => { + let ref_ = unsafe { as TypeRef<'_>>::from_slice(val) }; + Some(other.compare(&ref_).reverse()) + } + } } +} - /// Consumes the entry and returns the key and value. +impl<'a, T: 'a> Ord for Generic<'a, T> +where + T: ?Sized + Ord + Type + for<'b> Comparable>, + for<'b> T::Ref<'b>: Comparable + Ord, +{ #[inline] - pub fn into_components(self) -> (KeyBuilder, ValueBuilder) { - (self.kb, self.vb) + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + match (&self.data, &other.data) { + (Either::Left(val), Either::Left(other_val)) => (*val).cmp(other_val), + (Either::Right(val), Either::Right(other_val)) => { + let this = unsafe { as TypeRef<'_>>::from_slice(val) }; + let other = unsafe { as TypeRef<'_>>::from_slice(other_val) }; + this.cmp(&other) + } + (Either::Left(val), Either::Right(other_val)) => { + let other = unsafe { as TypeRef<'_>>::from_slice(other_val) }; + other.compare(*val).reverse() + } + (Either::Right(val), Either::Left(other_val)) => { + let this = unsafe { as TypeRef<'_>>::from_slice(val) }; + this.compare(*other_val) + } + } } } -/// A wrapper around a generic type that can be used to construct a [`GenericEntry`]. -#[repr(transparent)] -pub struct Generic<'a, T: ?Sized> { - data: Either<&'a T, &'a [u8]>, -} - -impl Generic<'_, T> { +impl<'a, T: 'a + Type + ?Sized> Generic<'a, T> { + /// Returns the encoded length. #[inline] - pub(crate) fn encoded_len(&self) -> usize { + pub fn encoded_len(&self) -> usize { match &self.data { Either::Left(val) => val.encoded_len(), Either::Right(val) => val.len(), } } + /// Encodes the generic into the buffer. #[inline] - pub(crate) fn encode(&self, buf: &mut [u8]) -> Result { + pub fn encode(&self, buf: &mut [u8]) -> Result { match &self.data { Either::Left(val) => val.encode(buf), Either::Right(val) => { @@ -287,7 +333,7 @@ impl Generic<'_, T> { } } -impl<'a, T: ?Sized> Generic<'a, T> { +impl<'a, T: 'a + ?Sized> Generic<'a, T> { /// Returns the value contained in the generic. #[inline] pub const fn data(&self) -> Either<&T, &'a [u8]> { @@ -306,7 +352,7 @@ impl<'a, T: ?Sized> Generic<'a, T> { } } -impl<'a, T: ?Sized> From<&'a T> for Generic<'a, T> { +impl<'a, T: 'a + ?Sized> From<&'a T> for Generic<'a, T> { #[inline] fn from(value: &'a T) -> Self { Self { @@ -335,6 +381,30 @@ impl<'a, K: ?Sized, V: ?Sized> GenericEntry<'a, K, V> { } } + /// Returns the length of the key. + #[inline] + pub fn key_len(&self) -> usize + where + K: Type, + { + match self.key.data() { + Either::Left(val) => val.encoded_len(), + Either::Right(val) => val.len(), + } + } + + /// Returns the length of the value. + #[inline] + pub fn value_len(&self) -> usize + where + V: Type, + { + match self.value.data() { + Either::Left(val) => val.encoded_len(), + Either::Right(val) => val.len(), + } + } + /// Returns the key. #[inline] pub const fn key(&self) -> Either<&K, &[u8]> { @@ -354,14 +424,66 @@ impl<'a, K: ?Sized, V: ?Sized> GenericEntry<'a, K, V> { } } +/// An entry builder which can build an [`GenericEntry`] to be inserted into the [`GenericOrderWal`](crate::swmr::generic::GenericOrderWal). +pub struct EntryWithBuilders { + pub(crate) kb: KeyBuilder, + pub(crate) vb: ValueBuilder, + pub(crate) pointer: Option

, + pub(crate) meta: BatchEncodedEntryMeta, +} + +impl EntryWithBuilders { + /// Creates a new entry. + #[inline] + pub const fn new(kb: KeyBuilder, vb: ValueBuilder) -> Self { + Self { + kb, + vb, + pointer: None, + meta: BatchEncodedEntryMeta::zero(), + } + } + + /// Returns the value builder. + #[inline] + pub const fn value_builder(&self) -> &ValueBuilder { + &self.vb + } + + /// Returns the key builder. + #[inline] + pub const fn key_builder(&self) -> &KeyBuilder { + &self.kb + } + + /// Returns the length of the key. + #[inline] + pub const fn key_len(&self) -> usize { + self.kb.size() as usize + } + + /// Returns the length of the value. + #[inline] + pub const fn value_len(&self) -> usize { + self.vb.size() as usize + } + + /// Consumes the entry and returns the key and value. + #[inline] + pub fn into_components(self) -> (KeyBuilder, ValueBuilder) { + (self.kb, self.vb) + } +} + /// The reference to an entry in the [`GenericOrderWal`](crate::swmr::GenericOrderWal). -#[repr(transparent)] pub struct GenericEntryRef<'a, K, V> where - K: ?Sized, - V: ?Sized, + K: ?Sized + Type, + V: ?Sized + Type, { ent: SetEntry<'a, GenericPointer>, + key: K::Ref<'a>, + value: V::Ref<'a>, } impl<'a, K, V> core::fmt::Debug for GenericEntryRef<'a, K, V> @@ -372,53 +494,89 @@ where V::Ref<'a>: core::fmt::Debug, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("EntryRef") + f.debug_struct("GenericEntryRef") .field("key", &self.key()) .field("value", &self.value()) .finish() } } -impl Clone for GenericEntryRef<'_, K, V> +impl<'a, K, V> Clone for GenericEntryRef<'a, K, V> where - K: ?Sized, - V: ?Sized, + K: ?Sized + Type, + K::Ref<'a>: Clone, + V: ?Sized + Type, + V::Ref<'a>: Clone, { #[inline] fn clone(&self) -> Self { Self { ent: self.ent.clone(), + key: self.key.clone(), + value: self.value.clone(), } } } impl<'a, K, V> GenericEntryRef<'a, K, V> where - K: ?Sized, - V: ?Sized, + K: ?Sized + Type, + V: ?Sized + Type, { #[inline] pub(super) fn new(ent: SetEntry<'a, GenericPointer>) -> Self { - Self { ent } + Self { + key: unsafe { TypeRef::from_slice(ent.value().as_key_slice()) }, + value: unsafe { TypeRef::from_slice(ent.value().as_value_slice()) }, + ent, + } + } +} + +impl GenericEntryRef<'_, K, V> +where + K: Type + Ord + ?Sized, + for<'b> K::Ref<'b>: KeyRef<'b, K>, + V: ?Sized + Type, +{ + /// Returns the next entry in the [`GenericOrderWal`](crate::swmr::GenericOrderWal). + /// + /// This does not move the cursor. + #[inline] + #[allow(clippy::should_implement_trait)] + pub fn next(&self) -> Option { + self.ent.next().map(Self::new) + } + + /// Returns the previous entry in the [`GenericOrderWal`](crate::swmr::GenericOrderWal). + /// + /// This does not move the cursor. + #[inline] + pub fn prev(&self) -> Option { + self.ent.prev().map(Self::new) } } impl<'a, K, V> GenericEntryRef<'a, K, V> where - K: Type + ?Sized, + K: ?Sized + Type, V: Type + ?Sized, { - /// Returns the key of the entry. + /// Returns the value of the entry. #[inline] - pub fn key(&self) -> K::Ref<'a> { - let p = self.ent.value(); - unsafe { TypeRef::from_slice(p.as_key_slice()) } + pub fn value(&self) -> &V::Ref<'a> { + &self.value } +} - /// Returns the value of the entry. +impl<'a, K, V> GenericEntryRef<'a, K, V> +where + K: Type + ?Sized, + V: ?Sized + Type, +{ + /// Returns the key of the entry. #[inline] - pub fn value(&self) -> V::Ref<'a> { - let p = self.ent.value(); - unsafe { TypeRef::from_slice(p.as_value_slice()) } + pub fn key(&self) -> &K::Ref<'a> { + &self.key } } diff --git a/src/swmr/generic.rs b/src/swmr/generic.rs index 0bdf641..5fe1578 100644 --- a/src/swmr/generic.rs +++ b/src/swmr/generic.rs @@ -2,6 +2,7 @@ use core::{ cmp, marker::PhantomData, ops::Bound, + ptr::NonNull, slice, sync::atomic::{AtomicPtr, Ordering}, }; @@ -13,10 +14,12 @@ use std::{ use among::Among; use crossbeam_skiplist::SkipSet; use dbutils::{ + buffer::VacantBuffer, checksum::{BuildChecksumer, Checksumer, Crc32}, leb128::encoded_u64_varint_len, }; -use rarena_allocator::{either::Either, sync::Arena, Allocator, Buffer}; +use rarena_allocator::{either::Either, sync::Arena, Allocator, Buffer, BytesRefMut}; +use ref_cast::RefCast; use crate::{ arena_options, check, entry_size, @@ -24,12 +27,13 @@ use crate::{ merge_lengths, pointer::GenericPointer, wal::sealed::Constructor, - BatchEncodedEntryMeta, Flags, Options, CHECKSUM_SIZE, HEADER_SIZE, STATUS_SIZE, + BatchEncodedEntryMeta, EntryWithBuilders, EntryWithKeyBuilder, EntryWithValueBuilder, Flags, + KeyBuilder, Options, ValueBuilder, CHECKSUM_SIZE, HEADER_SIZE, STATUS_SIZE, }; pub use crate::{ entry::{Generic, GenericEntry, GenericEntryRef}, - wal::GenericBatch, + wal::{BatchWithBuilders, BatchWithKeyBuilder, BatchWithValueBuilder, GenericBatch}, }; pub use dbutils::{ @@ -58,21 +62,22 @@ pub use builder::*; ))] mod tests; -struct PartialPointer { - key_len: usize, - ptr: *const u8, +#[derive(ref_cast::RefCast)] +#[repr(transparent)] +struct Slice { _k: PhantomData, + data: [u8], } -impl PartialEq for PartialPointer { +impl PartialEq for Slice { fn eq(&self, other: &Self) -> bool { - self.as_key_slice() == other.as_key_slice() + self.data == other.data } } -impl Eq for PartialPointer {} +impl Eq for Slice {} -impl PartialOrd for PartialPointer +impl PartialOrd for Slice where K: Type + Ord + ?Sized, for<'a> K::Ref<'a>: KeyRef<'a, K>, @@ -82,44 +87,20 @@ where } } -impl Ord for PartialPointer +impl Ord for Slice where K: Type + Ord + ?Sized, for<'a> K::Ref<'a>: KeyRef<'a, K>, { fn cmp(&self, other: &Self) -> cmp::Ordering { - unsafe { as KeyRef>::compare_binary(self.as_key_slice(), other.as_key_slice()) } + unsafe { as KeyRef>::compare_binary(&self.data, &other.data) } } } -impl PartialPointer -where - K: ?Sized, -{ - #[inline] - const fn new(key_len: usize, ptr: *const u8) -> Self { - Self { - key_len, - ptr, - _k: PhantomData, - } - } - - #[inline] - fn as_key_slice<'a>(&self) -> &'a [u8] { - if self.key_len == 0 { - return &[]; - } - - // SAFETY: `ptr` is a valid pointer to `len` bytes. - unsafe { slice::from_raw_parts(self.ptr, self.key_len) } - } -} - -impl<'a, K, V> Equivalent> for PartialPointer +impl Equivalent> for Slice where K: Type + Ord + ?Sized, - K::Ref<'a>: KeyRef<'a, K>, + for<'a> K::Ref<'a>: KeyRef<'a, K>, V: ?Sized, { fn equivalent(&self, key: &GenericPointer) -> bool { @@ -127,23 +108,24 @@ where } } -impl<'a, K, V> Comparable> for PartialPointer +impl Comparable> for Slice where K: Type + Ord + ?Sized, - K::Ref<'a>: KeyRef<'a, K>, + for<'a> K::Ref<'a>: KeyRef<'a, K>, V: ?Sized, { fn compare(&self, p: &GenericPointer) -> cmp::Ordering { unsafe { let kr: K::Ref<'_> = TypeRef::from_slice(p.as_key_slice()); - let or: K::Ref<'_> = TypeRef::from_slice(self.as_key_slice()); + let or: K::Ref<'_> = TypeRef::from_slice(&self.data); KeyRef::compare(&kr, &or).reverse() } } } #[derive(PartialEq, Eq, PartialOrd, Ord)] -struct Ref<'a, K, Q> +#[repr(transparent)] +struct Query<'a, K, Q> where K: ?Sized, Q: ?Sized, @@ -152,7 +134,7 @@ where _k: PhantomData, } -impl<'a, K, Q> Ref<'a, K, Q> +impl<'a, K, Q> Query<'a, K, Q> where K: ?Sized, Q: ?Sized, @@ -166,80 +148,31 @@ where } } -impl<'a, K, Q, V> Equivalent> for Ref<'a, K, Q> +impl<'a, 'b: 'a, K, Q, V> Equivalent> for Query<'a, K, Q> where K: Type + Ord + ?Sized, - K::Ref<'a>: KeyRef<'a, K>, V: ?Sized, - Q: ?Sized + Ord + Comparable>, -{ - fn equivalent(&self, key: &GenericPointer) -> bool { - self.compare(key).is_eq() - } -} - -impl<'a, K, Q, V> Comparable> for Ref<'a, K, Q> -where - K: Type + Ord + ?Sized, - K::Ref<'a>: KeyRef<'a, K>, - V: ?Sized, - Q: ?Sized + Ord + Comparable>, -{ - fn compare(&self, p: &GenericPointer) -> cmp::Ordering { - let kr = unsafe { TypeRef::from_slice(p.as_key_slice()) }; - KeyRef::compare(&kr, self.key).reverse() - } -} - -#[derive(PartialEq, Eq, PartialOrd, Ord)] -struct Owned<'a, K, Q> -where - K: ?Sized, - Q: ?Sized, -{ - key: &'a Q, - _k: PhantomData, -} - -impl<'a, K, Q> Owned<'a, K, Q> -where - K: ?Sized, - Q: ?Sized, + Q: ?Sized + Ord + Equivalent>, { #[inline] - const fn new(key: &'a Q) -> Self { - Self { - key, - _k: PhantomData, - } + fn equivalent(&self, p: &GenericPointer) -> bool { + let kr = unsafe { as TypeRef<'b>>::from_slice(p.as_key_slice()) }; + Equivalent::equivalent(self.key, &kr) } } -impl<'a, K, Q, V> Equivalent> for Owned<'a, K, Q> +impl<'a, 'b: 'a, K, Q, V> Comparable> for Query<'a, K, Q> where K: Type + Ord + ?Sized, - K::Ref<'a>: KeyRef<'a, K>, V: ?Sized, - Q: ?Sized + Ord + Comparable + Comparable>, -{ - fn equivalent(&self, key: &GenericPointer) -> bool { - self.compare(key).is_eq() - } -} - -impl<'a, K, Q, V> Comparable> for Owned<'a, K, Q> -where - K: Type + Ord + ?Sized, - K::Ref<'a>: KeyRef<'a, K>, - V: ?Sized, - Q: ?Sized + Ord + Comparable + Comparable>, + Q: ?Sized + Ord + Comparable>, { + #[inline] fn compare(&self, p: &GenericPointer) -> cmp::Ordering { - let kr = unsafe { as TypeRef<'_>>::from_slice(p.as_key_slice()) }; - KeyRef::compare(&kr, self.key).reverse() + let kr = unsafe { as TypeRef<'b>>::from_slice(p.as_key_slice()) }; + Comparable::compare(self.key, &kr) } } - #[doc(hidden)] pub struct GenericOrderWalCore { arena: Arena, @@ -290,6 +223,7 @@ where where K: Type + Ord, for<'b> K::Ref<'b>: KeyRef<'b, K>, + V: Type, { self.map.front().map(GenericEntryRef::new) } @@ -299,6 +233,7 @@ where where K: Type + Ord, for<'b> K::Ref<'b>: KeyRef<'b, K>, + V: Type, { self.map.back().map(GenericEntryRef::new) } @@ -312,24 +247,6 @@ where Iter::new(self.map.iter()) } - #[inline] - fn range_by_ref<'a, Q>( - &'a self, - start_bound: Bound<&'a Q>, - end_bound: Bound<&'a Q>, - ) -> RefRange<'a, Q, K, V> - where - K: Type + Ord, - for<'b> K::Ref<'b>: KeyRef<'b, K>, - Q: Ord + ?Sized + Comparable>, - { - RefRange::new( - self - .map - .range((start_bound.map(Ref::new), end_bound.map(Ref::new))), - ) - } - #[inline] fn range<'a, Q>( &'a self, @@ -339,12 +256,12 @@ where where K: Type + Ord, for<'b> K::Ref<'b>: KeyRef<'b, K>, - Q: Ord + ?Sized + Comparable + Comparable>, + Q: Ord + ?Sized + for<'b> Comparable>, { Range::new( self .map - .range((start_bound.map(Owned::new), end_bound.map(Owned::new))), + .range((start_bound.map(Query::new), end_bound.map(Query::new))), ) } } @@ -376,58 +293,84 @@ impl GenericOrderWalCore where K: Type + Ord + ?Sized, for<'a> ::Ref<'a>: KeyRef<'a, K>, - V: Type + ?Sized, + V: ?Sized, { #[inline] - fn contains_key<'a, Q>(&'a self, key: &'a Q) -> bool + fn contains_key<'a, Q>(&'a self, key: &Q) -> bool where - Q: ?Sized + Ord + Comparable> + Comparable, + Q: ?Sized + Ord + Comparable>, { - self.map.contains::>(&Owned::new(key)) + self.map.contains::>(&Query::new(key)) } #[inline] - fn contains_key_by_ref<'a, Q>(&'a self, key: &'a Q) -> bool + unsafe fn contains_key_by_bytes(&self, key: &[u8]) -> bool { + self.map.contains(Slice::ref_cast(key)) + } + + #[inline] + fn get<'a, Q>(&'a self, key: &Q) -> Option> where Q: ?Sized + Ord + Comparable>, + V: Type, { - self.map.contains::>(&Ref::new(key)) + self + .map + .get::>(&Query::new(key)) + .map(GenericEntryRef::new) } #[inline] - unsafe fn contains_key_by_bytes(&self, key: &[u8]) -> bool { + unsafe fn get_by_bytes(&self, key: &[u8]) -> Option> + where + V: Type, + { + self.map.get(Slice::ref_cast(key)).map(GenericEntryRef::new) + } + + #[inline] + fn upper_bound<'a, 'b: 'a, Q>(&'a self, key: Bound<&'b Q>) -> Option> + where + Q: ?Sized + Ord + Comparable>, + V: Type, + { self .map - .contains(&PartialPointer::new(key.len(), key.as_ptr())) + .upper_bound(key.map(Query::new).as_ref()) + .map(GenericEntryRef::new) } #[inline] - fn get<'a, Q>(&'a self, key: &'a Q) -> Option> + unsafe fn upper_bound_by_bytes(&self, key: Bound<&[u8]>) -> Option> where - Q: ?Sized + Ord + Comparable> + Comparable, + V: Type, { self .map - .get::>(&Owned::new(key)) + .upper_bound(key.map(Slice::ref_cast)) .map(GenericEntryRef::new) } #[inline] - fn get_by_ref<'a, Q>(&'a self, key: &'a Q) -> Option> + fn lower_bound<'a, 'b: 'a, Q>(&'a self, key: Bound<&'b Q>) -> Option> where - Q: ?Sized + Ord + Comparable>, + Q: ?Sized + Ord + Comparable>, + V: Type, { self .map - .get::>(&Ref::new(key)) + .lower_bound(key.map(Query::new).as_ref()) .map(GenericEntryRef::new) } #[inline] - unsafe fn get_by_bytes(&self, key: &[u8]) -> Option> { + unsafe fn lower_bound_by_bytes(&self, key: Bound<&[u8]>) -> Option> + where + V: Type, + { self .map - .get(&PartialPointer::new(key.len(), key.as_ptr())) + .lower_bound(key.map(Slice::ref_cast)) .map(GenericEntryRef::new) } } @@ -450,13 +393,19 @@ where { /// Returns the first key-value pair in the map. The key in this pair is the minimum key in the wal. #[inline] - pub fn first(&self) -> Option> { + pub fn first(&self) -> Option> + where + V: Type, + { self.core.first() } /// Returns the last key-value pair in the map. The key in this pair is the maximum key in the wal. #[inline] - pub fn last(&self) -> Option> { + pub fn last(&self) -> Option> + where + V: Type, + { self.core.last() } @@ -465,20 +414,6 @@ where pub fn iter(&self) -> Iter<'_, K, V> { self.core.iter() } - - /// Returns an iterator over a subset of the entries in the WAL. - #[inline] - pub fn range_by_ref<'a, Q>( - &'a self, - start_bound: Bound<&'a Q>, - end_bound: Bound<&'a Q>, - ) -> RefRange<'a, Q, K, V> - where - Q: Ord + ?Sized + Comparable>, - { - self.core.range_by_ref(start_bound, end_bound) - } - /// Returns an iterator over a subset of the entries in the WAL. #[inline] pub fn range<'a, Q>( @@ -487,7 +422,7 @@ where end_bound: Bound<&'a Q>, ) -> Range<'a, Q, K, V> where - Q: Ord + ?Sized + Comparable + Comparable>, + Q: Ord + ?Sized + for<'b> Comparable>, { self.core.range(start_bound, end_bound) } @@ -495,13 +430,13 @@ where impl GenericOrderWal where - K: ?Sized + 'static, - V: ?Sized + 'static, + K: ?Sized, + V: ?Sized, { /// Returns a read-only WAL instance. #[inline] - pub fn reader(&self) -> GenericWalReader { - GenericWalReader::new(self.core.clone()) + pub fn reader(&self) -> GenericOrderWalReader { + GenericOrderWalReader::new(self.core.clone()) } /// Returns the path of the WAL if it is backed by a file. @@ -555,13 +490,13 @@ impl GenericOrderWal where K: Type + Ord + ?Sized, for<'a> K::Ref<'a>: KeyRef<'a, K>, - V: Type + ?Sized, + V: ?Sized, { /// Returns `true` if the key exists in the WAL. #[inline] - pub fn contains_key<'a, Q>(&'a self, key: &'a Q) -> bool + pub fn contains_key<'a, Q>(&'a self, key: &Q) -> bool where - Q: ?Sized + Ord + Comparable> + Comparable, + Q: ?Sized + Ord + Comparable>, { self.core.contains_key(key) } @@ -575,40 +510,86 @@ where self.core.contains_key_by_bytes(key) } - /// Returns `true` if the key exists in the WAL. + /// Gets the value associated with the key. #[inline] - pub fn contains_key_by_ref<'a, Q>(&'a self, key: &'a Q) -> bool + pub fn get<'a, Q>(&'a self, key: &Q) -> Option> where Q: ?Sized + Ord + Comparable>, + V: Type, { - self.core.contains_key_by_ref(key) + self.core.get(key) } /// Gets the value associated with the key. + /// + /// ## Safety + /// - The given `key` must be valid to construct to `K::Ref` without remaining. #[inline] - pub fn get<'a, Q>(&'a self, key: &'a Q) -> Option> + pub unsafe fn get_by_bytes(&self, key: &[u8]) -> Option> where - Q: ?Sized + Ord + Comparable> + Comparable, + V: Type, { - self.core.get(key) + self.core.get_by_bytes(key) } - /// Gets the value associated with the key. + /// Returns a value associated to the highest element whose key is below the given bound. + /// If no such element is found then `None` is returned. #[inline] - pub fn get_by_ref<'a, Q>(&'a self, key: &'a Q) -> Option> + pub fn upper_bound<'a, 'b: 'a, Q>( + &'a self, + bound: Bound<&'b Q>, + ) -> Option> where - Q: ?Sized + Ord + Comparable>, + Q: ?Sized + Ord + Comparable>, + V: Type, { - self.core.get_by_ref(key) + self.core.upper_bound(bound) } - /// Gets the value associated with the key. + /// Returns a value associated to the highest element whose key is below the given bound. + /// If no such element is found then `None` is returned. /// /// ## Safety - /// - The given `key` must be valid to construct to `K::Ref` without remaining. + /// - The given `key` in `Bound` must be valid to construct to `K::Ref` without remaining. #[inline] - pub unsafe fn get_by_bytes(&self, key: &[u8]) -> Option> { - self.core.get_by_bytes(key) + pub unsafe fn upper_bound_by_bytes( + &self, + bound: Bound<&[u8]>, + ) -> Option> + where + V: Type, + { + self.core.upper_bound_by_bytes(bound) + } + + /// Returns a value associated to the lowest element whose key is above the given bound. + /// If no such element is found then `None` is returned. + #[inline] + pub fn lower_bound<'a, 'b: 'a, Q>( + &'a self, + bound: Bound<&'b Q>, + ) -> Option> + where + Q: ?Sized + Ord + Comparable>, + V: Type, + { + self.core.lower_bound(bound) + } + + /// Returns a value associated to the lowest element whose key is above the given bound. + /// If no such element is found then `None` is returned. + /// + /// ## Safety + /// - The given `key` in `Bound` must be valid to construct to `K::Ref` without remaining. + #[inline] + pub unsafe fn lower_bound_by_bytes( + &self, + bound: Bound<&[u8]>, + ) -> Option> + where + V: Type, + { + self.core.lower_bound_by_bytes(bound) } } @@ -624,18 +605,33 @@ where pub fn get_or_insert<'a>( &mut self, key: impl Into>, - value: impl Into>, + val: impl Into>, ) -> Either, Result<(), Among>> { let key: Generic<'a, K> = key.into(); let map = &self.core.map; let ent = match key.data() { - Either::Left(k) => map.get(&Owned::new(k)), - Either::Right(key) => map.get(&PartialPointer::new(key.len(), key.as_ptr())), + Either::Left(k) => map.get(&Query::new(k)), + Either::Right(key) => map.get(Slice::ref_cast(key)), }; match ent.map(|e| Either::Left(GenericEntryRef::new(e))) { Some(e) => e, - None => Either::Right(self.insert_in(key, value.into())), + None => { + let klen = key.encoded_len() as u32; + let kb: KeyBuilder<_> = KeyBuilder::once(klen, |buf| { + buf.set_len(klen as usize); + key.encode(buf).map(|_| ()) + }); + + let val: Generic<'_, V> = val.into(); + let vlen = val.encoded_len() as u32; + let vb: ValueBuilder<_> = ValueBuilder::once(vlen, |buf| { + buf.set_len(vlen as usize); + val.encode(buf).map(|_| ()) + }); + + Either::Right(self.insert_in(kb, vb)) + } } } @@ -652,51 +648,152 @@ where let key: Generic<'a, K> = key.into(); let map = &self.core.map; let ent = match key.data() { - Either::Left(k) => map.get(&Owned::new(k)), - Either::Right(key) => map.get(&PartialPointer::new(key.len(), key.as_ptr())), + Either::Left(k) => map.get(&Query::new(k)), + Either::Right(key) => map.get(Slice::ref_cast(key)), }; match ent.map(|e| Either::Left(GenericEntryRef::new(e))) { Some(e) => e, None => { - let v = value(); - Either::Right(self.insert_in(key, (&v).into())) + let klen = key.encoded_len() as u32; + let kb: KeyBuilder<_> = KeyBuilder::once(klen, |buf| { + buf.set_len(klen as usize); + key.encode(buf).map(|_| ()) + }); + let val = value(); + let vlen = val.encoded_len() as u32; + let vb: ValueBuilder<_> = ValueBuilder::once(vlen, |buf| { + buf.set_len(vlen as usize); + val.encode(buf).map(|_| ()) + }); + + Either::Right(self.insert_in(kb, vb)) } } } } +trait GenericEntryWithKeyBuilderLength { + fn value_len(&self) -> usize; +} + +impl GenericEntryWithKeyBuilderLength for EntryWithKeyBuilder, P> +where + V: Type + ?Sized, +{ + #[inline] + fn value_len(&self) -> usize { + self.value.encoded_len() + } +} + +trait GenericEntryWithValueBuilderLength { + fn key_len(&self) -> usize; +} + +impl GenericEntryWithValueBuilderLength for EntryWithValueBuilder, VB, P> +where + K: Type + ?Sized, +{ + #[inline] + fn key_len(&self) -> usize { + self.key.encoded_len() + } +} + +macro_rules! process_batch { + ($this:ident($batch:ident, $key:expr, $value:expr)) => {{ + let batch_ptr = AtomicPtr::new($batch); + let batch = batch_ptr.load(Ordering::Acquire); + (*batch) + .iter_mut() + .try_fold((0u32, 0u64), |(num_entries, size), ent| { + let klen = ent.key_len(); + let vlen = ent.value_len(); + crate::utils::check_batch_entry( + klen, + vlen, + $this.core.opts.maximum_key_size(), + $this.core.opts.maximum_value_size(), + ).map(|_| { + let merged_len = merge_lengths(klen as u32, vlen as u32); + let merged_len_size = encoded_u64_varint_len(merged_len); + let ent_size = klen as u64 + vlen as u64 + merged_len_size as u64; + ent.meta = BatchEncodedEntryMeta::new(klen, vlen, merged_len, merged_len_size); + (num_entries + 1, size + ent_size) + }) + .map_err(Among::Right) + }) + .and_then(|(num_entries, batch_encoded_size)| { + // safe to cast batch_encoded_size to u32 here, we already checked it's less than capacity (less than u32::MAX). + let batch_meta = merge_lengths(num_entries, batch_encoded_size as u32); + let batch_meta_size = encoded_u64_varint_len(batch_meta); + let allocator = &$this.core.arena; + let remaining = allocator.remaining() as u64; + let total_size = + STATUS_SIZE as u64 + batch_meta_size as u64 + batch_encoded_size + CHECKSUM_SIZE as u64; + if total_size > remaining { + return Err(Among::Right(Error::insufficient_space(total_size, remaining as u32))); + } + + let mut buf = allocator + .alloc_bytes(total_size as u32) + .map_err(|e| Among::Right(Error::from_insufficient_space(e)))?; + + let flag = Flags::BATCHING; + + buf.put_u8_unchecked(flag.bits); + buf.put_u64_varint_unchecked(batch_meta); + + let mut cursor = 1 + batch_meta_size; + + for ent in (*batch).iter_mut() { + let remaining = buf.remaining(); + if remaining < ent.meta.kvlen_size + ent.meta.klen + ent.meta.vlen { + return Err(Among::Right( + Error::larger_batch_size(buf.capacity() as u32), + )); + } + + let ent_len_size = buf.put_u64_varint_unchecked(ent.meta.kvlen); + let ko = cursor + ent_len_size; + buf.set_len(ko + ent.meta.klen + ent.meta.vlen); + let ptr = buf.as_mut_ptr().add(ko); + + $key(ptr, &ent)?; + $value(ptr.add(ent.meta.klen), &ent)?; + + cursor += ent_len_size + ent.meta.klen + ent.meta.vlen; + ent.pointer = Some(GenericPointer::new(ent.meta.klen, ent.meta.vlen, ptr)); + } + + $this + .insert_batch_helper(&$this.core.arena, buf, cursor as usize, || { + (*batch).iter_mut().map(|ent| ent.pointer.take().unwrap()) + }) + .map_err(Among::Right) + }) + }}; +} + impl GenericOrderWal where - K: Type + Ord + ?Sized + 'static, + K: Type + Ord + ?Sized, for<'a> K::Ref<'a>: KeyRef<'a, K>, - V: Type + ?Sized + 'static, + V: Type + ?Sized, S: BuildChecksumer, { /// Inserts a key-value pair into the write-ahead log. /// + /// See also [`insert_with_key_builder`](GenericOrderWal::insert_with_key_builder), [`insert_with_value_builder`](GenericOrderWal::insert_with_value_builder), and [`insert_with_builders`](GenericOrderWal::insert_with_builders). + /// /// ## Example /// - /// Here are three examples of how flexible the `insert` method is: + /// Here are two examples of how flexible the `insert` method is: /// /// The `Person` struct implementation can be found [here](https://github.com/al8n/orderwal/blob/main/src/swmr/generic/tests.rs#L24). /// - /// 1. **Inserting an owned key-value pair with structured key and value** - /// - /// ```rust,ignore - /// use orderwal::swmr::{*, generic::*}; - /// - /// let person = Person { - /// id: 1, - /// name: "Alice".to_string(), - /// }; - /// - /// let mut wal = GenericBuilder::new().with_capacity(1024).alloc::().unwrap(); - /// let value = "Hello, Alice!".to_string(); - /// wal.insert(&person, value); - /// ``` - /// - /// 2. **Inserting a key-value pair, key is a reference, value is owned** + /// 1. **Inserting a key-value pair, key and value are references** /// /// ```rust,ignore /// use orderwal::swmr::{*, generic::*}; @@ -708,10 +805,10 @@ where /// name: "Alice".to_string(), /// }; /// - /// wal.insert(&person, "value".to_string()); + /// wal.insert(&person, &"value".to_string()); /// ``` /// - /// 3. **Inserting a key-value pair, both of them are in encoded format** + /// 2. **Inserting a key-value pair, both of them are in encoded format** /// /// ```rust,ignore /// use orderwal::swmr::{*, generic::*}; @@ -735,131 +832,277 @@ where &mut self, key: impl Into>, val: impl Into>, - ) -> Result<(), Among> { - self.insert_in(key.into(), val.into()) + ) -> Result<(), Among> + where + GenericPointer: 'static, + { + let key: Generic<'_, K> = key.into(); + let klen = key.encoded_len() as u32; + let kb: KeyBuilder<_> = KeyBuilder::once(klen, |buf| { + buf.set_len(klen as usize); + key.encode(buf).map(|_| ()) + }); + + let val: Generic<'_, V> = val.into(); + let vlen = val.encoded_len() as u32; + let vb: ValueBuilder<_> = ValueBuilder::once(vlen, |buf| { + buf.set_len(vlen as usize); + val.encode(buf).map(|_| ()) + }); + self.insert_in(kb, vb) } - /// Inserts a batch of entries into the write-ahead log. - pub fn insert_batch<'a, 'b: 'a, B: GenericBatch<'b, Key = K, Value = V>>( - &'a mut self, - batch: &'b mut B, - ) -> Result<(), Among> { - // TODO: is there another way to avoid the borrow checker? - let batch_ptr = AtomicPtr::new(batch); + /// Inserts a key-value pair into the WAL. This method + /// allows the caller to build the key in place. + /// + /// This method is useful when playing with `?Sized` key types. See details in the example. + /// + /// ## Safety + /// - The bytes written to the buffer must be valid to decode by [`K::from_slice`](TypeRef::from_slice). + /// + /// ## Example + /// + /// See [`examples/generic_not_sized.rs`](https://github.com/al8n/orderwal/tree/main/examples/generic_not_sized.rs). + #[inline] + pub unsafe fn insert_with_key_builder<'a, E>( + &mut self, + kb: KeyBuilder) -> Result<(), E> + 'a>, + val: impl Into>, + ) -> Result<(), Among> + where + GenericPointer: 'static, + { + let val: Generic<'_, V> = val.into(); + let vlen = val.encoded_len() as u32; + let vb = ValueBuilder::once(vlen, |buf| { + buf.set_len(vlen as usize); + val.encode(buf).map(|_| ()) + }); + + self.insert_in(kb, vb) + } - let batch = batch_ptr.load(Ordering::Acquire); - let (num_entries, batch_encoded_size) = unsafe { - (*batch) - .iter_mut() - .try_fold((0u32, 0u64), |(num_entries, size), ent| { - let klen = ent.key.encoded_len(); - let vlen = ent.value.encoded_len(); - crate::utils::check_batch_entry( - klen, - vlen, - self.core.opts.maximum_key_size(), - self.core.opts.maximum_value_size(), - )?; - let merged_len = merge_lengths(klen as u32, vlen as u32); - let merged_len_size = encoded_u64_varint_len(merged_len); - - let ent_size = klen as u64 + vlen as u64 + merged_len_size as u64; - ent.meta = BatchEncodedEntryMeta::new(klen, vlen, merged_len, merged_len_size); - Ok((num_entries + 1, size + ent_size)) - }) - .map_err(Among::Right)? - }; + /// Inserts a key-value pair into the WAL. This method + /// allows the caller to build the value in place. + /// + /// This method is useful when playing with `?Sized` value types. See details in the example. + /// + /// ## Safety + /// - The bytes written to the buffer must be valid to decode by [`V::from_slice`](TypeRef::from_slice). + /// + /// ## Example + /// + /// See [`examples/generic_not_sized.rs`](https://github.com/al8n/orderwal/tree/main/examples/generic_not_sized.rs). + #[inline] + pub unsafe fn insert_with_value_builder<'a, E>( + &mut self, + key: impl Into>, + vb: ValueBuilder) -> Result<(), E> + 'a>, + ) -> Result<(), Among> + where + GenericPointer: 'static, + { + let key: Generic<'_, K> = key.into(); + let klen = key.encoded_len() as u32; + let kb: KeyBuilder<_> = KeyBuilder::once(klen, |buf| { + buf.set_len(klen as usize); + key.encode(buf).map(|_| ()) + }); + + self.insert_in::(kb, vb) + } - // safe to cast batch_encoded_size to u32 here, we already checked it's less than capacity (less than u32::MAX). - let batch_meta = merge_lengths(num_entries, batch_encoded_size as u32); - let batch_meta_size = encoded_u64_varint_len(batch_meta); - let allocator = self.allocator(); - let remaining = allocator.remaining() as u64; - let total_size = - STATUS_SIZE as u64 + batch_meta_size as u64 + batch_encoded_size + CHECKSUM_SIZE as u64; - if total_size > remaining { - return Err(Among::Right(Error::insufficient_space( - total_size, - remaining as u32, - ))); - } + /// Inserts a key-value pair into the WAL. This method + /// allows the caller to build the key and value in place. + /// + /// This method is useful when playing with `?Sized` key and value types. See details in the example. + /// + /// ## Safety + /// - The bytes written to the buffer must be valid to decode by [`K::from_slice`](TypeRef::from_slice) + /// and [`V::from_slice`](TypeRef::from_slice) respectively. + /// + /// ## Example + /// + /// See [`examples/generic_not_sized.rs`](https://github.com/al8n/orderwal/tree/main/examples/generic_not_sized.rs). + #[inline] + pub unsafe fn insert_with_builders<'a, KE, VE>( + &mut self, + kb: KeyBuilder) -> Result<(), KE> + 'a>, + vb: ValueBuilder) -> Result<(), VE> + 'a>, + ) -> Result<(), Among> + where + GenericPointer: 'static, + { + self.insert_in(kb, vb) + } - let mut buf = allocator - .alloc_bytes(total_size as u32) - .map_err(|e| Among::Right(Error::from_insufficient_space(e)))?; + /// Inserts a batch of entries into the write-ahead log. + pub fn insert_batch_with_key_builder<'a, B>( + &'a mut self, + batch: &'a mut B, + ) -> Result<(), Among> + where + B: BatchWithKeyBuilder, Value = Generic<'a, V>>, + GenericPointer: 'static, + { + unsafe { + process_batch!(self( + batch, + |ptr, ent: &EntryWithKeyBuilder, _>| { + let f = ent.kb.builder(); + f(&mut VacantBuffer::new( + ent.meta.klen, + NonNull::new_unchecked(ptr), + )) + .map_err(Among::Left) + }, + |ptr, ent: &EntryWithKeyBuilder, _>| { + let value_buf = slice::from_raw_parts_mut(ptr, ent.meta.vlen); + ent.value.encode(value_buf).map_err(Among::Middle) + } + )) + } + } + /// Inserts a batch of entries into the write-ahead log. + pub fn insert_batch_with_value_builder<'a, B>( + &'a mut self, + batch: &'a mut B, + ) -> Result<(), Among> + where + B: BatchWithValueBuilder, Key = Generic<'a, K>>, + GenericPointer: 'static, + { unsafe { - let committed_flag = Flags::BATCHING | Flags::COMMITTED; - let mut cks = self.core.cks.build_checksumer(); - let flag = Flags::BATCHING; - buf.put_u8_unchecked(flag.bits); - buf.put_u64_varint_unchecked(batch_meta); - let mut cursor = STATUS_SIZE + batch_meta_size; - - { - let batch = batch_ptr.load(Ordering::Acquire); - for ent in (*batch).iter_mut() { - let remaining = buf.remaining(); - if remaining < ent.meta.kvlen_size + ent.meta.klen + ent.meta.vlen { - return Err(Among::Right(Error::larger_batch_size(total_size as u32))); - } + process_batch!(self( + batch, + |ptr, ent: &EntryWithValueBuilder, B::ValueBuilder, _>| { + let key_buf = slice::from_raw_parts_mut(ptr, ent.meta.klen); + ent.key.encode(key_buf).map_err(Among::Left) + }, + |ptr, ent: &EntryWithValueBuilder, B::ValueBuilder, _>| { + let f = ent.vb.builder(); + f(&mut VacantBuffer::new( + ent.meta.vlen, + NonNull::new_unchecked(ptr), + )) + .map_err(Among::Middle) + } + )) + } + } - let ent_len_size = buf.put_u64_varint_unchecked(ent.meta.kvlen); - let ko = cursor as usize + ent_len_size; - buf.set_len(ko + ent.meta.klen + ent.meta.vlen); - let ptr = buf.as_mut_ptr().add(ko); + /// Inserts a batch of entries into the write-ahead log. + pub fn insert_batch_with_builders<'a, B>( + &'a mut self, + batch: &'a mut B, + ) -> Result<(), Among> + where + B: BatchWithBuilders>, + GenericPointer: 'static, + { + unsafe { + process_batch!(self( + batch, + |ptr, ent: &EntryWithBuilders| { + let f = ent.kb.builder(); + f(&mut VacantBuffer::new( + ent.meta.klen, + NonNull::new_unchecked(ptr), + )) + .map_err(Among::Left) + }, + |ptr, ent: &EntryWithBuilders| { + let f = ent.vb.builder(); + f(&mut VacantBuffer::new( + ent.meta.vlen, + NonNull::new_unchecked(ptr), + )) + .map_err(Among::Middle) + } + )) + } + } + /// Inserts a batch of entries into the write-ahead log. + pub fn insert_batch<'a, 'b: 'a, B: GenericBatch<'b, Key = K, Value = V>>( + &'a mut self, + batch: &'b mut B, + ) -> Result<(), Among> + where + GenericPointer: 'static, + { + unsafe { + process_batch!(self( + batch, + |ptr, ent: &GenericEntry<'_, K, V>| { let key_buf = slice::from_raw_parts_mut(ptr, ent.meta.klen); - ent.key.encode(key_buf).map_err(Among::Left)?; - let value_buf = slice::from_raw_parts_mut(ptr.add(ent.meta.klen), ent.meta.vlen); - ent.value.encode(value_buf).map_err(Among::Middle)?; - - cursor += ent_len_size + ent.meta.klen + ent.meta.vlen; - ent.pointer = Some(GenericPointer::new(ent.meta.klen, ent.meta.vlen, ptr)); + ent.key.encode(key_buf).map_err(Among::Left) + }, + |ptr, ent: &GenericEntry<'_, K, V>| { + let value_buf = slice::from_raw_parts_mut(ptr, ent.meta.vlen); + ent.value.encode(value_buf).map_err(Among::Middle) } - } + )) + } + } - if (cursor + CHECKSUM_SIZE) as u64 != total_size { - return Err(Among::Right(Error::batch_size_mismatch( - total_size as u32 - CHECKSUM_SIZE as u32, - cursor as u32, - ))); - } + unsafe fn insert_batch_helper<'a, I>( + &'a self, + allocator: &'a Arena, + mut buf: BytesRefMut<'a, Arena>, + cursor: usize, + on_success: impl FnOnce() -> I, + ) -> Result<(), Error> + where + GenericPointer: 'static, + I: Iterator>, + S: BuildChecksumer, + { + let total_size = buf.capacity(); + if cursor + CHECKSUM_SIZE != total_size { + return Err(Error::batch_size_mismatch( + total_size as u32 - CHECKSUM_SIZE as u32, + cursor as u32, + )); + } - cks.update(&[committed_flag.bits]); - cks.update(&buf[1..]); - let checksum = cks.digest(); - buf.put_u64_le_unchecked(checksum); + let mut cks = self.core.cks.build_checksumer(); + let committed_flag = Flags::BATCHING | Flags::COMMITTED; + cks.update(&[committed_flag.bits]); + cks.update(&buf[1..]); + let checksum = cks.digest(); + buf.put_u64_le_unchecked(checksum); - // commit the entry - buf[0] = committed_flag.bits; - let buf_cap = buf.capacity(); + // commit the entry + buf[0] = committed_flag.bits; + let buf_cap = buf.capacity(); - if self.core.opts.sync() && allocator.is_ondisk() { - allocator - .flush_header_and_range(buf.offset(), buf_cap) - .map_err(|e| Among::Right(e.into()))?; - } - buf.detach(); + if self.core.opts.sync() && allocator.is_ondisk() { + allocator.flush_header_and_range(buf.offset(), buf_cap)?; + } + buf.detach(); - { - let batch = batch_ptr.load(Ordering::Acquire); - (*batch).iter_mut().for_each(|ent| { - self.core.map.insert(ent.pointer.take().unwrap()); - }); - } + on_success().for_each(|p| { + self.core.map.insert(p); + }); - Ok(()) - } + Ok(()) } - fn insert_in( + fn insert_in( &self, - key: Generic<'_, K>, - val: Generic<'_, V>, - ) -> Result<(), Among> { - let klen = key.encoded_len(); - let vlen = val.encoded_len(); + kb: KeyBuilder) -> Result<(), KE>>, + vb: ValueBuilder) -> Result<(), VE>>, + ) -> Result<(), Among> + where + GenericPointer: 'static, + { + let (klen, kb) = kb.into_components(); + let (vlen, vb) = vb.into_components(); + + let klen = klen as usize; + let vlen = vlen as usize; self.check(klen, vlen).map_err(Among::Right)?; @@ -887,12 +1130,14 @@ where let ko = STATUS_SIZE + written; buf.set_len(ko + klen + vlen); - let key_buf = slice::from_raw_parts_mut(buf.as_mut_ptr().add(ko), klen); - key.encode(key_buf).map_err(Among::Left)?; + let kptr = NonNull::new_unchecked(buf.as_mut_ptr().add(ko)); + let mut key_buf = VacantBuffer::new(klen, kptr); + kb(&mut key_buf).map_err(Among::Left)?; let vo = STATUS_SIZE + written + klen; - let value_buf = slice::from_raw_parts_mut(buf.as_mut_ptr().add(vo), vlen); - val.encode(value_buf).map_err(Among::Middle)?; + let vptr = NonNull::new_unchecked(buf.as_mut_ptr().add(vo)); + let mut value_buf = VacantBuffer::new(vlen, vptr); + vb(&mut value_buf).map_err(Among::Middle)?; let cks = { cks.update(&buf[1..]); diff --git a/src/swmr/generic/builder.rs b/src/swmr/generic/builder.rs index 269b5c5..b44ea44 100644 --- a/src/swmr/generic/builder.rs +++ b/src/swmr/generic/builder.rs @@ -729,7 +729,10 @@ impl GenericBuilder { /// let reader = unsafe { GenericBuilder::new().map::(path).unwrap() }; /// ``` #[inline] - pub unsafe fn map>(self, path: P) -> Result, Error> + pub unsafe fn map>( + self, + path: P, + ) -> Result, Error> where K: Type + Ord + ?Sized + 'static, for<'a> K::Ref<'a>: KeyRef<'a, K>, @@ -777,7 +780,7 @@ impl GenericBuilder { pub unsafe fn map_with_path_builder( self, path_builder: PB, - ) -> Result, Either> + ) -> Result, Either> where K: Type + Ord + ?Sized + 'static, for<'a> K::Ref<'a>: KeyRef<'a, K>, @@ -793,7 +796,7 @@ impl GenericBuilder { .map_err(|e| e.map_right(Into::into)) .and_then(|arena| { GenericOrderWal::replay(arena, opts, true, (), cks) - .map(|core| GenericWalReader::new(Arc::new(core))) + .map(|core| GenericOrderWalReader::new(Arc::new(core))) .map_err(Either::Right) }) } diff --git a/src/swmr/generic/iter.rs b/src/swmr/generic/iter.rs index a11b91f..f7401bb 100644 --- a/src/swmr/generic/iter.rs +++ b/src/swmr/generic/iter.rs @@ -2,18 +2,12 @@ use core::ops::Bound; use crossbeam_skiplist::Comparable; -use super::{GenericEntryRef, GenericPointer as Pointer, KeyRef, Owned, Ref, Type}; +use super::{GenericEntryRef, GenericPointer as Pointer, KeyRef, Query, Type}; -type SetRefRange<'a, Q, K, V> = crossbeam_skiplist::set::Range< - 'a, - Ref<'a, K, Q>, - (Bound>, Bound>), - Pointer, ->; type SetRange<'a, Q, K, V> = crossbeam_skiplist::set::Range< 'a, - Owned<'a, K, Q>, - (Bound>, Bound>), + Query<'a, K, Q>, + (Bound>, Bound>), Pointer, >; @@ -37,7 +31,7 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> where K: Type + Ord + ?Sized, for<'b> K::Ref<'b>: KeyRef<'b, K>, - V: ?Sized, + V: ?Sized + Type, { type Item = GenericEntryRef<'a, K, V>; @@ -56,59 +50,7 @@ impl DoubleEndedIterator for Iter<'_, K, V> where K: Type + Ord + ?Sized, for<'b> K::Ref<'b>: KeyRef<'b, K>, - V: ?Sized, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(|ptr| GenericEntryRef::new(ptr)) - } -} - -/// An iterator over a subset of the entries in the WAL. -pub struct RefRange<'a, Q, K, V> -where - K: Type + Ord + ?Sized, - for<'b> K::Ref<'b>: KeyRef<'b, K>, - V: ?Sized, - Q: Ord + ?Sized + Comparable>, -{ - iter: SetRefRange<'a, Q, K, V>, -} - -impl<'a, Q, K, V> RefRange<'a, Q, K, V> -where - K: Type + Ord + ?Sized, - for<'b> K::Ref<'b>: KeyRef<'b, K>, - V: ?Sized, - Q: Ord + ?Sized + Comparable>, -{ - #[inline] - pub(super) fn new(iter: SetRefRange<'a, Q, K, V>) -> Self { - Self { iter } - } -} - -impl<'a, Q, K, V> Iterator for RefRange<'a, Q, K, V> -where - K: Type + Ord + ?Sized, - for<'b> K::Ref<'b>: KeyRef<'b, K>, - Q: Ord + ?Sized + Comparable>, - V: ?Sized, -{ - type Item = GenericEntryRef<'a, K, V>; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|ptr| GenericEntryRef::new(ptr)) - } -} - -impl<'a, Q, K, V> DoubleEndedIterator for RefRange<'a, Q, K, V> -where - K: Type + Ord + ?Sized, - for<'b> K::Ref<'b>: KeyRef<'b, K>, - V: ?Sized, - Q: Ord + ?Sized + Comparable>, + V: ?Sized + Type, { #[inline] fn next_back(&mut self) -> Option { @@ -122,7 +64,7 @@ where K: Type + Ord + ?Sized, for<'b> K::Ref<'b>: KeyRef<'b, K>, V: ?Sized, - Q: Ord + ?Sized + Comparable> + Comparable, + Q: Ord + ?Sized + for<'b> Comparable>, { iter: SetRange<'a, Q, K, V>, } @@ -132,7 +74,7 @@ where K: Type + Ord + ?Sized, for<'b> K::Ref<'b>: KeyRef<'b, K>, V: ?Sized, - Q: Ord + ?Sized + Comparable> + Comparable, + Q: Ord + ?Sized + for<'b> Comparable>, { #[inline] pub(super) fn new(iter: SetRange<'a, Q, K, V>) -> Self { @@ -144,8 +86,8 @@ impl<'a, Q, K, V> Iterator for Range<'a, Q, K, V> where K: Type + Ord + ?Sized, for<'b> K::Ref<'b>: KeyRef<'b, K>, - V: ?Sized, - Q: Ord + ?Sized + Comparable> + Comparable, + V: ?Sized + Type, + Q: Ord + ?Sized + for<'b> Comparable>, { type Item = GenericEntryRef<'a, K, V>; @@ -155,12 +97,12 @@ where } } -impl<'a, Q, K, V> DoubleEndedIterator for Range<'a, Q, K, V> +impl DoubleEndedIterator for Range<'_, Q, K, V> where K: Type + Ord + ?Sized, for<'b> K::Ref<'b>: KeyRef<'b, K>, - V: ?Sized, - Q: Ord + ?Sized + Comparable> + Comparable, + V: ?Sized + Type, + Q: Ord + ?Sized + for<'b> Comparable>, { #[inline] fn next_back(&mut self) -> Option { diff --git a/src/swmr/generic/reader.rs b/src/swmr/generic/reader.rs index 7ef7d23..8989c59 100644 --- a/src/swmr/generic/reader.rs +++ b/src/swmr/generic/reader.rs @@ -4,14 +4,12 @@ use std::sync::Arc; use dbutils::equivalent::Comparable; use rarena_allocator::Allocator; -use super::{ - GenericEntryRef, GenericOrderWalCore, Iter, KeyRef, Range, RefRange, Type, HEADER_SIZE, -}; +use super::{GenericEntryRef, GenericOrderWalCore, Iter, KeyRef, Range, Type, HEADER_SIZE}; /// A read-only view of a generic single-writer, multi-reader WAL. -pub struct GenericWalReader(Arc>); +pub struct GenericOrderWalReader(Arc>); -impl Clone for GenericWalReader +impl Clone for GenericOrderWalReader where K: ?Sized, V: ?Sized, @@ -21,7 +19,7 @@ where } } -impl GenericWalReader +impl GenericOrderWalReader where K: ?Sized, V: ?Sized, @@ -63,7 +61,7 @@ where } } -impl GenericWalReader +impl GenericOrderWalReader where K: Type + Ord + ?Sized, for<'a> K::Ref<'a>: KeyRef<'a, K>, @@ -71,13 +69,19 @@ where { /// Returns the first key-value pair in the map. The key in this pair is the minimum key in the wal. #[inline] - pub fn first(&self) -> Option> { + pub fn first(&self) -> Option> + where + V: Type, + { self.0.first() } /// Returns the last key-value pair in the map. The key in this pair is the maximum key in the wal. #[inline] - pub fn last(&self) -> Option> { + pub fn last(&self) -> Option> + where + V: Type, + { self.0.last() } @@ -87,19 +91,6 @@ where self.0.iter() } - /// Returns an iterator over a subset of the entries in the WAL. - #[inline] - pub fn range_by_ref<'a, Q>( - &'a self, - start_bound: Bound<&'a Q>, - end_bound: Bound<&'a Q>, - ) -> RefRange<'a, Q, K, V> - where - Q: Ord + ?Sized + Comparable>, - { - self.0.range_by_ref(start_bound, end_bound) - } - /// Returns an iterator over a subset of the entries in the WAL. #[inline] pub fn range<'a, Q>( @@ -108,69 +99,115 @@ where end_bound: Bound<&'a Q>, ) -> Range<'a, Q, K, V> where - Q: Ord + ?Sized + Comparable + Comparable>, + Q: Ord + ?Sized + for<'b> Comparable>, { self.0.range(start_bound, end_bound) } } -impl GenericWalReader +impl GenericOrderWalReader where K: Type + Ord + ?Sized, for<'a> K::Ref<'a>: KeyRef<'a, K>, - V: Type + ?Sized, + V: ?Sized, { /// Returns `true` if the key exists in the WAL. #[inline] - pub fn contains_key<'a, Q>(&'a self, key: &'a Q) -> bool + pub fn contains_key<'a, Q>(&'a self, key: &Q) -> bool where - Q: ?Sized + Ord + Comparable> + Comparable, + Q: ?Sized + Ord + Comparable>, { self.0.contains_key(key) } /// Returns `true` if the key exists in the WAL. + /// + /// ## Safety + /// - The given `key` must be valid to construct to `K::Ref` without remaining. + #[inline] + pub unsafe fn contains_key_by_bytes(&self, key: &[u8]) -> bool { + self.0.contains_key_by_bytes(key) + } + + /// Gets the value associated with the key. #[inline] - pub fn contains_key_by_ref<'a, Q>(&'a self, key: &'a Q) -> bool + pub fn get<'a, Q>(&'a self, key: &Q) -> Option> where Q: ?Sized + Ord + Comparable>, + V: Type, { - self.0.contains_key_by_ref(key) + self.0.get(key) } - /// Returns `true` if the key exists in the WAL. + /// Gets the value associated with the key. /// /// ## Safety /// - The given `key` must be valid to construct to `K::Ref` without remaining. #[inline] - pub unsafe fn contains_key_by_bytes(&self, key: &[u8]) -> bool { - self.0.contains_key_by_bytes(key) + pub unsafe fn get_by_bytes(&self, key: &[u8]) -> Option> + where + V: Type, + { + self.0.get_by_bytes(key) } - /// Gets the value associated with the key. + /// Returns a value associated to the highest element whose key is below the given bound. + /// If no such element is found then `None` is returned. #[inline] - pub fn get<'a, Q>(&'a self, key: &'a Q) -> Option> + pub fn upper_bound<'a, 'b: 'a, Q>( + &'a self, + bound: Bound<&'b Q>, + ) -> Option> where - Q: ?Sized + Ord + Comparable> + Comparable, + Q: ?Sized + Ord + Comparable>, + V: Type, { - self.0.get(key) + self.0.upper_bound(bound) } - /// Gets the value associated with the key. + /// Returns a value associated to the highest element whose key is below the given bound. + /// If no such element is found then `None` is returned. + /// + /// ## Safety + /// - The given `key` in `Bound` must be valid to construct to `K::Ref` without remaining. #[inline] - pub fn get_by_ref<'a, Q>(&'a self, key: &'a Q) -> Option> + pub unsafe fn upper_bound_by_bytes( + &self, + bound: Bound<&[u8]>, + ) -> Option> where - Q: ?Sized + Ord + Comparable>, + V: Type, { - self.0.get_by_ref(key) + self.0.upper_bound_by_bytes(bound) } - /// Gets the value associated with the key. + /// Returns a value associated to the lowest element whose key is above the given bound. + /// If no such element is found then `None` is returned. + #[inline] + pub fn lower_bound<'a, 'b: 'a, Q>( + &'a self, + bound: Bound<&'b Q>, + ) -> Option> + where + Q: ?Sized + Ord + Comparable>, + V: Type, + { + self.0.lower_bound(bound) + } + + /// Returns a value associated to the lowest element whose key is above the given bound. + /// If no such element is found then `None` is returned. /// /// ## Safety - /// - The given `key` must be valid to construct to `K::Ref` without remaining. + /// - The given `key` in `Bound` must be valid to construct to `K::Ref` without remaining. #[inline] - pub unsafe fn get_by_bytes(&self, key: &[u8]) -> Option> { - self.0.get_by_bytes(key) + pub unsafe fn lower_bound_by_bytes( + &self, + bound: Bound<&[u8]>, + ) -> Option> + where + V: Type, + { + self.0.lower_bound_by_bytes(bound) } } diff --git a/src/swmr/generic/tests.rs b/src/swmr/generic/tests.rs index 11d08f3..76e812f 100644 --- a/src/swmr/generic/tests.rs +++ b/src/swmr/generic/tests.rs @@ -113,7 +113,7 @@ impl Comparable> for Person { } } -impl<'a> KeyRef<'a, Person> for PersonRef<'a> { +impl KeyRef<'_, Person> for PersonRef<'_> { fn compare(&self, a: &Q) -> cmp::Ordering where Q: ?Sized + Ord + Comparable, diff --git a/src/swmr/generic/tests/constructor.rs b/src/swmr/generic/tests/constructor.rs index e6946a5..f51bc1c 100644 --- a/src/swmr/generic/tests/constructor.rs +++ b/src/swmr/generic/tests/constructor.rs @@ -2,7 +2,7 @@ use super::*; #[test] #[allow(clippy::needless_borrows_for_generic_args)] -fn owned_comparable() { +fn query_comparable() { let p1 = Person { id: 3127022870678870148, name: "enthusiastic-magic".into(), @@ -22,11 +22,11 @@ fn owned_comparable() { map.insert(ptr1); map.insert(ptr2); - assert!(map.contains(&Owned::new(&p1))); - assert!(map.get(&Owned::new(&p1)).is_some()); + assert!(map.contains(&Query::new(&p1))); + assert!(map.get(&Query::new(&p1)).is_some()); - assert!(map.contains(&Owned::new(&p2))); - assert!(map.get(&Owned::new(&p2)).is_some()); + assert!(map.contains(&Query::new(&p2))); + assert!(map.get(&Query::new(&p2)).is_some()); let mut wal = GenericBuilder::new() .with_capacity(MB) @@ -42,74 +42,6 @@ fn owned_comparable() { assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); } -#[test] -fn ref_comparable() { - let p1 = PersonRef { - id: 3127022870678870148, - name: "enthusiastic-magic", - }; - let p2 = PersonRef { - id: 9872687799307360216, - name: "damaged-friend", - }; - - let p1bytes = p1.encode_into_vec().unwrap(); - let p2bytes = p2.encode_into_vec().unwrap(); - - let ptr1 = GenericPointer::::new(p1bytes.len(), 0, p1bytes.as_ptr()); - let ptr2 = GenericPointer::::new(p2bytes.len(), 0, p2bytes.as_ptr()); - - let map = SkipSet::new(); - map.insert(ptr1); - map.insert(ptr2); - - assert!(map.contains(&Owned::new(&p1))); - assert!(map.get(&Owned::new(&p1)).is_some()); - - assert!(map.contains(&Owned::new(&p2))); - assert!(map.get(&Owned::new(&p2)).is_some()); - - let mut wal = GenericBuilder::new() - .with_capacity(MB) - .alloc::() - .unwrap(); - - unsafe { - wal - .insert( - Generic::from_slice(p1bytes.as_ref()), - &"My name is Alice!".to_string(), - ) - .unwrap(); - wal - .insert( - Generic::from_slice(p2bytes.as_ref()), - &"My name is Bob!".to_string(), - ) - .unwrap(); - } - - assert!(wal.contains_key(&p1)); - assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); - - assert!(wal.contains_key(&p2)); - assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); - - assert!(wal.contains_key_by_ref(&p1)); - assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); - - assert!(wal.contains_key_by_ref(&p2)); - assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); - - unsafe { - assert!(wal.contains_key_by_bytes(&p1bytes)); - assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); - - assert!(wal.contains_key_by_bytes(&p2bytes)); - assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); - } -} - #[test] #[allow(clippy::needless_borrows_for_generic_args)] fn construct_inmemory() { diff --git a/src/swmr/generic/tests/get.rs b/src/swmr/generic/tests/get.rs index 4a0db16..3ad2ebb 100644 --- a/src/swmr/generic/tests/get.rs +++ b/src/swmr/generic/tests/get.rs @@ -134,7 +134,6 @@ fn get_or_insert(wal: &mut GenericOrderWal) { for (p, pv) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); assert_eq!( wal @@ -147,7 +146,6 @@ fn get_or_insert(wal: &mut GenericOrderWal) { for (p, _) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); } } @@ -205,7 +203,6 @@ fn get_or_insert_with(wal: &mut GenericOrderWal) { for (p, pv) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); assert_eq!( wal .get_or_insert_with(p, || (&format!("Hello! {}!", p.name)).into()) @@ -217,7 +214,7 @@ fn get_or_insert_with(wal: &mut GenericOrderWal) { for (p, _) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); + assert!(wal.contains_key(&p.as_ref())); } } @@ -279,7 +276,6 @@ fn get_or_insert_key_with_value_bytes(wal: &mut GenericOrderWal) for (p, pv) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); assert_eq!( wal @@ -292,7 +288,6 @@ fn get_or_insert_key_with_value_bytes(wal: &mut GenericOrderWal) for (p, _) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); } } @@ -354,7 +349,7 @@ fn get_or_insert_value_bytes(wal: &mut GenericOrderWal) { for (p, pv) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); + assert!(wal.contains_key(&p.as_ref())); unsafe { assert_eq!( wal @@ -368,7 +363,6 @@ fn get_or_insert_value_bytes(wal: &mut GenericOrderWal) { for (p, _) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); } } @@ -431,7 +425,6 @@ fn get_by_bytes_or_insert_with(wal: &mut GenericOrderWal) { for (p, pvec, pv) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); unsafe { assert_eq!( wal @@ -445,7 +438,6 @@ fn get_by_bytes_or_insert_with(wal: &mut GenericOrderWal) { for (p, _, _) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); } } @@ -511,7 +503,6 @@ fn get_by_bytes_or_insert_bytes(wal: &mut GenericOrderWal) { for (p, pvec, pv) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); unsafe { assert_eq!( wal @@ -528,7 +519,6 @@ fn get_by_bytes_or_insert_bytes(wal: &mut GenericOrderWal) { for (p, _, _) in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); } } diff --git a/src/swmr/generic/tests/insert.rs b/src/swmr/generic/tests/insert.rs index 0f9b21a..c432a49 100644 --- a/src/swmr/generic/tests/insert.rs +++ b/src/swmr/generic/tests/insert.rs @@ -63,10 +63,9 @@ fn insert(wal: &mut GenericOrderWal) -> Vec { for p in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); assert_eq!( wal.get(p).unwrap().value(), - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); } @@ -116,10 +115,257 @@ fn insert_map_file() { for p in people { assert!(wal.contains_key(&p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); assert_eq!( wal.get(&p).unwrap().value(), - format!("My name is {}", p.name) + &format!("My name is {}", p.name) + ); + } +} + +fn insert_with_key_builder(wal: &mut GenericOrderWal) -> Vec { + let people = (0..100) + .map(|_| unsafe { + let p = Person::random(); + wal + .insert_with_key_builder( + KeyBuilder::new(p.encoded_len() as u32, |buf: &mut VacantBuffer<'_>| { + buf.set_len(p.encoded_len()); + p.encode(buf).map(|_| ()) + }), + &format!("My name is {}", p.name), + ) + .unwrap(); + p + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for p in &people { + assert!(wal.contains_key(p)); + assert_eq!( + wal.get(p).unwrap().value(), + &format!("My name is {}", p.name) + ); + } + + people +} + +#[test] +fn insert_with_key_builder_inmemory() { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .alloc::() + .unwrap(); + insert_with_key_builder(&mut wal); +} + +#[test] +fn insert_with_key_builder_map_anon() { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .map_anon::() + .unwrap(); + insert_with_key_builder(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn insert_with_key_builder_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_insert_with_key_builder_map_file"); + + let people = unsafe { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) + .unwrap(); + insert_with_key_builder(&mut wal) + }; + + let wal = unsafe { + GenericBuilder::new() + .map::(&path) + .unwrap() + }; + + for p in people { + assert!(wal.contains_key(&p)); + assert_eq!( + wal.get(&p).unwrap().value(), + &format!("My name is {}", p.name) + ); + } +} + +fn insert_with_value_builder(wal: &mut GenericOrderWal) -> Vec { + let people = (0..100) + .map(|_| unsafe { + let p = Person::random(); + let v = format!("My name is {}", p.name); + + wal + .insert_with_value_builder( + &p, + ValueBuilder::new(v.len() as u32, |buf: &mut VacantBuffer<'_>| { + buf.put_slice(v.as_bytes()) + }), + ) + .unwrap(); + p + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for p in &people { + assert!(wal.contains_key(p)); + assert_eq!( + wal.get(p).unwrap().value(), + &format!("My name is {}", p.name) + ); + } + + people +} + +#[test] +fn insert_with_value_builder_inmemory() { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .alloc::() + .unwrap(); + insert_with_value_builder(&mut wal); +} + +#[test] +fn insert_with_value_builder_map_anon() { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .map_anon::() + .unwrap(); + insert_with_value_builder(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn insert_with_value_builder_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_insert_with_value_builder_map_file"); + + let people = unsafe { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) + .unwrap(); + insert_with_value_builder(&mut wal) + }; + + let wal = unsafe { + GenericBuilder::new() + .map::(&path) + .unwrap() + }; + + for p in people { + assert!(wal.contains_key(&p)); + assert_eq!( + wal.get(&p).unwrap().value(), + &format!("My name is {}", p.name) + ); + } +} + +fn insert_with_builders(wal: &mut GenericOrderWal) -> Vec { + let people = (0..100) + .map(|_| unsafe { + let p = Person::random(); + let v = format!("My name is {}", p.name); + wal + .insert_with_builders( + KeyBuilder::new(p.encoded_len() as u32, |buf: &mut VacantBuffer<'_>| { + buf.set_len(p.encoded_len()); + p.encode(buf).map(|_| ()) + }), + ValueBuilder::new(v.len() as u32, |buf: &mut VacantBuffer<'_>| { + buf.put_slice(v.as_bytes()) + }), + ) + .unwrap(); + p + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for p in &people { + assert!(wal.contains_key(p)); + assert_eq!( + wal.get(p).unwrap().value(), + &format!("My name is {}", p.name) + ); + } + + people +} + +#[test] +fn insert_with_builders_inmemory() { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .alloc::() + .unwrap(); + insert_with_builders(&mut wal); +} + +#[test] +fn insert_with_builders_map_anon() { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .map_anon::() + .unwrap(); + insert_with_builders(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn insert_with_builders_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_insert_with_builders_map_file"); + + let people = unsafe { + let mut wal = GenericBuilder::new() + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) + .unwrap(); + insert_with_builders(&mut wal) + }; + + let wal = unsafe { + GenericBuilder::new() + .map::(&path) + .unwrap() + }; + + for p in people { + assert!(wal.contains_key(&p)); + assert_eq!( + wal.get(&p).unwrap().value(), + &format!("My name is {}", p.name) ); } } @@ -152,12 +398,12 @@ fn insert_key_bytes_with_value( } assert_eq!( wal.get(p).unwrap().value(), - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); assert_eq!( unsafe { wal.get_by_bytes(pbytes).unwrap().value() }, - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); } @@ -210,11 +456,11 @@ fn insert_key_bytes_with_value_map_file() { } assert_eq!( wal.get(p).unwrap().value(), - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); assert_eq!( unsafe { wal.get_by_bytes(pbytes).unwrap().value() }, - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); } @@ -231,11 +477,11 @@ fn insert_key_bytes_with_value_map_file() { } assert_eq!( wal.get(&p).unwrap().value(), - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); assert_eq!( unsafe { wal.get_by_bytes(&pbytes).unwrap().value() }, - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); } } @@ -260,10 +506,9 @@ fn insert_key_with_value_bytes(wal: &mut GenericOrderWal) -> Vec for p in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); assert_eq!( - wal.get_by_ref(p).unwrap().value(), - format!("My name is {}", p.name) + wal.get(p).unwrap().value(), + &format!("My name is {}", p.name) ); } @@ -311,10 +556,9 @@ fn insert_key_with_value_bytes_map_file() { for p in &people { assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); assert_eq!( - wal.get_by_ref(p).unwrap().value(), - format!("My name is {}", p.name) + wal.get(p).unwrap().value(), + &format!("My name is {}", p.name) ); } } @@ -345,7 +589,7 @@ fn insert_bytes(wal: &mut GenericOrderWal) -> Vec { } assert_eq!( wal.get(p).unwrap().value(), - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); } @@ -397,7 +641,7 @@ fn insert_bytes_map_file() { } assert_eq!( wal.get(p).unwrap().value(), - format!("My name is {}", p.name) + &format!("My name is {}", p.name) ); } } @@ -408,8 +652,8 @@ fn concurrent_basic(mut w: GenericOrderWal) { let handles = readers.into_iter().map(|(i, reader)| { spawn(move || loop { if let Some(p) = reader.get(&i) { - assert_eq!(p.key(), i); - assert_eq!(p.value(), i.to_le_bytes()); + assert_eq!(p.key(), &i); + assert_eq!(p.value(), &i.to_le_bytes()); break; } }) @@ -469,8 +713,8 @@ fn concurrent_one_key(mut w: GenericOrderWal) { let handles = readers.into_iter().map(|(_, reader)| { spawn(move || loop { if let Some(p) = reader.get(&1) { - assert_eq!(p.key(), 1); - assert_eq!(p.value(), 1u32.to_le_bytes()); + assert_eq!(p.key(), &1); + assert_eq!(p.value(), &1u32.to_le_bytes()); break; } }) @@ -613,7 +857,302 @@ fn test_insert_batch_map_file() { }; for (p, val) in data { - assert_eq!(map.get(&p).unwrap().value(), val); + assert_eq!(map.get(&p).unwrap().value(), &val); + } + assert_eq!(map.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(map.get(&rp2).unwrap().value(), "rp2"); +} + +fn insert_batch_with_key_builder( + wal: &mut GenericOrderWal, +) -> (Person, Vec<(Person, String)>, Person) { + const N: u32 = 5; + + let mut batch = vec![]; + let output = (0..N) + .map(|i| { + ( + { + let mut p = Person::random(); + p.id = i as u64; + p + }, + format!("My id is {i}"), + ) + .clone() + }) + .collect::>(); + + for (person, val) in output.iter() { + batch.push(EntryWithKeyBuilder::new( + KeyBuilder::new(person.encoded_len() as u32, |buf: &mut VacantBuffer<'_>| { + buf.set_len(person.encoded_len()); + person.encode(buf).map(|_| ()) + }), + Generic::from(val), + )); + } + + let rp1 = Person::random(); + wal.insert(&rp1, &"rp1".to_string()).unwrap(); + wal.insert_batch_with_key_builder(&mut batch).unwrap(); + let rp2 = Person::random(); + wal.insert(&rp2, &"rp2".to_string()).unwrap(); + + for (p, val) in output.iter() { + assert_eq!(wal.get(p).unwrap().value(), val); + } + + assert_eq!(wal.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(wal.get(&rp2).unwrap().value(), "rp2"); + + let wal = wal.reader(); + for (p, val) in output.iter() { + assert_eq!(wal.get(p).unwrap().value(), val); + } + + assert_eq!(wal.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(wal.get(&rp2).unwrap().value(), "rp2"); + + (rp1, output, rp2) +} + +#[test] +fn test_insert_batch_with_key_builder_inmemory() { + insert_batch_with_key_builder(&mut GenericBuilder::new().with_capacity(MB).alloc().unwrap()); +} + +#[test] +fn test_insert_batch_with_key_builder_map_anon() { + insert_batch_with_key_builder(&mut GenericBuilder::new().with_capacity(MB).map_anon().unwrap()); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn test_insert_batch_with_key_builder_map_file() { + let dir = ::tempfile::tempdir().unwrap(); + let path = dir.path().join(concat!( + "test_", + stringify!($prefix), + "_insert_batch_with_key_builder_map_file" + )); + let mut map = unsafe { + GenericBuilder::new() + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) + .unwrap() + }; + + let (rp1, data, rp2) = insert_batch_with_key_builder(&mut map); + + let map = unsafe { + GenericBuilder::new() + .map::(&path) + .unwrap() + }; + + for (p, val) in data { + assert_eq!(map.get(&p).unwrap().value(), &val); + } + assert_eq!(map.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(map.get(&rp2).unwrap().value(), "rp2"); +} + +fn insert_batch_with_value_builder( + wal: &mut GenericOrderWal, +) -> (Person, Vec<(Person, String)>, Person) { + const N: u32 = 5; + + let mut batch = vec![]; + let output = (0..N) + .map(|i| { + ( + { + let mut p = Person::random(); + p.id = i as u64; + p + }, + format!("My id is {i}"), + ) + .clone() + }) + .collect::>(); + + for (person, val) in output.iter() { + batch.push(EntryWithValueBuilder::new( + person.into(), + ValueBuilder::new(val.len() as u32, |buf: &mut VacantBuffer<'_>| { + buf.put_slice(val.as_bytes()) + }), + )); + } + + let rp1 = Person::random(); + wal.insert(&rp1, &"rp1".to_string()).unwrap(); + wal.insert_batch_with_value_builder(&mut batch).unwrap(); + let rp2 = Person::random(); + wal.insert(&rp2, &"rp2".to_string()).unwrap(); + + for (p, val) in output.iter() { + assert_eq!(wal.get(p).unwrap().value(), val); + } + + assert_eq!(wal.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(wal.get(&rp2).unwrap().value(), "rp2"); + + let wal = wal.reader(); + for (p, val) in output.iter() { + assert_eq!(wal.get(p).unwrap().value(), val); + } + + assert_eq!(wal.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(wal.get(&rp2).unwrap().value(), "rp2"); + + (rp1, output, rp2) +} + +#[test] +fn test_insert_batch_with_value_builder_inmemory() { + insert_batch_with_value_builder(&mut GenericBuilder::new().with_capacity(MB).alloc().unwrap()); +} + +#[test] +fn test_insert_batch_with_value_builder_map_anon() { + insert_batch_with_value_builder(&mut GenericBuilder::new().with_capacity(MB).map_anon().unwrap()); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn test_insert_batch_with_value_builder_map_file() { + let dir = ::tempfile::tempdir().unwrap(); + let path = dir.path().join(concat!( + "test_", + stringify!($prefix), + "_insert_batch_with_value_builder_map_file" + )); + let mut map = unsafe { + GenericBuilder::new() + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) + .unwrap() + }; + + let (rp1, data, rp2) = insert_batch_with_value_builder(&mut map); + + let map = unsafe { + GenericBuilder::new() + .map::(&path) + .unwrap() + }; + + for (p, val) in data { + assert_eq!(map.get(&p).unwrap().value(), &val); + } + assert_eq!(map.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(map.get(&rp2).unwrap().value(), "rp2"); +} + +fn insert_batch_with_builders( + wal: &mut GenericOrderWal, +) -> (Person, Vec<(Person, String)>, Person) { + const N: u32 = 5; + + let mut batch = vec![]; + let output = (0..N) + .map(|i| { + ( + { + let mut p = Person::random(); + p.id = i as u64; + p + }, + format!("My id is {i}"), + ) + .clone() + }) + .collect::>(); + + for (person, val) in output.iter() { + batch.push(EntryWithBuilders::new( + KeyBuilder::new(person.encoded_len() as u32, |buf: &mut VacantBuffer<'_>| { + buf.set_len(person.encoded_len()); + person.encode(buf).map(|_| ()) + }), + ValueBuilder::new(val.len() as u32, |buf: &mut VacantBuffer<'_>| { + buf.put_slice(val.as_bytes()) + }), + )); + } + + let rp1 = Person::random(); + wal.insert(&rp1, &"rp1".to_string()).unwrap(); + wal.insert_batch_with_builders(&mut batch).unwrap(); + let rp2 = Person::random(); + wal.insert(&rp2, &"rp2".to_string()).unwrap(); + + for (p, val) in output.iter() { + assert_eq!(wal.get(p).unwrap().value(), val); + } + + assert_eq!(wal.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(wal.get(&rp2).unwrap().value(), "rp2"); + + let wal = wal.reader(); + for (p, val) in output.iter() { + assert_eq!(wal.get(p).unwrap().value(), val); + } + + assert_eq!(wal.get(&rp1).unwrap().value(), "rp1"); + assert_eq!(wal.get(&rp2).unwrap().value(), "rp2"); + + (rp1, output, rp2) +} + +#[test] +fn test_insert_batch_with_builders_inmemory() { + insert_batch_with_builders(&mut GenericBuilder::new().with_capacity(MB).alloc().unwrap()); +} + +#[test] +fn test_insert_batch_with_builders_map_anon() { + insert_batch_with_builders(&mut GenericBuilder::new().with_capacity(MB).map_anon().unwrap()); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn test_insert_batch_with_builders_map_file() { + let dir = ::tempfile::tempdir().unwrap(); + let path = dir.path().join(concat!( + "test_", + stringify!($prefix), + "_insert_batch_with_builders_map_file" + )); + let mut map = unsafe { + GenericBuilder::new() + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut(&path) + .unwrap() + }; + + let (rp1, data, rp2) = insert_batch_with_builders(&mut map); + + let map = unsafe { + GenericBuilder::new() + .map::(&path) + .unwrap() + }; + + for (p, val) in data { + assert_eq!(map.get(&p).unwrap().value(), &val); } assert_eq!(map.get(&rp1).unwrap().value(), "rp1"); assert_eq!(map.get(&rp2).unwrap().value(), "rp2"); diff --git a/src/swmr/generic/tests/iters.rs b/src/swmr/generic/tests/iters.rs index b43ee91..0463eb6 100644 --- a/src/swmr/generic/tests/iters.rs +++ b/src/swmr/generic/tests/iters.rs @@ -15,15 +15,15 @@ fn iter(wal: &mut GenericOrderWal) -> Vec<(Person, String)> { let mut iter = wal.iter(); for (pwal, pvec) in people.iter().zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); + assert!(pwal.0.equivalent(pvec.key())); + assert_eq!(&pwal.1, pvec.value()); } let mut rev_iter = wal.iter().rev(); for (pwal, pvec) in people.iter().rev().zip(rev_iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); + assert!(pwal.0.equivalent(pvec.key())); + assert_eq!(&pwal.1, pvec.value()); } people @@ -69,11 +69,177 @@ fn iter_map_file() { let mut iter = wal.iter(); for (pwal, pvec) in people.iter().zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); + assert!(pwal.0.equivalent(pvec.key())); + assert_eq!(&pwal.1, pvec.value()); } } +fn bounds(wal: &mut GenericOrderWal) { + for i in 0..100u32 { + wal.insert(&i, &i).unwrap(); + } + + let upper50 = wal.upper_bound(Bound::Included(&50u32)).unwrap(); + assert_eq!(upper50.value(), &50u32); + let upper51 = wal.upper_bound(Bound::Excluded(&51u32)).unwrap(); + assert_eq!(upper51.value(), &50u32); + + let upper50 = unsafe { + wal + .upper_bound_by_bytes(Bound::Included(50u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(upper50.value(), &50u32); + let upper51 = unsafe { + wal + .upper_bound_by_bytes(Bound::Excluded(51u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(upper51.value(), &50u32); + + let upper101 = wal.upper_bound(Bound::Included(&101u32)).unwrap(); + assert_eq!(upper101.value(), &99u32); + let upper101 = unsafe { + wal + .upper_bound_by_bytes(Bound::Included(101u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(upper101.value(), &99u32); + + let upper_unbounded = wal.upper_bound::(Bound::Unbounded).unwrap(); + assert_eq!(upper_unbounded.value(), &99u32); + let upper_unbounded = unsafe { wal.upper_bound_by_bytes(Bound::Unbounded).unwrap() }; + assert_eq!(upper_unbounded.value(), &99u32); + + let lower50 = wal.lower_bound(Bound::Included(&50u32)).unwrap(); + assert_eq!(lower50.value(), &50u32); + let lower50 = unsafe { + wal + .lower_bound_by_bytes(Bound::Included(50u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(lower50.value(), &50u32); + + let lower51 = wal.lower_bound(Bound::Excluded(&51u32)).unwrap(); + assert_eq!(lower51.value(), &52u32); + let lower51 = unsafe { + wal + .lower_bound_by_bytes(Bound::Excluded(51u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(lower51.value(), &52u32); + + let lower0 = wal.lower_bound(Bound::Excluded(&0u32)).unwrap(); + assert_eq!(lower0.value(), &1u32); + let lower0 = unsafe { + wal + .lower_bound_by_bytes(Bound::Excluded(0u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(lower0.value(), &1u32); + + let lower_unbounded = wal.lower_bound::(Bound::Unbounded).unwrap(); + assert_eq!(lower_unbounded.value(), &0u32); + let lower_unbounded = unsafe { wal.lower_bound_by_bytes(Bound::Unbounded).unwrap() }; + assert_eq!(lower_unbounded.value(), &0u32); + + let wal = wal.reader(); + let upper50 = wal.upper_bound(Bound::Included(&50u32)).unwrap(); + assert_eq!(upper50.value(), &50u32); + let upper50 = unsafe { + wal + .upper_bound_by_bytes(Bound::Included(50u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(upper50.value(), &50u32); + + let upper51 = wal.upper_bound(Bound::Excluded(&51u32)).unwrap(); + assert_eq!(upper51.value(), &50u32); + let upper51 = unsafe { + wal + .upper_bound_by_bytes(Bound::Excluded(51u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(upper51.value(), &50u32); + + let upper101 = wal.upper_bound(Bound::Included(&101u32)).unwrap(); + assert_eq!(upper101.value(), &99u32); + let upper101 = unsafe { + wal + .upper_bound_by_bytes(Bound::Included(101u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(upper101.value(), &99u32); + + let upper_unbounded = wal.upper_bound::(Bound::Unbounded).unwrap(); + assert_eq!(upper_unbounded.value(), &99u32); + let upper_unbounded = unsafe { wal.upper_bound_by_bytes(Bound::Unbounded).unwrap() }; + assert_eq!(upper_unbounded.value(), &99u32); + + let lower50 = wal.lower_bound(Bound::Included(&50u32)).unwrap(); + assert_eq!(lower50.value(), &50u32); + let lower50 = unsafe { + wal + .lower_bound_by_bytes(Bound::Included(50u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(lower50.value(), &50u32); + + let lower51 = wal.lower_bound(Bound::Excluded(&51u32)).unwrap(); + assert_eq!(lower51.value(), &52u32); + let lower51 = unsafe { + wal + .lower_bound_by_bytes(Bound::Excluded(51u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(lower51.value(), &52u32); + + let lower0 = wal.lower_bound(Bound::Excluded(&0u32)).unwrap(); + assert_eq!(lower0.value(), &1u32); + let lower0 = unsafe { + wal + .lower_bound_by_bytes(Bound::Excluded(0u32.to_le_bytes().as_ref())) + .unwrap() + }; + assert_eq!(lower0.value(), &1u32); + + let lower_unbounded = wal.lower_bound::(Bound::Unbounded).unwrap(); + assert_eq!(lower_unbounded.value(), &0u32); + let lower_unbounded = unsafe { wal.lower_bound_by_bytes(Bound::Unbounded).unwrap() }; + assert_eq!(lower_unbounded.value(), &0u32); +} + +#[test] +fn bounds_inmemory() { + let mut wal = GenericBuilder::new().with_capacity(MB).alloc().unwrap(); + bounds(&mut wal); +} + +#[test] +fn bounds_map_anon() { + let mut wal = GenericBuilder::new().with_capacity(MB).map_anon().unwrap(); + bounds(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn bounds_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_bounds_map_file"); + + let mut wal = unsafe { + GenericBuilder::new() + .with_capacity(MB) + .with_create_new(true) + .with_read(true) + .with_write(true) + .map_mut::(&path) + .unwrap() + }; + + bounds(&mut wal); +} + fn range(wal: &mut GenericOrderWal) { let mut mid = Person::random(); let people = (0..100) @@ -92,8 +258,8 @@ fn range(wal: &mut GenericOrderWal) { let mut iter = wal.range(Bound::Included(&mid), Bound::Unbounded); for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); + assert!(pwal.0.equivalent(pvec.key())); + assert_eq!(&pwal.1, pvec.value()); } assert!(iter.next().is_none()); @@ -102,15 +268,15 @@ fn range(wal: &mut GenericOrderWal) { let mut iter = wal.range(Bound::Included(&mid), Bound::Unbounded); for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); + assert!(pwal.0.equivalent(pvec.key())); + assert_eq!(&pwal.1, pvec.value()); } let mut rev_iter = wal.range(Bound::Included(&mid), Bound::Unbounded).rev(); for (pwal, pvec) in people.range(&mid..).rev().zip(rev_iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); + assert!(pwal.0.equivalent(pvec.key())); + assert_eq!(&pwal.1, pvec.value()); } } @@ -151,72 +317,50 @@ fn range_map_file() { range(&mut wal); } -fn range_ref(wal: &mut GenericOrderWal) { - let mut mid = Person::random(); - let people = (0..100) - .map(|idx| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - wal.insert(&p, &v).unwrap(); - - if idx == 500 { - mid = p.clone(); - } - (p, v) - }) - .collect::>(); - - let mid_ref = mid.as_ref(); - let mut iter = wal.range_by_ref(Bound::Included(&mid_ref), Bound::Unbounded); - - for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); +fn entry_iter(wal: &mut GenericOrderWal) { + for i in 0..100u32 { + wal.insert(&i, &i).unwrap(); } - assert!(iter.next().is_none()); - - let wal = wal.reader(); - let mut iter = wal.range_by_ref(Bound::Included(&mid), Bound::Unbounded); - - for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); + let mut curr = wal.first(); + let mut cursor = 0; + while let Some(ent) = curr { + assert_eq!(ent.key(), &cursor); + assert_eq!(ent.value(), &cursor); + cursor += 1; + curr = ent.next(); } - let mut rev_iter = wal - .range_by_ref(Bound::Included(&mid), Bound::Unbounded) - .rev(); + let curr = wal.last(); + std::println!("{:?}", curr); - for (pwal, pvec) in people.range(&mid..).rev().zip(rev_iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); + let mut curr = curr.clone(); + let mut cursor = 100; + while let Some(ent) = curr { + cursor -= 1; + assert_eq!(ent.key(), &cursor); + assert_eq!(ent.value(), &cursor); + curr = ent.prev(); } } #[test] -fn range_ref_inmemory() { - let mut wal = GenericBuilder::new() - .with_capacity(MB) - .alloc::() - .unwrap(); - range(&mut wal); +fn entry_iter_inmemory() { + let mut wal = GenericBuilder::new().with_capacity(MB).alloc().unwrap(); + entry_iter(&mut wal); } #[test] -fn range_ref_map_anon() { - let mut wal = GenericBuilder::new() - .with_capacity(MB) - .map_anon::() - .unwrap(); - range_ref(&mut wal); +fn entry_iter_map_anon() { + let mut wal = GenericBuilder::new().with_capacity(MB).map_anon().unwrap(); + entry_iter(&mut wal); } #[test] #[cfg_attr(miri, ignore)] -fn range_ref_map_file() { +fn entry_iter_map_file() { let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_range_map_file"); + let path = dir.path().join("generic_wal_entry_iter_map_file"); let mut wal = unsafe { GenericBuilder::new() @@ -228,5 +372,5 @@ fn range_ref_map_file() { .unwrap() }; - range_ref(&mut wal); + entry_iter(&mut wal); } diff --git a/src/swmr/wal.rs b/src/swmr/wal.rs index 37d4b01..e617687 100644 --- a/src/swmr/wal.rs +++ b/src/swmr/wal.rs @@ -16,7 +16,7 @@ pub use crate::{ }; pub use dbutils::CheapClone; -use core::{borrow::Borrow, marker::PhantomData}; +use core::{borrow::Borrow, marker::PhantomData, ops::Bound}; use rarena_allocator::sync::Arena; use std::sync::Arc; @@ -334,6 +334,34 @@ where { self.core.map.get(key).map(|ent| ent.as_value_slice()) } + + #[inline] + fn upper_bound(&self, bound: Bound<&Q>) -> Option<&[u8]> + where + [u8]: Borrow, + Q: ?Sized + Ord, + C: Comparator, + { + self + .core + .map + .upper_bound(bound) + .map(|ent| ent.as_value_slice()) + } + + #[inline] + fn lower_bound(&self, bound: Bound<&Q>) -> Option<&[u8]> + where + [u8]: Borrow, + Q: ?Sized + Ord, + C: Comparator, + { + self + .core + .map + .lower_bound(bound) + .map(|ent| ent.as_value_slice()) + } } impl Wal for OrderWal diff --git a/src/tests.rs b/src/tests.rs index 49e2b96..effcec7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -5,6 +5,37 @@ use wal::{ImmutableWal, Wal}; const MB: usize = 1024 * 1024; +macro_rules! expand_unit_tests { + ($wal:ident { $($name:ident), +$(,)? }) => { + $( + paste::paste! { + #[test] + fn [< test_ $name _inmemory >]() { + $crate::tests::$name(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); + } + + #[test] + fn [< test_ $name _map_anon >]() { + $crate::tests::$name(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn [< test_ $name _map_file >]() { + let dir = ::tempfile::tempdir().unwrap(); + $crate::tests::$name( + &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( + dir.path().join(concat!("test_", stringify!($prefix), "_", stringify!($name), "_map_file")), + + ) + .unwrap() }, + ); + } + } + )* + }; +} + macro_rules! common_unittests { ($prefix:ident::insert::$wal:ty) => { paste::paste! { @@ -197,6 +228,7 @@ macro_rules! common_unittests { }; $crate::tests::insert_batch_with_key_builder(&mut map); + map.flush().unwrap(); let map = unsafe { $crate::Builder::new().map::<$wal, _>(&path).unwrap() }; @@ -233,6 +265,7 @@ macro_rules! common_unittests { }; $crate::tests::insert_batch_with_value_builder(&mut map); + map.flush_async().unwrap(); let map = unsafe { $crate::Builder::new().map::<$wal, _>(&path).unwrap() }; @@ -279,250 +312,27 @@ macro_rules! common_unittests { } }; ($prefix:ident::iters::$wal:ident) => { - paste::paste! { - #[test] - fn test_iter_inmemory() { - $crate::tests::iter(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_iter_map_anon() { - $crate::tests::iter(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_iter_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - $crate::tests::iter( - &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_iter_map_file")), - - ) - .unwrap() }, - ); - } - - #[test] - fn test_range() { - $crate::tests::range(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_range_map_anon() { - $crate::tests::range(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_range_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - $crate::tests::range( - &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_range_map_file")), - - ) - .unwrap() }, - ); - } - - #[test] - fn test_keys() { - $crate::tests::keys(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_keys_map_anon() { - $crate::tests::keys(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_keys_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - $crate::tests::keys( - &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_keys_map_file")), - - ) - .unwrap() }, - ); - } - - #[test] - fn test_values() { - $crate::tests::values(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_values_map_anon() { - $crate::tests::values(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_values_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - $crate::tests::values( - &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_values_map_file")), - - ) - .unwrap() }, - ); - } - - #[test] - fn test_range_keys() { - $crate::tests::range_keys(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_range_keys_map_anon() { - $crate::tests::range_keys(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_range_keys_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - $crate::tests::range_keys( - &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_range_keys_map_file")), - - ) - .unwrap() }, - ); - } - - #[test] - fn test_range_values() { - $crate::tests::range_values(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_range_values_map_anon() { - $crate::tests::range_values(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_range_values_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - $crate::tests::range_values( - &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test", stringify!($prefix), "_range_values_map_file")), - - ) - .unwrap() }, - ); - } - } + expand_unit_tests!( + $wal { + iter, + range, + keys, + values, + bounds, + range_keys, + range_values, + } + ); }; ($prefix:ident::get::$wal:ident) => { - paste::paste! { - #[test] - fn test_first_inmemory() { - $crate::tests::first(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_first_map_anon() { - $crate::tests::first(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_first_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - $crate::tests::first( - &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_first_map_file")), - - ) - .unwrap() }, - ); - } - - #[test] - fn test_last_inmemory() { - $crate::tests::last(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_last_map_anon() { - $crate::tests::last(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_last_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - $crate::tests::last( - &mut unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_last_map_file")), - - ) - .unwrap() }, - ); - } - - #[test] - fn test_get_or_insert_inmemory() { - $crate::tests::get_or_insert(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_get_or_insert_map_anon() { - $crate::tests::get_or_insert(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_get_or_insert_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - - let mut wal = unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - dir.path().join(concat!("test_", stringify!($prefix), "_get_or_insert_map_file")), - ) - .unwrap() }; - - $crate::tests::get_or_insert( - &mut wal, - ); - - wal.flush().unwrap(); - } - - #[test] - fn test_get_or_insert_with_value_builder_inmemory() { - $crate::tests::get_or_insert_with_value_builder(&mut $crate::Builder::new().with_capacity(MB).alloc::<$wal>().unwrap()); - } - - #[test] - fn test_get_or_insert_with_value_builder_map_anon() { - $crate::tests::get_or_insert_with_value_builder(&mut $crate::Builder::new().with_capacity(MB).map_anon::<$wal>().unwrap()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_get_or_insert_with_value_builder_map_file() { - let dir = ::tempfile::tempdir().unwrap(); - let path = dir.path().join(concat!("test_", stringify!($prefix), "_get_or_insert_with_value_builder_map_file")); - let mut wal = unsafe { $crate::Builder::new().with_create_new(true).with_read(true).with_write(true).with_capacity(MB as u32).map_mut::<$wal, _>( - &path, - - ) - .unwrap() }; - $crate::tests::get_or_insert_with_value_builder( - &mut wal, - ); - - wal.flush_async().unwrap(); - - assert_eq!(wal.path().unwrap(), path); - } - } + expand_unit_tests!( + $wal { + first, + last, + get_or_insert, + get_or_insert_with_value_builder, + } + ); }; ($prefix:ident::constructor::$wal:ident) => { paste::paste! { @@ -858,6 +668,81 @@ pub(crate) fn iter>(wal: &mut W) { } } +pub(crate) fn bounds>(wal: &mut W) { + for i in 0..100u32 { + wal.insert(&i.to_be_bytes(), &i.to_be_bytes()).unwrap(); + } + + let upper50 = wal + .upper_bound(Bound::Included(&50u32.to_be_bytes())) + .unwrap(); + assert_eq!(upper50, 50u32.to_be_bytes()); + let upper51 = wal + .upper_bound(Bound::Excluded(&51u32.to_be_bytes())) + .unwrap(); + assert_eq!(upper51, 50u32.to_be_bytes()); + + let upper101 = wal + .upper_bound(Bound::Included(&101u32.to_be_bytes())) + .unwrap(); + assert_eq!(upper101, 99u32.to_be_bytes()); + + let upper_unbounded = wal.upper_bound(Bound::Unbounded).unwrap(); + assert_eq!(upper_unbounded, 99u32.to_be_bytes()); + + let lower50 = wal + .lower_bound(Bound::Included(&50u32.to_be_bytes())) + .unwrap(); + assert_eq!(lower50, 50u32.to_be_bytes()); + let lower51 = wal + .lower_bound(Bound::Excluded(&51u32.to_be_bytes())) + .unwrap(); + assert_eq!(lower51, 52u32.to_be_bytes()); + + let lower0 = wal + .lower_bound(Bound::Excluded(&0u32.to_be_bytes())) + .unwrap(); + assert_eq!(lower0, 1u32.to_be_bytes()); + + let lower_unbounded = wal.lower_bound(Bound::Unbounded).unwrap(); + assert_eq!(lower_unbounded, 0u32.to_be_bytes()); + + let wal = wal.reader(); + let upper50 = wal + .upper_bound(Bound::Included(&50u32.to_be_bytes())) + .unwrap(); + assert_eq!(upper50, 50u32.to_be_bytes()); + let upper51 = wal + .upper_bound(Bound::Excluded(&51u32.to_be_bytes())) + .unwrap(); + assert_eq!(upper51, 50u32.to_be_bytes()); + + let upper101 = wal + .upper_bound(Bound::Included(&101u32.to_be_bytes())) + .unwrap(); + assert_eq!(upper101, 99u32.to_be_bytes()); + + let upper_unbounded = wal.upper_bound(Bound::Unbounded).unwrap(); + assert_eq!(upper_unbounded, 99u32.to_be_bytes()); + + let lower50 = wal + .lower_bound(Bound::Included(&50u32.to_be_bytes())) + .unwrap(); + assert_eq!(lower50, 50u32.to_be_bytes()); + let lower51 = wal + .lower_bound(Bound::Excluded(&51u32.to_be_bytes())) + .unwrap(); + assert_eq!(lower51, 52u32.to_be_bytes()); + + let lower0 = wal + .lower_bound(Bound::Excluded(&0u32.to_be_bytes())) + .unwrap(); + assert_eq!(lower0, 1u32.to_be_bytes()); + + let lower_unbounded = wal.lower_bound(Bound::Unbounded).unwrap(); + assert_eq!(lower_unbounded, 0u32.to_be_bytes()); +} + pub(crate) fn range>(wal: &mut W) { for i in 0..100u32 { wal.insert(&i.to_be_bytes(), &i.to_be_bytes()).unwrap(); diff --git a/src/wal.rs b/src/wal.rs index 4596a99..5df6196 100644 --- a/src/wal.rs +++ b/src/wal.rs @@ -1,7 +1,7 @@ use checksum::BuildChecksumer; -use core::ops::RangeBounds; +use core::ops::{Bound, RangeBounds}; -use super::*; +use super::{pointer::Pointer, *}; pub(crate) mod sealed; @@ -175,6 +175,38 @@ pub trait ImmutableWal: sealed::Constructor { [u8]: Borrow, Q: ?Sized + Ord, C: Comparator; + + /// Returns a value associated to the highest element whose key is below the given bound. + /// If no such element is found then `None` is returned. + // TODO: implement this method for unsync::OrderWal when BTreeMap::upper_bound is stable + #[inline] + fn upper_bound(&self, bound: Bound<&Q>) -> Option<&[u8]> + where + [u8]: Borrow, + Q: ?Sized + Ord, + C: Comparator, + { + self + .range((Bound::Unbounded, bound)) + .last() + .map(|ent| ent.0) + } + + /// Returns a value associated to the lowest element whose key is above the given bound. + /// If no such element is found then `None` is returned. + // TODO: implement this method for unsync::OrderWal when BTreeMap::lower_bound is stable + #[inline] + fn lower_bound(&self, bound: Bound<&Q>) -> Option<&[u8]> + where + [u8]: Borrow, + Q: ?Sized + Ord, + C: Comparator, + { + self + .range((bound, Bound::Unbounded)) + .next() + .map(|ent| ent.0) + } } /// An abstract layer for the write-ahead log. @@ -353,11 +385,13 @@ pub trait Wal: } /// Inserts a batch of key-value pairs into the WAL. - fn insert_batch_with_key_builder>( + fn insert_batch_with_key_builder( &mut self, batch: &mut B, ) -> Result<(), Either> where + B: BatchWithKeyBuilder>, + B::Value: Borrow<[u8]>, C: Comparator + CheapClone, S: BuildChecksumer, { @@ -371,11 +405,13 @@ pub trait Wal: } /// Inserts a batch of key-value pairs into the WAL. - fn insert_batch_with_value_builder>( + fn insert_batch_with_value_builder( &mut self, batch: &mut B, ) -> Result<(), Either> where + B: BatchWithValueBuilder>, + B::Key: Borrow<[u8]>, C: Comparator + CheapClone, S: BuildChecksumer, { @@ -389,11 +425,12 @@ pub trait Wal: } /// Inserts a batch of key-value pairs into the WAL. - fn insert_batch_with_builders>( + fn insert_batch_with_builders( &mut self, batch: &mut B, ) -> Result<(), Among> where + B: BatchWithBuilders>, C: Comparator + CheapClone, S: BuildChecksumer, { diff --git a/src/wal/batch.rs b/src/wal/batch.rs index 39967af..c9414a5 100644 --- a/src/wal/batch.rs +++ b/src/wal/batch.rs @@ -47,7 +47,7 @@ where /// A batch of keys and values that can be inserted into the [`Wal`](super::Wal). /// Comparing to [`Batch`], this trait is used to build /// the key in place. -pub trait BatchWithKeyBuilder { +pub trait BatchWithKeyBuilder { /// The key builder type. type KeyBuilder: Fn(&mut VacantBuffer<'_>) -> Result<(), Self::Error>; @@ -55,15 +55,10 @@ pub trait BatchWithKeyBuilder { type Error; /// The value type. - type Value: Borrow<[u8]>; - - /// The [`Comparator`] type. - type Comparator: Comparator; + type Value; /// The iterator type. - type IterMut<'a>: Iterator< - Item = &'a mut EntryWithKeyBuilder, - > + type IterMut<'a>: Iterator> where Self: 'a; @@ -71,17 +66,15 @@ pub trait BatchWithKeyBuilder { fn iter_mut(&mut self) -> Self::IterMut<'_>; } -impl BatchWithKeyBuilder for T +impl BatchWithKeyBuilder

for T where KB: Fn(&mut VacantBuffer<'_>) -> Result<(), E>, - V: Borrow<[u8]>, - C: Comparator, - for<'a> &'a mut T: IntoIterator>, + for<'a> &'a mut T: IntoIterator>, + P: 'static, { type KeyBuilder = KB; type Error = E; type Value = V; - type Comparator = C; type IterMut<'a> = <&'a mut T as IntoIterator>::IntoIter where Self: 'a; @@ -93,7 +86,7 @@ where /// A batch of keys and values that can be inserted into the [`Wal`](super::Wal). /// Comparing to [`Batch`], this trait is used to build /// the value in place. -pub trait BatchWithValueBuilder { +pub trait BatchWithValueBuilder { /// The value builder type. type ValueBuilder: Fn(&mut VacantBuffer<'_>) -> Result<(), Self::Error>; @@ -101,15 +94,10 @@ pub trait BatchWithValueBuilder { type Error; /// The key type. - type Key: Borrow<[u8]>; - - /// The [`Comparator`] type. - type Comparator: Comparator; + type Key; /// The iterator type. - type IterMut<'a>: Iterator< - Item = &'a mut EntryWithValueBuilder, - > + type IterMut<'a>: Iterator> where Self: 'a; @@ -117,17 +105,15 @@ pub trait BatchWithValueBuilder { fn iter_mut(&mut self) -> Self::IterMut<'_>; } -impl BatchWithValueBuilder for T +impl BatchWithValueBuilder

for T where VB: Fn(&mut VacantBuffer<'_>) -> Result<(), E>, - K: Borrow<[u8]>, - C: Comparator, - for<'a> &'a mut T: IntoIterator>, + for<'a> &'a mut T: IntoIterator>, + P: 'static, { type Key = K; type Error = E; type ValueBuilder = VB; - type Comparator = C; type IterMut<'a> = <&'a mut T as IntoIterator>::IntoIter where Self: 'a; @@ -139,7 +125,7 @@ where /// A batch of keys and values that can be inserted into the [`Wal`](super::Wal). /// Comparing to [`Batch`], this trait is used to build /// the key and value in place. -pub trait BatchWithBuilders { +pub trait BatchWithBuilders { /// The value builder type. type ValueBuilder: Fn(&mut VacantBuffer<'_>) -> Result<(), Self::ValueError>; @@ -152,12 +138,9 @@ pub trait BatchWithBuilders { /// The error for the value builder. type KeyError; - /// The [`Comparator`] type. - type Comparator: Comparator; - /// The iterator type. type IterMut<'a>: Iterator< - Item = &'a mut EntryWithBuilders, + Item = &'a mut EntryWithBuilders, > where Self: 'a; @@ -166,18 +149,17 @@ pub trait BatchWithBuilders { fn iter_mut(&mut self) -> Self::IterMut<'_>; } -impl BatchWithBuilders for T +impl BatchWithBuilders

for T where VB: Fn(&mut VacantBuffer<'_>) -> Result<(), VE>, KB: Fn(&mut VacantBuffer<'_>) -> Result<(), KE>, - C: Comparator, - for<'a> &'a mut T: IntoIterator>, + for<'a> &'a mut T: IntoIterator>, + P: 'static, { type KeyBuilder = KB; type KeyError = KE; type ValueBuilder = VB; type ValueError = VE; - type Comparator = C; type IterMut<'a> = <&'a mut T as IntoIterator>::IntoIter where Self: 'a; diff --git a/src/wal/sealed.rs b/src/wal/sealed.rs index 9d605f2..b7fe008 100644 --- a/src/wal/sealed.rs +++ b/src/wal/sealed.rs @@ -5,7 +5,7 @@ use rarena_allocator::{ArenaPosition, BytesRefMut}; use super::*; -pub trait Pointer { +pub trait Pointer: Sized { type Comparator; fn new(klen: usize, vlen: usize, ptr: *const u8, cmp: Self::Comparator) -> Self; @@ -120,11 +120,13 @@ pub trait Sealed: Constructor { where C: Comparator; - fn insert_batch_with_key_builder_in>( + fn insert_batch_with_key_builder_in( &mut self, batch: &mut B, ) -> Result<(), Either> where + B: BatchWithKeyBuilder>, + B::Value: Borrow<[u8]>, C: Comparator + CheapClone, S: BuildChecksumer, { @@ -163,11 +165,13 @@ pub trait Sealed: Constructor { } } - fn insert_batch_with_value_builder_in>( + fn insert_batch_with_value_builder_in( &mut self, batch: &mut B, ) -> Result<(), Either> where + B: BatchWithValueBuilder>, + B::Key: Borrow<[u8]>, C: Comparator + CheapClone, S: BuildChecksumer, { @@ -207,11 +211,12 @@ pub trait Sealed: Constructor { } } - fn insert_batch_with_builders_in>( + fn insert_batch_with_builders_in( &mut self, batch: &mut B, ) -> Result<(), Among> where + B: BatchWithBuilders>, C: Comparator + CheapClone, S: BuildChecksumer, {