diff --git a/Cargo.lock b/Cargo.lock index 221be3944b67ee3177da0a048f2b199318ba6021..a8e8112d3a50e773bdb65f1561e2d29cfbf49b21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1952,6 +1952,7 @@ name = "kv_typed" version = "0.1.0" dependencies = [ "async-std", + "byteorder", "cfg-if 0.1.10", "criterion", "flume", diff --git a/rust-libs/tools/kv_typed/Cargo.toml b/rust-libs/tools/kv_typed/Cargo.toml index d1d549612dab8f0bcb8290d6397a219e5cff5974..fe242ec6fad58dc04d5743883113d7d2658429ec 100644 --- a/rust-libs/tools/kv_typed/Cargo.toml +++ b/rust-libs/tools/kv_typed/Cargo.toml @@ -12,6 +12,7 @@ edition = "2018" path = "src/lib.rs" [dependencies] +byteorder = "1.3.4" cfg-if = "0.1.10" flume = "0.9.1" leveldb_minimal = { version = "0.1.0", optional = true } diff --git a/rust-libs/tools/kv_typed/src/backend.rs b/rust-libs/tools/kv_typed/src/backend.rs index 6e8688c93c09e3099d6ce2d2d07d9a02ea7ea444..5e91cc21d5e569bf2314c533f25e4bc56861b7b5 100644 --- a/rust-libs/tools/kv_typed/src/backend.rs +++ b/rust-libs/tools/kv_typed/src/backend.rs @@ -58,7 +58,22 @@ pub trait BackendCol: 'static + Clone + Debug + Send + Sync { fn contains_key<K: Key>(&self, k: &K) -> KvResult<bool>; fn count(&self) -> KvResult<usize>; fn iter<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter; - fn iter_rev<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter; + fn iter_ref_slice<D, K, V, F>( + &self, + range: RangeBytes, + f: F, + ) -> KvInnerIterRefSlice<Self, D, K, V, F> + where + K: KeyZc, + V: ValueSliceZc, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, + { + KvInnerIterRefSlice { + backend_iter: self.iter::<K, V>(range), + f, + phantom: PhantomData, + } + } fn put<K: Key, V: Value>(&mut self, k: &K, value: &V) -> KvResult<()>; fn delete<K: Key>(&mut self, k: &K) -> KvResult<()>; fn new_batch() -> Self::Batch; diff --git a/rust-libs/tools/kv_typed/src/backend/leveldb.rs b/rust-libs/tools/kv_typed/src/backend/leveldb.rs index 7176a7fddffc71fcfac14165bcf8f2ae74201b9b..f710347418e55a1c36d9fe76439838c39830d0aa 100644 --- a/rust-libs/tools/kv_typed/src/backend/leveldb.rs +++ b/rust-libs/tools/kv_typed/src/backend/leveldb.rs @@ -206,12 +206,8 @@ impl BackendCol for LevelDbCol { Ok(()) } #[inline(always)] - fn iter<K: Key, V: Value>(&self, _range: RangeBytes) -> Self::Iter { - LevelDbIter(self.0.iter(ReadOptions::new())) - } - #[inline(always)] - fn iter_rev<K: Key, V: Value>(&self, _range: RangeBytes) -> Self::Iter { - LevelDbIter(self.0.iter(ReadOptions::new()).reverse()) + fn iter<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter { + LevelDbIter::new(self.0.iter(ReadOptions::new()), range) } #[inline(always)] fn save(&self) -> KvResult<()> { @@ -219,11 +215,28 @@ impl BackendCol for LevelDbCol { } } -pub struct LevelDbIter(LevelDbIterator); +pub struct LevelDbIter { + inner: LevelDbIterator, + range_start: Bound<IVec>, + range_end: Bound<IVec>, + reversed: bool, +} +impl LevelDbIter { + fn new(inner: LevelDbIterator, range: RangeBytes) -> Self { + LevelDbIter { + inner, + range_start: range.0, + range_end: range.1, + reversed: false, + } + } +} impl Debug for LevelDbIter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("LevelDbIter") - .field("0", &"LevelDbIterator<'db>") + .field("inner", &"LevelDbIterator<'db>") + .field("range_start", &self.range_start) + .field("range_end", &self.range_end) .finish() } } @@ -233,15 +246,60 @@ impl Iterator for LevelDbIter { #[inline(always)] fn next(&mut self) -> Option<Self::Item> { - self.0 - .next() - .map(|(k, v)| Ok((LevelDbBytes(k), LevelDbBytes(v)))) + loop { + match self + .inner + .next() + .map(|(k, v)| Ok((LevelDbBytes(k), LevelDbBytes(v)))) + { + Some(Ok((key_bytes, value_bytes))) => { + let start_bound_ok = match &self.range_start { + Bound::Included(start_bytes) => key_bytes.as_ref() >= start_bytes.as_ref(), + Bound::Excluded(start_bytes) => key_bytes.as_ref() > start_bytes.as_ref(), + Bound::Unbounded => true, + }; + let end_bound_ok = match &self.range_end { + Bound::Included(end_bytes) => key_bytes.as_ref() <= end_bytes.as_ref(), + Bound::Excluded(end_bytes) => key_bytes.as_ref() < end_bytes.as_ref(), + Bound::Unbounded => true, + }; + if start_bound_ok { + if end_bound_ok { + break Some(Ok((key_bytes, value_bytes))); + } else if self.reversed { + // The interval has not yet begun. + continue; + } else { + // The range has been fully traversed, the iterator is finished. + break None; + } + } else if end_bound_ok { + if self.reversed { + // The range has been fully traversed, the iterator is finished. + break None; + } else { + // The interval has not yet begun. + continue; + } + } else { + // Empty range, the iterator is finished. + break None; + } + } + other => break other, + } + } } } impl ReversableIterator for LevelDbIter { #[inline(always)] fn reverse(self) -> Self { - Self(self.0.reverse()) + LevelDbIter { + range_start: self.range_start, + range_end: self.range_end, + reversed: !self.reversed, + inner: self.inner.reverse(), + } } } impl BackendIter<LevelDbBytes, LevelDbBytes> for LevelDbIter {} diff --git a/rust-libs/tools/kv_typed/src/backend/memory.rs b/rust-libs/tools/kv_typed/src/backend/memory.rs index b3ec5589cae81679324b4bf4e341a59040f1d695..fd3709c5c59eab6c3b1f59155c34ca701d075525 100644 --- a/rust-libs/tools/kv_typed/src/backend/memory.rs +++ b/rust-libs/tools/kv_typed/src/backend/memory.rs @@ -337,10 +337,6 @@ impl BackendCol for MemCol { }) } #[inline(always)] - fn iter_rev<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter { - self.iter::<K, V>(range).reverse() - } - #[inline(always)] fn save(&self) -> KvResult<()> { /*if let Some(ref file_path) = self.path { let bytes = Self::tree_to_bytes(&self.tree); diff --git a/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs b/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs index 200973d752061dd568183fd666e62c57d35a45f5..d77bcedda42b506b4861a5587fec26312038a3ea 100644 --- a/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs +++ b/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs @@ -155,10 +155,6 @@ impl BackendCol for MemCol { MemIter(self.0.clone()) } #[inline(always)] - fn iter_rev<K: Key, V: Value>(&self, _: RangeBytes) -> Self::Iter { - MemIter(self.0.clone()) - } - #[inline(always)] fn save(&self) -> KvResult<()> { Ok(()) } diff --git a/rust-libs/tools/kv_typed/src/backend/sled.rs b/rust-libs/tools/kv_typed/src/backend/sled.rs index d519fa0027192b23992bd233f6cf298fa1ec04f8..6efd6cb2144035c5896afa99120005d8c45ea14c 100644 --- a/rust-libs/tools/kv_typed/src/backend/sled.rs +++ b/rust-libs/tools/kv_typed/src/backend/sled.rs @@ -163,10 +163,6 @@ impl BackendCol for SledCol { } } #[inline(always)] - fn iter_rev<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter { - self.iter::<K, V>(range).reverse() - } - #[inline(always)] fn save(&self) -> KvResult<()> { self.0.flush()?; Ok(()) diff --git a/rust-libs/tools/kv_typed/src/collection_inner.rs b/rust-libs/tools/kv_typed/src/collection_inner.rs index a03d9883ef2e6bab986194de3fb6eb42360b088d..452cc3f7904d983d1df3c6db8fe1764f9a0d6184 100644 --- a/rust-libs/tools/kv_typed/src/collection_inner.rs +++ b/rust-libs/tools/kv_typed/src/collection_inner.rs @@ -16,7 +16,7 @@ use crate::*; #[derive(Debug)] -pub(crate) struct ColInner<BC: BackendCol, E: EventTrait> { +pub struct ColInner<BC: BackendCol, E: EventTrait> { pub(crate) backend_col: BC, subscribers: ColSubscribers<E>, } diff --git a/rust-libs/tools/kv_typed/src/collection_ro.rs b/rust-libs/tools/kv_typed/src/collection_ro.rs index 485b204f6445616c67f7779a78a38ccd16caad41..1ab5360100f86ddbb25da8e20c57ba886c42f735 100644 --- a/rust-libs/tools/kv_typed/src/collection_ro.rs +++ b/rust-libs/tools/kv_typed/src/collection_ro.rs @@ -67,6 +67,8 @@ mockall::mock! { } } +type ColRoReader<'r, BC, E> = parking_lot::RwLockReadGuard<'r, ColInner<BC, E>>; + #[derive(Debug)] pub struct ColRo<BC: BackendCol, E: EventTrait> { pub(crate) inner: Arc<parking_lot::RwLock<ColInner<BC, E>>>, @@ -123,8 +125,8 @@ impl<BC: BackendCol, E: EventTrait> DbCollectionRo for ColRo<BC, E> { ) -> D { let range: RangeBytes = crate::iter::convert_range::<Self::K, R>(range); let r = self.inner.read(); - let iter = r.backend_col.iter::<Self::K, Self::V>(range.clone()); - f(KvIter::new(iter, range)) + let iter = r.backend_col.iter::<Self::K, Self::V>(range); + f(KvIter::new(iter)) } #[inline(always)] fn iter_rev< @@ -147,8 +149,8 @@ impl<BC: BackendCol, E: EventTrait> DbCollectionRo for ColRo<BC, E> { ) -> D { let range: RangeBytes = crate::iter::convert_range::<Self::K, R>(range); let r = self.inner.read(); - let iter = r.backend_col.iter::<Self::K, Self::V>(range.clone()); - f(KvIter::new(iter, range).reverse()) + let iter = r.backend_col.iter::<Self::K, Self::V>(range).reverse(); + f(KvIter::new(iter)) } #[inline(always)] fn subscribe(&self, subscriber_sender: Subscriber<Self::Event>) -> KvResult<()> { @@ -193,3 +195,73 @@ impl<V: ValueSliceZc, BC: BackendCol, E: EventTrait<V = V>> DbCollectionRoGetRef r.backend_col.get_ref_slice::<E::K, V, D, F>(k, f) } } + +pub trait DbCollectionRoIterRefSlice<'r, BC: BackendCol, K: KeyZc, V: ValueSliceZc, READER>: + DbCollectionRo<K = K, V = V> +{ + fn iter_ref_slice<D, R, F>(&'r self, range: R, f: F) -> KvIterRefSlice<BC, D, K, V, F, READER> + where + K: KeyZc, + V: ValueSliceZc, + R: 'static + RangeBounds<K>, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>; + fn iter_ref_slice_rev<D, R, F>( + &'r self, + range: R, + f: F, + ) -> KvIterRefSlice<BC, D, K, V, F, READER> + where + K: KeyZc, + V: ValueSliceZc, + R: 'static + RangeBounds<K>, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>; +} + +impl<'r, K: KeyZc, V: ValueSliceZc, BC: BackendCol, E: EventTrait<K = K, V = V>> + DbCollectionRoIterRefSlice<'r, BC, K, V, ColRoReader<'r, BC, E>> for ColRo<BC, E> +{ + fn iter_ref_slice<D, R, F>( + &'r self, + range: R, + f: F, + ) -> KvIterRefSlice<BC, D, K, V, F, ColRoReader<'r, BC, E>> + where + K: KeyZc, + V: ValueSliceZc, + R: 'static + RangeBounds<K>, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, + { + let range: RangeBytes = crate::iter::convert_range::<Self::K, R>(range); + let reader = self.inner.read(); + let inner_iter = reader.backend_col.iter_ref_slice::<D, K, V, F>(range, f); + + KvIterRefSlice { + inner: inner_iter, + reader: OwnedOrRef::Owned(reader), + } + } + + fn iter_ref_slice_rev<D, R, F>( + &'r self, + range: R, + f: F, + ) -> KvIterRefSlice<BC, D, K, V, F, ColRoReader<'r, BC, E>> + where + K: KeyZc, + V: ValueSliceZc, + R: 'static + RangeBounds<K>, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, + { + let range: RangeBytes = crate::iter::convert_range::<Self::K, R>(range); + let reader = self.inner.read(); + let inner_iter = reader + .backend_col + .iter_ref_slice::<D, K, V, F>(range, f) + .reverse(); + + KvIterRefSlice { + inner: inner_iter, + reader: OwnedOrRef::Owned(reader), + } + } +} diff --git a/rust-libs/tools/kv_typed/src/iter.rs b/rust-libs/tools/kv_typed/src/iter.rs index 2fee25780e6d7c43c306fe38f70e0db159dbe23a..7e1256df0a51970e08f66b4df15f724016a26686 100644 --- a/rust-libs/tools/kv_typed/src/iter.rs +++ b/rust-libs/tools/kv_typed/src/iter.rs @@ -16,7 +16,6 @@ //! KV Typed iterators pub mod keys; -mod range; pub mod values; use crate::*; @@ -49,9 +48,8 @@ pub struct KvIter< K: Key, V: Value, > { - range_iter: range::RangeIter<C, KB, VB, BI>, - phantom_key: PhantomData<K>, - phantom_value: PhantomData<V>, + backend_iter: BI, + phantom: PhantomData<(C, KB, VB, K, V)>, } impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key, V: Value> @@ -60,7 +58,7 @@ impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Ke type Item = KvResult<(K, V)>; fn next(&mut self) -> Option<Self::Item> { - match self.range_iter.next() { + match self.backend_iter.next() { Some(Ok((key_bytes, value_bytes))) => match K::from_bytes(key_bytes.as_ref()) { Ok(key) => match V::from_bytes(value_bytes.as_ref()) { Ok(value) => Some(Ok((key, value))), @@ -74,36 +72,13 @@ impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Ke } } -impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key, V: Value> - ReversableIterator for KvIter<C, KB, VB, BI, K, V> -{ - #[inline(always)] - fn reverse(self) -> Self { - Self { - range_iter: self.range_iter.reverse(), - phantom_key: PhantomData, - phantom_value: PhantomData, - } - } -} - impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key, V: Value> KvIter<C, KB, VB, BI, K, V> { - #[cfg(feature = "mock")] - pub fn new(backend_iter: BI, range: RangeBytes) -> Self { - Self { - range_iter: range::RangeIter::new(backend_iter, range.0, range.1), - phantom_key: PhantomData, - phantom_value: PhantomData, - } - } - #[cfg(not(feature = "mock"))] - pub(crate) fn new(backend_iter: BI, range: RangeBytes) -> Self { + pub fn new(backend_iter: BI) -> Self { Self { - range_iter: range::RangeIter::new(backend_iter, range.0, range.1), - phantom_key: PhantomData, - phantom_value: PhantomData, + backend_iter, + phantom: PhantomData, } } } @@ -127,10 +102,10 @@ impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Ke type ValuesIter = KvIterValues<C, KB, VB, BI, K, V>; fn keys(self) -> KvIterKeys<C, KB, VB, BI, K> { - KvIterKeys::new(self.range_iter) + KvIterKeys::new(self.backend_iter) } fn values(self) -> KvIterValues<C, KB, VB, BI, K, V> { - KvIterValues::new(self.range_iter) + KvIterValues::new(self.backend_iter) } } @@ -148,3 +123,92 @@ fn convert_bound<K: Key>(bound_key: Bound<&K>) -> Bound<IVec> { Bound::Unbounded => Bound::Unbounded, } } + +#[allow(dead_code, missing_debug_implementations)] +pub struct KvIterRefSlice<'db, BC, D, K, V, F, R> +where + BC: BackendCol, + K: KeyZc, + V: ValueSliceZc, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, +{ + pub(crate) inner: KvInnerIterRefSlice<BC, D, K, V, F>, + pub(crate) reader: OwnedOrRef<'db, R>, +} +impl<'db, BC, D, K, V, F, R> Iterator for KvIterRefSlice<'db, BC, D, K, V, F, R> +where + BC: BackendCol, + K: KeyZc, + V: ValueSliceZc, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, +{ + type Item = KvResult<D>; + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next() + } +} + +#[allow(missing_debug_implementations)] +pub struct KvInnerIterRefSlice<BC, D, K, V, F> +where + BC: BackendCol, + K: KeyZc, + V: ValueSliceZc, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, +{ + pub(crate) backend_iter: BC::Iter, + pub(crate) f: F, + pub(crate) phantom: PhantomData<(D, K, V)>, +} +impl<BC, D, K, V, F> Iterator for KvInnerIterRefSlice<BC, D, K, V, F> +where + BC: BackendCol, + K: KeyZc, + V: ValueSliceZc, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, +{ + type Item = KvResult<D>; + + fn next(&mut self) -> Option<Self::Item> { + match self.backend_iter.next() { + Some(Ok((k_bytes, v_bytes))) => { + if let Some(k_layout) = zerocopy::LayoutVerified::<_, K::Ref>::new(k_bytes.as_ref()) + { + if let Some(v_layout) = zerocopy::LayoutVerified::<_, [V::Elem]>::new_slice( + &v_bytes.as_ref()[V::prefix_len()..], + ) { + Some((self.f)(&k_layout, &v_layout)) + } else { + Some(Err(KvError::DeserError( + "Bytes are invalid length or alignment.".into(), + ))) + } + } else { + Some(Err(KvError::DeserError( + "Bytes are invalid length or alignment.".into(), + ))) + } + } + Some(Err(e)) => Some(Err(KvError::BackendError(e))), + None => None, + } + } +} + +impl<BC, D, K, V, F> ReversableIterator for KvInnerIterRefSlice<BC, D, K, V, F> +where + BC: BackendCol, + K: KeyZc, + V: ValueSliceZc, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, +{ + #[inline(always)] + fn reverse(self) -> Self { + Self { + backend_iter: self.backend_iter.reverse(), + f: self.f, + phantom: PhantomData, + } + } +} diff --git a/rust-libs/tools/kv_typed/src/iter/keys.rs b/rust-libs/tools/kv_typed/src/iter/keys.rs index 89c63f7a5ce67f8d8b6d9cada919337df347531b..0555e16cefc6a54977e7230581121aad84f4517d 100644 --- a/rust-libs/tools/kv_typed/src/iter/keys.rs +++ b/rust-libs/tools/kv_typed/src/iter/keys.rs @@ -20,8 +20,8 @@ use crate::*; #[derive(Debug)] pub struct KvIterKeys<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key> { - range_iter: super::range::RangeIter<C, KB, VB, BI>, - phantom_key: PhantomData<K>, + backend_iter: BI, + phantom: PhantomData<(C, KB, VB, K)>, } impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key> Iterator @@ -30,7 +30,7 @@ impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Ke type Item = KvResult<K>; fn next(&mut self) -> Option<Self::Item> { - match self.range_iter.next() { + match self.backend_iter.next() { Some(Ok((key_bytes, _value_bytes))) => match K::from_bytes(key_bytes.as_ref()) { Ok(key) => Some(Ok(key)), Err(e) => Some(Err(KvError::DeserError(format!("{}", e)))), @@ -41,25 +41,13 @@ impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Ke } } -impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key> - ReversableIterator for KvIterKeys<C, KB, VB, BI, K> -{ - #[inline(always)] - fn reverse(self) -> Self { - Self { - range_iter: self.range_iter.reverse(), - phantom_key: PhantomData, - } - } -} - impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key> KvIterKeys<C, KB, VB, BI, K> { - pub(super) fn new(range_iter: super::range::RangeIter<C, KB, VB, BI>) -> Self { + pub(super) fn new(backend_iter: BI) -> Self { Self { - range_iter, - phantom_key: PhantomData, + backend_iter, + phantom: PhantomData, } } } diff --git a/rust-libs/tools/kv_typed/src/iter/range.rs b/rust-libs/tools/kv_typed/src/iter/range.rs deleted file mode 100644 index cabef97a24211929e74fdee83e1c28519998e873..0000000000000000000000000000000000000000 --- a/rust-libs/tools/kv_typed/src/iter/range.rs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (C) 2020 Éloïs SANCHEZ. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see <https://www.gnu.org/licenses/>. - -//! KV Typed iterators - -use crate::*; - -pub(super) struct RangeIter<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>> { - backend_iter: BI, - phantom: PhantomData<C>, - phantom_kb: PhantomData<KB>, - phantom_vb: PhantomData<VB>, - reversed: bool, - range_start: Bound<IVec>, - range_end: Bound<IVec>, -} - -impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>> Debug - for RangeIter<C, KB, VB, BI> -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("LevelDbCol") - .field("backend_iter", &"BackendIter") - .field("reversed", &format!("{:?}", self.reversed)) - .field("range_start", &format!("{:?}", self.range_start)) - .field("range_end", &format!("{:?}", self.range_end)) - .finish() - } -} - -impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>> - RangeIter<C, KB, VB, BI> -{ - #[inline(always)] - pub(crate) fn new(backend_iter: BI, range_start: Bound<IVec>, range_end: Bound<IVec>) -> Self { - RangeIter { - backend_iter, - phantom: PhantomData, - phantom_kb: PhantomData, - phantom_vb: PhantomData, - reversed: false, - range_start, - range_end, - } - } -} - -impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>> Iterator - for RangeIter<C, KB, VB, BI> -{ - type Item = Result<(KB, VB), DynErr>; - - fn next(&mut self) -> Option<Self::Item> { - loop { - match self.backend_iter.next() { - Some(Ok((key_bytes, value_bytes))) => { - let start_bound_ok = match &self.range_start { - Bound::Included(start_bytes) => key_bytes.as_ref() >= start_bytes.as_ref(), - Bound::Excluded(start_bytes) => key_bytes.as_ref() > start_bytes.as_ref(), - Bound::Unbounded => true, - }; - let end_bound_ok = match &self.range_end { - Bound::Included(end_bytes) => key_bytes.as_ref() <= end_bytes.as_ref(), - Bound::Excluded(end_bytes) => key_bytes.as_ref() < end_bytes.as_ref(), - Bound::Unbounded => true, - }; - if start_bound_ok { - if end_bound_ok { - break Some(Ok((key_bytes, value_bytes))); - } else if self.reversed { - // The interval has not yet begun. - continue; - } else { - // The range has been fully traversed, the iterator is finished. - break None; - } - } else if end_bound_ok { - if self.reversed { - // The range has been fully traversed, the iterator is finished. - break None; - } else { - // The interval has not yet begun. - continue; - } - } else { - // Empty range, the iterator is finished. - break None; - } - } - other => break other, - } - } - } -} -impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>> ReversableIterator - for RangeIter<C, KB, VB, BI> -{ - #[inline(always)] - fn reverse(self) -> Self { - RangeIter { - backend_iter: self.backend_iter.reverse(), - phantom: PhantomData, - phantom_kb: PhantomData, - phantom_vb: PhantomData, - reversed: !self.reversed, - range_start: self.range_start, - range_end: self.range_end, - } - } -} diff --git a/rust-libs/tools/kv_typed/src/iter/values.rs b/rust-libs/tools/kv_typed/src/iter/values.rs index f701dab041c0beff984dfa388c91dfe3294af3a1..8652d53c486a0bfbdadbe7dbe43ff873496e2bb0 100644 --- a/rust-libs/tools/kv_typed/src/iter/values.rs +++ b/rust-libs/tools/kv_typed/src/iter/values.rs @@ -26,9 +26,8 @@ pub struct KvIterValues< K: Key, V: Value, > { - range_iter: super::range::RangeIter<C, KB, VB, BI>, - phantom_key: PhantomData<K>, - phantom_value: PhantomData<V>, + backend_iter: BI, + phantom: PhantomData<(C, KB, VB, K, V)>, } impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key, V: Value> @@ -37,7 +36,7 @@ impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Ke type Item = KvResult<V>; fn next(&mut self) -> Option<Self::Item> { - match self.range_iter.next() { + match self.backend_iter.next() { Some(Ok((_key_bytes, value_bytes))) => match V::from_bytes(value_bytes.as_ref()) { Ok(value) => Some(Ok(value)), Err(e) => Some(Err(KvError::DeserError(format!("{}", e)))), @@ -48,27 +47,13 @@ impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Ke } } -impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key, V: Value> - ReversableIterator for KvIterValues<C, KB, VB, BI, K, V> -{ - #[inline(always)] - fn reverse(self) -> Self { - Self { - range_iter: self.range_iter.reverse(), - phantom_key: PhantomData, - phantom_value: PhantomData, - } - } -} - impl<C: BackendCol, KB: KeyBytes, VB: ValueBytes, BI: BackendIter<KB, VB>, K: Key, V: Value> KvIterValues<C, KB, VB, BI, K, V> { - pub(super) fn new(range_iter: super::range::RangeIter<C, KB, VB, BI>) -> Self { + pub(super) fn new(backend_iter: BI) -> Self { Self { - range_iter, - phantom_key: PhantomData, - phantom_value: PhantomData, + backend_iter, + phantom: PhantomData, } } } diff --git a/rust-libs/tools/kv_typed/src/key.rs b/rust-libs/tools/kv_typed/src/key.rs index da3992b9a23d9e39ab8cb86e1b100a98f8e03bd0..8a1d1a94a4e7c8b8cba0fb3c9f2308fad6baf0ec 100644 --- a/rust-libs/tools/kv_typed/src/key.rs +++ b/rust-libs/tools/kv_typed/src/key.rs @@ -61,5 +61,26 @@ impl<T> Key for T where { } -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[derive( + Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, zerocopy::AsBytes, zerocopy::FromBytes, +)] +#[repr(transparent)] pub struct U32BE(pub u32); + +impl From<&zerocopy::U32<byteorder::BigEndian>> for U32BE { + fn from(u32_zc: &zerocopy::U32<byteorder::BigEndian>) -> Self { + U32BE(u32_zc.get()) + } +} + +pub trait KeyZc: Key { + type Ref: Sized + zerocopy::AsBytes + zerocopy::FromBytes; +} + +impl KeyZc for () { + type Ref = (); +} + +impl KeyZc for U32BE { + type Ref = zerocopy::U32<byteorder::BigEndian>; +} diff --git a/rust-libs/tools/kv_typed/src/lib.rs b/rust-libs/tools/kv_typed/src/lib.rs index 2a881c6b7e68ea2559c2c4e7fb7ec518d8286767..05a4fc5f4b9eea8ac677f35ac0465ceb7200c73e 100644 --- a/rust-libs/tools/kv_typed/src/lib.rs +++ b/rust-libs/tools/kv_typed/src/lib.rs @@ -72,6 +72,7 @@ pub mod prelude { pub use crate::collection_ro::MockColRo; pub use crate::collection_ro::{ ColRo, DbCollectionRo, DbCollectionRoGetRef, DbCollectionRoGetRefSlice, + DbCollectionRoIterRefSlice, }; pub use crate::collection_rw::{ColRw, DbCollectionRw}; pub use crate::error::{DynErr, KvError, KvResult, StringErr}; @@ -79,8 +80,10 @@ pub mod prelude { #[cfg(feature = "explorer")] pub use crate::explorer::{ExplorableKey, ExplorableValue}; pub use crate::from_bytes::FromBytes; - pub use crate::iter::{keys::KvIterKeys, values::KvIterValues, EntryIter, KvIter, ResultIter}; - pub use crate::key::{Key, U32BE}; + pub use crate::iter::{ + keys::KvIterKeys, values::KvIterValues, EntryIter, KvIter, KvIterRefSlice, ResultIter, + }; + pub use crate::key::{Key, KeyZc, U32BE}; pub use crate::subscription::{NewSubscribers, Subscriber, Subscribers}; pub use crate::transactional_read::{TransactionalRead, TxColRo}; pub use crate::transactional_write::{DbTxCollectionRw, TransactionalWrite, TxColRw}; @@ -95,7 +98,7 @@ pub(crate) use crate::collection_inner::ColInner; pub(crate) use crate::error::BackendResult; #[cfg(feature = "explorer")] pub(crate) use crate::explorer::{ExplorableKey, ExplorableValue}; -pub(crate) use crate::iter::{RangeBytes, ReversableIterator}; +pub(crate) use crate::iter::{KvInnerIterRefSlice, RangeBytes, ReversableIterator}; pub(crate) use crate::prelude::*; pub(crate) use crate::subscription::{ColSubscribers, SubscriptionsSender}; pub(crate) use crate::transactional_write::tx_iter::BackendTxIter; @@ -114,3 +117,16 @@ pub(crate) use std::{ str::FromStr, }; pub(crate) use thiserror::Error; + +pub enum OwnedOrRef<'a, T> { + Owned(T), + Borrow(&'a T), +} +impl<'a, T: Debug> Debug for OwnedOrRef<'a, T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Owned(t) => write!(f, "OwnedOrRef::Owned({:?})", t), + Self::Borrow(t) => write!(f, "OwnedOrRef::Borrow({:?})", t), + } + } +} diff --git a/rust-libs/tools/kv_typed/src/transactional_read.rs b/rust-libs/tools/kv_typed/src/transactional_read.rs index 94b63d4606815d5b18d35e95990a069265a006c5..647861f9b3c8d7c6518e3063e8fdcaf4639b70f8 100644 --- a/rust-libs/tools/kv_typed/src/transactional_read.rs +++ b/rust-libs/tools/kv_typed/src/transactional_read.rs @@ -18,19 +18,21 @@ use crate::*; use parking_lot::RwLockReadGuard as ReadGuard; -pub struct TxColRo<'db, BC: BackendCol, E: EventTrait> { - col_reader: ReadGuard<'db, ColInner<BC, E>>, +type TxColRoReader<'r, BC, E> = parking_lot::RwLockReadGuard<'r, ColInner<BC, E>>; + +pub struct TxColRo<'tx, BC: BackendCol, E: EventTrait> { + col_reader: ReadGuard<'tx, ColInner<BC, E>>, } -impl<'db, BC: BackendCol, E: EventTrait> Debug for TxColRo<'db, BC, E> { +impl<'tx, BC: BackendCol, E: EventTrait> Debug for TxColRo<'tx, BC, E> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("LevelDbCol") .field("col_reader", &format!("{:?}", self.col_reader)) .finish() } } -impl<'db, BC: BackendCol, E: EventTrait> TxColRo<'db, BC, E> { +impl<'tx, BC: BackendCol, E: EventTrait> TxColRo<'tx, BC, E> { #[inline(always)] - fn new(col_reader: ReadGuard<'db, ColInner<BC, E>>) -> Self { + fn new(col_reader: ReadGuard<'tx, ColInner<BC, E>>) -> Self { TxColRo { col_reader } } #[inline(always)] @@ -51,11 +53,8 @@ impl<'db, BC: BackendCol, E: EventTrait> TxColRo<'db, BC, E> { F: FnOnce(KvIter<BC, BC::KeyBytes, BC::ValueBytes, BC::Iter, E::K, E::V>) -> D, { let range_bytes = crate::iter::convert_range::<E::K, R>(range); - let backend_iter = self - .col_reader - .backend_col - .iter::<E::K, E::V>(range_bytes.clone()); - f(KvIter::new(backend_iter, range_bytes)) + let backend_iter = self.col_reader.backend_col.iter::<E::K, E::V>(range_bytes); + f(KvIter::new(backend_iter)) } #[allow(clippy::type_complexity)] #[inline(always)] @@ -70,16 +69,67 @@ impl<'db, BC: BackendCol, E: EventTrait> TxColRo<'db, BC, E> { let backend_iter = self .col_reader .backend_col - .iter::<E::K, E::V>(range_bytes.clone()); - f(KvIter::new(backend_iter, range_bytes).reverse()) + .iter::<E::K, E::V>(range_bytes) + .reverse(); + f(KvIter::new(backend_iter)) } } -impl<'db, V: ValueZc, BC: BackendCol, E: EventTrait<V = V>> TxColRo<'db, BC, E> { +impl<'tx, V: ValueZc, BC: BackendCol, E: EventTrait<V = V>> TxColRo<'tx, BC, E> { pub fn get_ref<D, F: Fn(&V::Ref) -> KvResult<D>>(&self, k: &E::K, f: F) -> KvResult<Option<D>> { self.col_reader.backend_col.get_ref::<E::K, V, D, F>(k, f) } } -impl<'db, V: ValueSliceZc, BC: BackendCol, E: EventTrait<V = V>> TxColRo<'db, BC, E> { +impl<'tx, K: KeyZc, V: ValueSliceZc, BC: BackendCol, E: EventTrait<K = K, V = V>> + TxColRo<'tx, BC, E> +{ + pub fn iter_ref_slice<D, R, F>( + &self, + range: R, + f: F, + ) -> KvIterRefSlice<BC, D, K, V, F, TxColRoReader<BC, E>> + where + K: KeyZc, + V: ValueSliceZc, + R: 'static + RangeBounds<K>, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, + { + let range: RangeBytes = crate::iter::convert_range::<K, R>(range); + let inner_iter = self + .col_reader + .backend_col + .iter_ref_slice::<D, K, V, F>(range, f); + + KvIterRefSlice { + inner: inner_iter, + reader: OwnedOrRef::Borrow(&self.col_reader), + } + } + pub fn iter_ref_slice_rev<D, R, F>( + &self, + range: R, + f: F, + ) -> KvIterRefSlice<BC, D, K, V, F, TxColRoReader<BC, E>> + where + K: KeyZc, + V: ValueSliceZc, + R: 'static + RangeBounds<K>, + F: FnMut(&K::Ref, &[V::Elem]) -> KvResult<D>, + { + let range: RangeBytes = crate::iter::convert_range::<K, R>(range); + let inner_iter = self + .col_reader + .backend_col + .iter_ref_slice::<D, K, V, F>(range, f) + .reverse(); + + KvIterRefSlice { + inner: inner_iter, + reader: OwnedOrRef::Borrow(&self.col_reader), + } + } +} + +impl<'tx, V: ValueSliceZc, BC: BackendCol, E: EventTrait<V = V>> TxColRo<'tx, BC, E> { pub fn get_ref_slice<D, F: Fn(&[V::Elem]) -> KvResult<D>>( &self, k: &E::K, @@ -91,24 +141,24 @@ impl<'db, V: ValueSliceZc, BC: BackendCol, E: EventTrait<V = V>> TxColRo<'db, BC } } -pub trait TransactionalRead<'db, BC: BackendCol> { +pub trait TransactionalRead<'tx, BC: BackendCol> { type TxCols; - fn read<D, F: Fn(Self::TxCols) -> KvResult<D>>(&'db self, f: F) -> KvResult<D>; + fn read<D, F: Fn(Self::TxCols) -> KvResult<D>>(&'tx self, f: F) -> KvResult<D>; - fn try_read<D, F: Fn(Self::TxCols) -> KvResult<D>>(&'db self, f: F) -> Result<KvResult<D>, F>; + fn try_read<D, F: Fn(Self::TxCols) -> KvResult<D>>(&'tx self, f: F) -> Result<KvResult<D>, F>; } -impl<'db, BC: BackendCol, E: EventTrait> TransactionalRead<'db, BC> for &'db ColRo<BC, E> { - type TxCols = TxColRo<'db, BC, E>; +impl<'tx, BC: BackendCol, E: EventTrait> TransactionalRead<'tx, BC> for &'tx ColRo<BC, E> { + type TxCols = TxColRo<'tx, BC, E>; - fn read<D, F: Fn(Self::TxCols) -> KvResult<D>>(&'db self, f: F) -> KvResult<D> { + fn read<D, F: Fn(Self::TxCols) -> KvResult<D>>(&'tx self, f: F) -> KvResult<D> { let read_guard_0 = self.inner.read(); f(TxColRo::new(read_guard_0)) } - fn try_read<D, F: Fn(Self::TxCols) -> KvResult<D>>(&'db self, f: F) -> Result<KvResult<D>, F> { + fn try_read<D, F: Fn(Self::TxCols) -> KvResult<D>>(&'tx self, f: F) -> Result<KvResult<D>, F> { if let Some(read_guard_0) = self.inner.try_read() { Ok(f(TxColRo::new(read_guard_0))) } else { @@ -120,13 +170,13 @@ impl<'db, BC: BackendCol, E: EventTrait> TransactionalRead<'db, BC> for &'db Col macro_rules! impl_transactional_read { ($($i:literal),*) => { paste::paste! { - impl<'db, BC: BackendCol $( ,[<E $i>]: EventTrait)*> TransactionalRead<'db, BC> - for ($(&'db ColRo<BC, [<E $i>]>, )*) + impl<'tx, BC: BackendCol $( ,[<E $i>]: EventTrait)*> TransactionalRead<'tx, BC> + for ($(&'tx ColRo<BC, [<E $i>]>, )*) { - type TxCols = ($(TxColRo<'db, BC, [<E $i>]>, )*); + type TxCols = ($(TxColRo<'tx, BC, [<E $i>]>, )*); fn read<D, F: Fn(Self::TxCols) -> KvResult<D>>( - &'db self, + &'tx self, f: F, ) -> KvResult<D> { $(let [<read_guard_ $i>] = self.$i.inner.read();)* @@ -135,7 +185,7 @@ macro_rules! impl_transactional_read { } fn try_read<D, F: Fn(Self::TxCols) -> KvResult<D>>( - &'db self, + &'tx self, f: F, ) -> Result<KvResult<D>, F> { $(let [<read_guard_opt_ $i>] = self.$i.inner.try_read();)* diff --git a/rust-libs/tools/kv_typed/src/transactional_write.rs b/rust-libs/tools/kv_typed/src/transactional_write.rs index b7b4d4181871230679d6a3122a313debca46f75e..7f461bc49922859bef89215ce0cdf8df9cb94d3c 100644 --- a/rust-libs/tools/kv_typed/src/transactional_write.rs +++ b/rust-libs/tools/kv_typed/src/transactional_write.rs @@ -20,11 +20,11 @@ pub(crate) mod tx_iter; use crate::*; use parking_lot::RwLockUpgradableReadGuard as UpgradableReadGuard; -pub struct TxColRw<'db, BC: BackendCol, E: EventTrait> { +pub struct TxColRw<'tx, BC: BackendCol, E: EventTrait> { batch: &'static mut Batch<BC, ColRw<BC, E>>, - col_reader: &'db UpgradableReadGuard<'db, ColInner<BC, E>>, + col_reader: &'tx UpgradableReadGuard<'tx, ColInner<BC, E>>, } -impl<'db, BC: BackendCol, E: EventTrait> Debug for TxColRw<'db, BC, E> { +impl<'tx, BC: BackendCol, E: EventTrait> Debug for TxColRw<'tx, BC, E> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("LevelDbCol") .field("batch", &format!("{:?}", self.batch)) @@ -33,12 +33,12 @@ impl<'db, BC: BackendCol, E: EventTrait> Debug for TxColRw<'db, BC, E> { } } -impl<'db, V: ValueZc, BC: BackendCol, E: EventTrait<V = V>> TxColRw<'db, BC, E> { +impl<'tx, V: ValueZc, BC: BackendCol, E: EventTrait<V = V>> TxColRw<'tx, BC, E> { pub fn get_ref<D, F: Fn(&V::Ref) -> KvResult<D>>(&self, k: &E::K, f: F) -> KvResult<Option<D>> { self.col_reader.backend_col.get_ref::<E::K, V, D, F>(k, f) } } -impl<'db, V: ValueSliceZc, BC: BackendCol, E: EventTrait<V = V>> TxColRw<'db, BC, E> { +impl<'tx, V: ValueSliceZc, BC: BackendCol, E: EventTrait<V = V>> TxColRw<'tx, BC, E> { pub fn get_ref_slice<D, F: Fn(&[V::Elem]) -> KvResult<D>>( &self, k: &E::K, @@ -50,12 +50,7 @@ impl<'db, V: ValueSliceZc, BC: BackendCol, E: EventTrait<V = V>> TxColRw<'db, BC } } -impl<'db, BC: BackendCol, E: EventTrait> TxColRw<'db, BC, E> { - /*type BackendCol = BC; - type K = E::K; - type V = E::V; - type Event = E;*/ - +impl<'tx, BC: BackendCol, E: EventTrait> TxColRw<'tx, BC, E> { #[inline(always)] pub fn count(&self) -> KvResult<usize> { self.col_reader.backend_col.count() @@ -73,7 +68,7 @@ impl<'db, BC: BackendCol, E: EventTrait> TxColRw<'db, BC, E> { #[allow(clippy::type_complexity)] #[inline(always)] /// Don't worry about complex iter type. Use it like an `impl Iterator<Item=KvResult<(K, V)>>`. - pub fn iter<'tx, D, R, F>(&'tx self, range: R, f: F) -> D + pub fn iter<D, R, F>(&'tx self, range: R, f: F) -> D where D: Send + Sync, R: 'static + RangeBounds<E::K>, @@ -89,19 +84,16 @@ impl<'db, BC: BackendCol, E: EventTrait> TxColRw<'db, BC, E> { ) -> D, { let range_bytes = crate::iter::convert_range::<E::K, R>(range); - let backend_iter = self - .col_reader - .backend_col - .iter::<E::K, E::V>(range_bytes.clone()); - f(KvIter::new( - BackendTxIter::new(backend_iter, &self.batch.tree), - range_bytes, - )) + let backend_iter = self.col_reader.backend_col.iter::<E::K, E::V>(range_bytes); + f(KvIter::new(BackendTxIter::new( + backend_iter, + &self.batch.tree, + ))) } #[allow(clippy::type_complexity)] #[inline(always)] /// Don't worry about complex iter type. Use it like an `impl Iterator<Item=KvResult<(K, V)>>`. - pub fn iter_rev<'tx, D, R, F>(&'tx self, range: R, f: F) -> D + pub fn iter_rev<D, R, F>(&'tx self, range: R, f: F) -> D where D: Send + Sync, R: 'static + RangeBounds<E::K>, @@ -117,15 +109,10 @@ impl<'db, BC: BackendCol, E: EventTrait> TxColRw<'db, BC, E> { ) -> D, { let range_bytes = crate::iter::convert_range::<E::K, R>(range); - let backend_iter = self - .col_reader - .backend_col - .iter::<E::K, E::V>(range_bytes.clone()); + let backend_iter = self.col_reader.backend_col.iter::<E::K, E::V>(range_bytes); f(KvIter::new( - BackendTxIter::new(backend_iter, &self.batch.tree), - range_bytes, - ) - .reverse()) + BackendTxIter::new(backend_iter, &self.batch.tree).reverse(), + )) } } @@ -138,7 +125,7 @@ pub trait DbTxCollectionRw { fn upsert(&mut self, k: Self::K, v: Self::V); } -impl<'db, BC: BackendCol, E: EventTrait> DbTxCollectionRw for TxColRw<'db, BC, E> { +impl<'tx, BC: BackendCol, E: EventTrait> DbTxCollectionRw for TxColRw<'tx, BC, E> { type K = E::K; type V = E::V; type Event = E; @@ -153,16 +140,16 @@ impl<'db, BC: BackendCol, E: EventTrait> DbTxCollectionRw for TxColRw<'db, BC, E } } -pub trait TransactionalWrite<'db, BC: BackendCol> { +pub trait TransactionalWrite<'tx, BC: BackendCol> { type TxCols; - fn write<D, F: FnOnce(Self::TxCols) -> KvResult<D>>(&'db self, f: F) -> KvResult<D>; + fn write<D, F: FnOnce(Self::TxCols) -> KvResult<D>>(&'tx self, f: F) -> KvResult<D>; } -impl<'db, BC: BackendCol, E: EventTrait> TransactionalWrite<'db, BC> for &'db ColRw<BC, E> { - type TxCols = TxColRw<'db, BC, E>; +impl<'tx, BC: BackendCol, E: EventTrait> TransactionalWrite<'tx, BC> for &'tx ColRw<BC, E> { + type TxCols = TxColRw<'tx, BC, E>; - fn write<D, F: FnOnce(Self::TxCols) -> KvResult<D>>(&'db self, f: F) -> KvResult<D> { + fn write<D, F: FnOnce(Self::TxCols) -> KvResult<D>>(&'tx self, f: F) -> KvResult<D> { let upgradable_guard = self.inner.inner.upgradable_read(); let mut batch = Batch::<BC, ColRw<BC, E>>::default(); @@ -189,13 +176,13 @@ impl<'db, BC: BackendCol, E: EventTrait> TransactionalWrite<'db, BC> for &'db Co macro_rules! impl_transactional_write { ($($i:literal),*) => { paste::paste! { - impl<'db, BC: BackendCol $( ,[<E $i>]: EventTrait)*> TransactionalWrite<'db, BC> - for ($(&'db ColRw<BC, [<E $i>]>, )*) + impl<'tx, BC: BackendCol $( ,[<E $i>]: EventTrait)*> TransactionalWrite<'tx, BC> + for ($(&'tx ColRw<BC, [<E $i>]>, )*) { - type TxCols = ($(TxColRw<'db, BC, [<E $i>]>, )*); + type TxCols = ($(TxColRw<'tx, BC, [<E $i>]>, )*); fn write<D, F: FnOnce(Self::TxCols) -> KvResult<D>>( - &'db self, + &'tx self, f: F, ) -> KvResult<D> { $(let [<upgradable_guard_ $i>] = self.$i.inner.inner.upgradable_read();)* diff --git a/rust-libs/tools/kv_typed/src/value.rs b/rust-libs/tools/kv_typed/src/value.rs index 92f0afd877a88cbcd55e17501e32dfb0393522f7..e55ecbf615cc5bf241df3d5ab597376bac5116ff 100644 --- a/rust-libs/tools/kv_typed/src/value.rs +++ b/rust-libs/tools/kv_typed/src/value.rs @@ -54,6 +54,10 @@ pub trait ValueZc: Value { type Ref: Sized + zerocopy::AsBytes + zerocopy::FromBytes; } +impl ValueZc for () { + type Ref = (); +} + macro_rules! impl_value_zc_for_numbers { ($($T:ty),*) => {$( impl ValueZc for $T { @@ -61,7 +65,6 @@ macro_rules! impl_value_zc_for_numbers { } )*}; } - impl_value_zc_for_numbers!( usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64 ); @@ -74,6 +77,14 @@ pub trait ValueSliceZc: Value { } } +impl ValueSliceZc for () { + type Elem = (); + + fn prefix_len() -> usize { + 0 + } +} + impl ValueSliceZc for String { type Elem = u8; diff --git a/rust-libs/tools/kv_typed/tests/test_db_schema.rs b/rust-libs/tools/kv_typed/tests/test_db_schema.rs index 63f0cada21106fda528aafe03c56d834eb393dd6..3722783da33877a0374f8089d00216fe01f12271 100644 --- a/rust-libs/tools/kv_typed/tests/test_db_schema.rs +++ b/rust-libs/tools/kv_typed/tests/test_db_schema.rs @@ -8,7 +8,7 @@ db_schema!( [ ["c1", Col1, i32, String], ["c2", Col2, usize, ()], - ["c3", Col3, u64, Vec<u128>], + ["c3", Col3, U32BE, Vec<u128>], ["c4", Col4, u64, BTreeSet<u128>], ] ); @@ -25,7 +25,7 @@ fn test_macro_db() { vec![ ("col1", "i32", "String"), ("col2", "usize", "()"), - ("col3", "u64", "Vec<u128>"), + ("col3", "U32BE", "Vec<u128>"), ("col4", "u64", "BTreeSet<u128>") ] ); @@ -111,8 +111,8 @@ fn test_db<B: Backend>(db: &TestV1Db<B>) -> KvResult<()> { Ok::<(), KvError>(()) })?; - db.col3_write().upsert(4, vec![1, 2, 3])?; - db.col3().get_ref_slice(&4, |numbers| { + db.col3_write().upsert(U32BE(4), vec![1, 2, 3])?; + db.col3().get_ref_slice(&U32BE(4), |numbers| { assert_eq!(numbers, &[1, 2, 3]); Ok(()) })?; @@ -126,6 +126,13 @@ fn test_db<B: Backend>(db: &TestV1Db<B>) -> KvResult<()> { Ok(()) })?; + // Test iter_ref_slice + let vec: Vec<(U32BE, Vec<u128>)> = db + .col3() + .iter_ref_slice(.., |k, v_slice| Ok((k.into(), Vec::from(v_slice)))) + .collect::<KvResult<_>>()?; + assert_eq!(vec, vec![(U32BE(4), vec![1, 2, 3])]); + // Test transactional // A read tx should be opened when write tx not commited let (s1, r1) = flume::bounded::<()>(0); @@ -134,14 +141,14 @@ fn test_db<B: Backend>(db: &TestV1Db<B>) -> KvResult<()> { let read_task = std::thread::spawn(move || { r1.recv().expect("disconnected"); (db_ro.col3(), db_ro.col4(), db_ro.col2()).read(|(c3, c4, _c2)| { - c3.get_ref_slice(&4, |numbers| { + c3.get_ref_slice(&U32BE(4), |numbers| { assert_eq!(numbers, &[1, 2, 3]); Ok(()) })?; c3.iter(.., |it| { let iter = it.keys(); s2.send(()).expect("disconnected"); - assert_eq!(iter.collect::<KvResult<Vec<_>>>()?, vec![4]); + assert_eq!(iter.collect::<KvResult<Vec<_>>>()?, vec![U32BE(4)]); Ok::<(), KvError>(()) })?; c4.get_ref_slice(&4, |numbers| { @@ -157,31 +164,34 @@ fn test_db<B: Backend>(db: &TestV1Db<B>) -> KvResult<()> { s1.send(()).expect("disconnected"); assert_eq!( c3.iter(.., |it| it.keys().collect::<KvResult<Vec<_>>>())?, - vec![4] + vec![U32BE(4)] ); assert_eq!( c3.iter(.., |it| it.values().collect::<KvResult<Vec<_>>>())?, vec![vec![1, 2, 3]] ); - c3.upsert(42, vec![5, 4, 6]); + c3.upsert(U32BE(42), vec![5, 4, 6]); assert_eq!( c3.iter(.., |it| it.keys().collect::<KvResult<Vec<_>>>())?, - vec![4, 42] + vec![U32BE(4), U32BE(42)] ); assert_eq!( c3.iter_rev(.., |it| it.keys().collect::<KvResult<Vec<_>>>())?, - vec![42, 4] + vec![U32BE(42), U32BE(4)] ); - c3.upsert(8, vec![11, 12, 13]); - c3.remove(4); + c3.upsert(U32BE(8), vec![11, 12, 13]); + c3.remove(U32BE(4)); assert_eq!( c3.iter(.., |it| it.keys().collect::<KvResult<Vec<_>>>())?, - vec![8, 42] + vec![U32BE(8), U32BE(42)] ); c3.iter_rev(.., |it| { let iter = it.keys(); r2.recv().expect("disconnected"); - assert_eq!(iter.collect::<KvResult<Vec<_>>>()?, vec![42, 8]); + assert_eq!( + iter.collect::<KvResult<Vec<_>>>()?, + vec![U32BE(42), U32BE(8)] + ); Ok::<(), KvError>(()) })?;