From 9d7e674ce5439d8c05965f94f20b575acdaf4d53 Mon Sep 17 00:00:00 2001 From: Gerd Zellweger Date: Mon, 22 Dec 2025 17:33:33 -0800 Subject: [PATCH 1/6] [storage] None optimization for ArchivedTup's. - Stores None's as 1-bit in a bitmap - In case something isn't None, store as the value in a dynamically sized-list - Support handling old format by passing version to deserializer Signed-off-by: Gerd Zellweger --- crates/dbsp/src/dynamic/pair.rs | 8 +- crates/dbsp/src/dynamic/rkyv.rs | 52 +- crates/dbsp/src/operator/group/custom_ord.rs | 8 +- crates/dbsp/src/storage/file.rs | 54 +- crates/dbsp/src/storage/file/reader.rs | 73 +- .../dbsp/src/storage/file/reader/bulk_rows.rs | 8 +- .../storage/file/reader/fetch_indexed_zset.rs | 2 + .../src/storage/file/reader/fetch_zset.rs | 1 + crates/dbsp/src/storage/file/test.rs | 121 +++ crates/dbsp/src/storage/file/writer.rs | 2 + crates/dbsp/src/trace.rs | 4 +- crates/dbsp/src/trace/spine_async.rs | 9 +- crates/dbsp/src/typed_batch.rs | 6 +- crates/feldera-macros/Cargo.toml | 2 + crates/feldera-macros/src/tuples.rs | 360 ++++++- crates/feldera-macros/tests/compile.rs | 897 ++++++++++++++++++ .../tests/declare_tuple_rkyv.rs | 107 +++ 17 files changed, 1651 insertions(+), 63 deletions(-) create mode 100644 crates/feldera-macros/tests/compile.rs create mode 100644 crates/feldera-macros/tests/declare_tuple_rkyv.rs diff --git a/crates/dbsp/src/dynamic/pair.rs b/crates/dbsp/src/dynamic/pair.rs index 5e494632a6..59e5bf8ed2 100644 --- a/crates/dbsp/src/dynamic/pair.rs +++ b/crates/dbsp/src/dynamic/pair.rs @@ -100,17 +100,17 @@ where Trait2: DataTrait + ?Sized, { fn fst(&self) -> &Trait1::Archived { - >::erase_archived(&self.0) + >::erase_archived(self.get_t0()) } fn snd(&self) -> &Trait2::Archived { - >::erase_archived(&self.1) + >::erase_archived(self.get_t1()) } fn split(&self) -> (&Trait1::Archived, &Trait2::Archived) { ( - >::erase_archived(&self.0), - >::erase_archived(&self.1), + >::erase_archived(self.get_t0()), + >::erase_archived(self.get_t1()), ) } } diff --git a/crates/dbsp/src/dynamic/rkyv.rs b/crates/dbsp/src/dynamic/rkyv.rs index 57b29496ca..aa6fe75a87 100644 --- a/crates/dbsp/src/dynamic/rkyv.rs +++ b/crates/dbsp/src/dynamic/rkyv.rs @@ -3,10 +3,7 @@ use crate::{ derive_comparison_traits, storage::file::{Deserializer, Serializer}, }; -use rkyv::{ - Archive, Archived, Deserialize, Fallible, Serialize, archived_value, - de::deserializers::SharedDeserializeMap, -}; +use rkyv::{Archive, Archived, Deserialize, Fallible, Serialize, archived_value}; use std::{cmp::Ordering, marker::PhantomData, mem::transmute}; /// Trait for DBData that can be deserialized with [`rkyv`]. @@ -42,7 +39,24 @@ pub trait DeserializableDyn { /// /// The offset must store a valid serialized value of the /// concrete type that `self` points to. - unsafe fn deserialize_from_bytes(&mut self, bytes: &[u8], pos: usize); + unsafe fn deserialize_from_bytes_with( + &mut self, + bytes: &[u8], + pos: usize, + deserializer: &mut Deserializer, + ); + + /// Deserialize `self` from the given slice and offset using the default + /// deserializer configuration. + /// + /// # Safety + /// + /// The offset must store a valid serialized value of the + /// concrete type that `self` points to. + unsafe fn deserialize_from_bytes(&mut self, bytes: &[u8], pos: usize) { + let mut deserializer = Deserializer::default(); + unsafe { self.deserialize_from_bytes_with(bytes, pos, &mut deserializer) }; + } } impl SerializeDyn for T @@ -60,20 +74,28 @@ impl DeserializableDyn for T where T: ArchivedDBData, { - unsafe fn deserialize_from_bytes(&mut self, bytes: &[u8], pos: usize) { + unsafe fn deserialize_from_bytes_with( + &mut self, + bytes: &[u8], + pos: usize, + deserializer: &mut Deserializer, + ) { unsafe { let archived: &::Archived = archived_value::(bytes, pos); - *self = archived - .deserialize(&mut SharedDeserializeMap::new()) - .unwrap(); + *self = archived.deserialize(deserializer).unwrap(); } } } /// Object-safe version of the `Deserialize` trait. pub trait DeserializeDyn: AsAny + Comparable { - fn deserialize(&self, target: &mut Trait); + fn deserialize_with(&self, target: &mut Trait, deserializer: &mut Deserializer); + + fn deserialize(&self, target: &mut Trait) { + let mut deserializer = Deserializer::default(); + self.deserialize_with(target, &mut deserializer); + } fn eq_target(&self, target: &Trait) -> bool; fn cmp_target(&self, target: &Trait) -> Option; @@ -143,23 +165,25 @@ where T: ArchivedDBData + Eq + Ord + 'static, Trait: DowncastTrait + ?Sized + 'static, { - fn deserialize(&self, target: &mut Trait) { + fn deserialize_with(&self, target: &mut Trait, deserializer: &mut Deserializer) { *unsafe { target.downcast_mut::() } = self .archived - .deserialize(&mut SharedDeserializeMap::new()) + .deserialize(deserializer) .unwrap() } fn eq_target(&self, other: &Trait) -> bool { + let mut deserializer = Deserializer::default(); self.archived - .deserialize(&mut SharedDeserializeMap::new()) + .deserialize(&mut deserializer) .unwrap() .eq(unsafe { other.downcast::() }) } fn cmp_target(&self, other: &Trait) -> Option { + let mut deserializer = Deserializer::default(); self.archived - .deserialize(&mut SharedDeserializeMap::new()) + .deserialize(&mut deserializer) .unwrap() .partial_cmp(unsafe { other.downcast::() }) } diff --git a/crates/dbsp/src/operator/group/custom_ord.rs b/crates/dbsp/src/operator/group/custom_ord.rs index e8c31ba9d2..285f264ea7 100644 --- a/crates/dbsp/src/operator/group/custom_ord.rs +++ b/crates/dbsp/src/operator/group/custom_ord.rs @@ -1,6 +1,6 @@ -use crate::trace::Deserializable; +use crate::trace::{Deserializable, Deserializer}; use feldera_macros::IsNone; -use rkyv::{Archive, Deserialize, Serialize, de::deserializers::SharedDeserializeMap}; +use rkyv::{Archive, Deserialize, Serialize}; use size_of::SizeOf; use std::{ cmp::Ordering, @@ -162,11 +162,11 @@ where // the Archived (we already know that T::Archived implements Ord). let real_self: T = self .val - .deserialize(&mut SharedDeserializeMap::new()) + .deserialize(&mut Deserializer::default()) .unwrap(); let real_other: T = other .val - .deserialize(&mut SharedDeserializeMap::new()) + .deserialize(&mut Deserializer::default()) .unwrap(); F::cmp(&real_self, &real_other) } diff --git a/crates/dbsp/src/storage/file.rs b/crates/dbsp/src/storage/file.rs index 08155c5ce2..5d936bf278 100644 --- a/crates/dbsp/src/storage/file.rs +++ b/crates/dbsp/src/storage/file.rs @@ -73,6 +73,7 @@ use crate::{ storage::buffer_cache::{FBuf, FBufSerializer}, }; use rkyv::de::deserializers::SharedDeserializeMap; +use rkyv::de::{SharedDeserializeRegistry, SharedPointer}; use rkyv::{ Archive, Archived, Deserialize, Fallible, Serialize, ser::{ @@ -279,7 +280,58 @@ pub type Serializer = CompositeSerializer, DbspScratch, Sha pub type DbspScratch = FallbackScratch, AllocScratch>; /// The particular [`rkyv`] deserializer that we use. -pub type Deserializer = SharedDeserializeMap; +#[derive(Debug)] +pub struct Deserializer { + version: u32, + inner: SharedDeserializeMap, +} + +impl Deserializer { + /// Create a deserializer configured for the given file format version. + pub fn new(version: u32) -> Self { + Self { + version, + inner: SharedDeserializeMap::new(), + } + } + + /// Create a deserializer with a preallocated shared pointer map. + pub fn with_capacity(version: u32, capacity: usize) -> Self { + Self { + version, + inner: SharedDeserializeMap::with_capacity(capacity), + } + } + + /// Return the file format version this deserializer targets. + pub fn version(&self) -> u32 { + self.version + } +} + +impl Default for Deserializer { + fn default() -> Self { + Self::new(format::VERSION_NUMBER) + } +} + +impl Fallible for Deserializer { + type Error = ::Error; +} + +impl SharedDeserializeRegistry for Deserializer { + fn get_shared_ptr(&mut self, ptr: *const u8) -> Option<&dyn SharedPointer> { + self.inner.get_shared_ptr(ptr) + } + + fn add_shared_ptr( + &mut self, + ptr: *const u8, + shared: Box, + ) -> Result<(), Self::Error> { + self.inner.add_shared_ptr(ptr, shared) + } +} /// Creates an instance of [Serializer] that will serialize to `serializer` and /// passes it to `f`. Returns a tuple of the `FBuf` from the [Serializer] and diff --git a/crates/dbsp/src/storage/file/reader.rs b/crates/dbsp/src/storage/file/reader.rs index 31f5cafccf..319a850351 100644 --- a/crates/dbsp/src/storage/file/reader.rs +++ b/crates/dbsp/src/storage/file/reader.rs @@ -3,7 +3,7 @@ //! [`Reader`] is the top-level interface for reading layer files. use super::format::{Compression, FileTrailer}; -use super::{AnyFactories, Factories}; +use super::{AnyFactories, Deserializer, Factories}; use crate::dynamic::{DynVec, WeightTrait}; use crate::storage::buffer_cache::{CacheAccess, CacheEntry}; use crate::storage::file::format::FilterBlock; @@ -463,6 +463,7 @@ where value_map: ValueMapReader, row_groups: Option, first_row: u64, + version: u32, _phantom: PhantomData, } @@ -485,6 +486,7 @@ where raw: Arc, location: BlockLocation, first_row: u64, + version: u32, ) -> Result { let header = DataBlockHeader::read_le(&mut io::Cursor::new(raw.as_slice())).map_err(|e| { @@ -510,6 +512,7 @@ where )?, raw, first_row, + version, _phantom: PhantomData, }) } @@ -519,8 +522,14 @@ where node: &TreeNode, cache: &BufferCache, file_id: FileId, + version: u32, ) -> Result, Error> { - let block = Arc::new(Self::from_raw(raw, node.location, node.rows.start)?); + let block = Arc::new(Self::from_raw( + raw, + node.location, + node.rows.start, + version, + )?); cache.insert(file_id, node.location.offset, block.clone()); Ok(block) } @@ -545,8 +554,13 @@ where ), None => { let block = file.read_block(node.location)?; - let entry = - Self::from_raw_with_cache(block, node, &cache, file.file_handle.file_id())?; + let entry = Self::from_raw_with_cache( + block, + node, + &cache, + file.file_handle.file_id(), + file.version, + )?; (CacheAccess::Miss, entry) } }; @@ -620,8 +634,10 @@ where unsafe fn item(&self, factories: &Factories, index: usize, item: (&mut K, &mut A)) { unsafe { let archived_item = self.archived_item(factories, index); - DeserializeDyn::deserialize(archived_item.fst(), item.0); - DeserializeDyn::deserialize(archived_item.snd(), item.1); + let mut deserializer = Deserializer::new(self.version); + DeserializeDyn::deserialize_with(archived_item.fst(), item.0, &mut deserializer); + let mut deserializer = Deserializer::new(self.version); + DeserializeDyn::deserialize_with(archived_item.snd(), item.1, &mut deserializer); } } unsafe fn item_for_row(&self, factories: &Factories, row: u64, item: (&mut K, &mut A)) { @@ -633,13 +649,15 @@ where unsafe fn key(&self, factories: &Factories, index: usize, key: &mut K) { unsafe { let item = self.archived_item(factories, index); - DeserializeDyn::deserialize(item.fst(), key) + let mut deserializer = Deserializer::new(self.version); + DeserializeDyn::deserialize_with(item.fst(), key, &mut deserializer) } } unsafe fn aux(&self, factories: &Factories, index: usize, aux: &mut A) { unsafe { let item = self.archived_item(factories, index); - DeserializeDyn::deserialize(item.snd(), aux) + let mut deserializer = Deserializer::new(self.version); + DeserializeDyn::deserialize_with(item.snd(), aux, &mut deserializer) } } unsafe fn key_for_row(&self, factories: &Factories, row: u64, key: &mut K) { @@ -824,13 +842,14 @@ where node: &TreeNode, cache: &BufferCache, file_id: FileId, + version: u32, ) -> Result { match node.node_type { NodeType::Data => Ok(Self::Data(DataBlock::from_raw_with_cache( - raw, node, cache, file_id, + raw, node, cache, file_id, version, )?)), NodeType::Index => Ok(Self::Index(IndexBlock::from_raw_with_cache( - raw, node, cache, file_id, + raw, node, cache, file_id, version, )?)), } } @@ -865,6 +884,7 @@ where child_offsets: VarintReader, child_sizes: VarintReader, first_row: u64, + version: u32, _phantom: PhantomData, } @@ -885,6 +905,7 @@ where raw: Arc, location: BlockLocation, first_row: u64, + version: u32, ) -> Result { let header = IndexBlockHeader::read_le(&mut io::Cursor::new(raw.as_slice())).map_err(|e| { @@ -941,6 +962,7 @@ where )?, raw, first_row, + version, _phantom: PhantomData, }) } @@ -950,8 +972,14 @@ where node: &TreeNode, cache: &BufferCache, file_id: FileId, + version: u32, ) -> Result, Error> { - let block = Arc::new(Self::from_raw(raw, node.location, node.rows.start)?); + let block = Arc::new(Self::from_raw( + raw, + node.location, + node.rows.start, + version, + )?); cache.insert(file_id, node.location.offset, block.clone()); Ok(block) } @@ -982,8 +1010,13 @@ where } None => { let block = file.read_block(node.location)?; - let entry = - Self::from_raw_with_cache(block, node, &cache, file.file_handle.file_id())?; + let entry = Self::from_raw_with_cache( + block, + node, + &cache, + file.file_handle.file_id(), + file.version, + )?; (CacheAccess::Miss, entry) } }; @@ -1072,7 +1105,8 @@ where unsafe fn get_bound(&self, index: usize, bound: &mut K) { unsafe { let offset = self.bounds.get(&self.raw, index) as usize; - bound.deserialize_from_bytes(&self.raw, offset) + let mut deserializer = Deserializer::new(self.version); + bound.deserialize_from_bytes_with(&self.raw, offset, &mut deserializer) } } @@ -1318,6 +1352,7 @@ struct ImmutableFileRef { file_handle: Arc, compression: Option, stats: AtomicCacheStats, + version: u32, } impl Debug for ImmutableFileRef { @@ -1339,12 +1374,14 @@ impl ImmutableFileRef { file_handle: Arc, compression: Option, stats: AtomicCacheStats, + version: u32, ) -> Self { Self { cache, file_handle, compression, stats, + version, } } @@ -1583,7 +1620,13 @@ where }; Ok(Self { - file: ImmutableFileRef::new(cache, file, file_trailer.compression, stats), + file: ImmutableFileRef::new( + cache, + file, + file_trailer.compression, + stats, + file_trailer.version, + ), columns, bloom_filter, _phantom: PhantomData, diff --git a/crates/dbsp/src/storage/file/reader/bulk_rows.rs b/crates/dbsp/src/storage/file/reader/bulk_rows.rs index 858dace8e9..e317a5f865 100644 --- a/crates/dbsp/src/storage/file/reader/bulk_rows.rs +++ b/crates/dbsp/src/storage/file/reader/bulk_rows.rs @@ -216,7 +216,13 @@ where { let raw = decompress(self.reader.file.compression, node.location, result?)?; let file_id = self.reader.file.file_handle.file_id(); - let tree_block = TreeBlock::from_raw_with_cache(raw, &node, &self.cache, file_id)?; + let tree_block = TreeBlock::from_raw_with_cache( + raw, + &node, + &self.cache, + file_id, + self.reader.file.version, + )?; match tree_block { TreeBlock::Data(data_block) => self.received_data(data_block), TreeBlock::Index(index_block) => self.indexes[level].received(index_block), diff --git a/crates/dbsp/src/storage/file/reader/fetch_indexed_zset.rs b/crates/dbsp/src/storage/file/reader/fetch_indexed_zset.rs index e6c0bf0dca..94f0f4ae35 100644 --- a/crates/dbsp/src/storage/file/reader/fetch_indexed_zset.rs +++ b/crates/dbsp/src/storage/file/reader/fetch_indexed_zset.rs @@ -266,6 +266,7 @@ where &read.node, &self.cache, self.reader.file_handle().file_id(), + self.reader.file.version, ) .unwrap(); self.process_read(&read.keys, tree_block, reads)?; @@ -581,6 +582,7 @@ where &read.node, &self.cache, self.reader.file_handle().file_id(), + self.reader.file.version, ) .unwrap(); self.process_read(read.keys, tree_block, reads)?; diff --git a/crates/dbsp/src/storage/file/reader/fetch_zset.rs b/crates/dbsp/src/storage/file/reader/fetch_zset.rs index da9261960c..a8853bdafe 100644 --- a/crates/dbsp/src/storage/file/reader/fetch_zset.rs +++ b/crates/dbsp/src/storage/file/reader/fetch_zset.rs @@ -193,6 +193,7 @@ where &read.node, &self.cache, self.reader.file_handle().file_id(), + self.reader.file.version, ) .unwrap(); self.process_read(&read.keys, tree_block, reads)?; diff --git a/crates/dbsp/src/storage/file/test.rs b/crates/dbsp/src/storage/file/test.rs index c77463f1cf..7f53e69159 100644 --- a/crates/dbsp/src/storage/file/test.rs +++ b/crates/dbsp/src/storage/file/test.rs @@ -32,6 +32,112 @@ use feldera_types::config::{StorageConfig, StorageOptions}; use rand::{Rng, seq::SliceRandom, thread_rng}; use tempfile::tempdir; +feldera_macros::declare_tuple! { + Tup65< + T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, + T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, + T36, T37, T38, T39, T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50, T51, T52, + T53, T54, T55, T56, T57, T58, T59, T60, T61, T62, T63, T64 + > +} + +type OptString = Option; +type Tup65OptString = Tup65< + OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, + OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, + OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, + OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, + OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, + OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, + OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, + OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, + OptString +>; + +// Map bits to fields in MSB->LSB order so row indices remain lexicographically sorted. +fn bit_set(bits: u128, idx: usize) -> bool { + debug_assert!(idx < 65); + ((bits >> (64 - idx)) & 1) != 0 +} + +fn opt_str(bit: bool) -> Option { + if bit { + Some("abc".to_string()) + } else { + None + } +} + +fn tup65_from_bits(bits: u128) -> Tup65OptString { + Tup65( + opt_str(bit_set(bits, 0)), + opt_str(bit_set(bits, 1)), + opt_str(bit_set(bits, 2)), + opt_str(bit_set(bits, 3)), + opt_str(bit_set(bits, 4)), + opt_str(bit_set(bits, 5)), + opt_str(bit_set(bits, 6)), + opt_str(bit_set(bits, 7)), + opt_str(bit_set(bits, 8)), + opt_str(bit_set(bits, 9)), + opt_str(bit_set(bits, 10)), + opt_str(bit_set(bits, 11)), + opt_str(bit_set(bits, 12)), + opt_str(bit_set(bits, 13)), + opt_str(bit_set(bits, 14)), + opt_str(bit_set(bits, 15)), + opt_str(bit_set(bits, 16)), + opt_str(bit_set(bits, 17)), + opt_str(bit_set(bits, 18)), + opt_str(bit_set(bits, 19)), + opt_str(bit_set(bits, 20)), + opt_str(bit_set(bits, 21)), + opt_str(bit_set(bits, 22)), + opt_str(bit_set(bits, 23)), + opt_str(bit_set(bits, 24)), + opt_str(bit_set(bits, 25)), + opt_str(bit_set(bits, 26)), + opt_str(bit_set(bits, 27)), + opt_str(bit_set(bits, 28)), + opt_str(bit_set(bits, 29)), + opt_str(bit_set(bits, 30)), + opt_str(bit_set(bits, 31)), + opt_str(bit_set(bits, 32)), + opt_str(bit_set(bits, 33)), + opt_str(bit_set(bits, 34)), + opt_str(bit_set(bits, 35)), + opt_str(bit_set(bits, 36)), + opt_str(bit_set(bits, 37)), + opt_str(bit_set(bits, 38)), + opt_str(bit_set(bits, 39)), + opt_str(bit_set(bits, 40)), + opt_str(bit_set(bits, 41)), + opt_str(bit_set(bits, 42)), + opt_str(bit_set(bits, 43)), + opt_str(bit_set(bits, 44)), + opt_str(bit_set(bits, 45)), + opt_str(bit_set(bits, 46)), + opt_str(bit_set(bits, 47)), + opt_str(bit_set(bits, 48)), + opt_str(bit_set(bits, 49)), + opt_str(bit_set(bits, 50)), + opt_str(bit_set(bits, 51)), + opt_str(bit_set(bits, 52)), + opt_str(bit_set(bits, 53)), + opt_str(bit_set(bits, 54)), + opt_str(bit_set(bits, 55)), + opt_str(bit_set(bits, 56)), + opt_str(bit_set(bits, 57)), + opt_str(bit_set(bits, 58)), + opt_str(bit_set(bits, 59)), + opt_str(bit_set(bits, 60)), + opt_str(bit_set(bits, 61)), + opt_str(bit_set(bits, 62)), + opt_str(bit_set(bits, 63)), + opt_str(bit_set(bits, 64)), + ) +} + fn test_buffer_cache() -> Arc { thread_local! { static BUFFER_CACHE: Arc = Arc::new(BufferCache::new(1024 * 1024)); @@ -929,6 +1035,21 @@ fn test_tuple() { }); } +#[test] +fn test_tup65_option_string() { + init_test_logger(); + let n = 10_000usize; + for_each_compression_type(Parameters::default(), |parameters| { + test_one_column(n, |row| { + let bits = row as u128 * 2 + 1; + let before = tup65_from_bits(bits - 1); + let key = tup65_from_bits(bits); + let after = tup65_from_bits(bits + 1); + (before, key, after, ()) + }, parameters); + }); +} + #[test] fn test_big_values() { fn v(row: usize) -> Vec { diff --git a/crates/dbsp/src/storage/file/writer.rs b/crates/dbsp/src/storage/file/writer.rs index 437500c4f0..82c395f304 100644 --- a/crates/dbsp/src/storage/file/writer.rs +++ b/crates/dbsp/src/storage/file/writer.rs @@ -311,6 +311,7 @@ impl ColumnWriter { }, &block_writer.cache, block_writer.file_handle.file_id(), + VERSION_NUMBER, ) .unwrap(); @@ -347,6 +348,7 @@ impl ColumnWriter { }, &block_writer.cache, block_writer.file_handle.file_id(), + VERSION_NUMBER, ) .unwrap(); diff --git a/crates/dbsp/src/trace.rs b/crates/dbsp/src/trace.rs index 9367bf4244..0939938876 100644 --- a/crates/dbsp/src/trace.rs +++ b/crates/dbsp/src/trace.rs @@ -69,7 +69,7 @@ pub use ord::{ VecWSetFactories, }; -use rkyv::{Deserialize, archived_root, de::deserializers::SharedDeserializeMap}; +use rkyv::{Deserialize, archived_root}; use crate::{ Error, NumEntries, Timestamp, @@ -129,7 +129,7 @@ pub fn unaligned_deserialize(bytes: &[u8]) -> T { let mut aligned_bytes = FBuf::new(); aligned_bytes.extend_from_slice(bytes); unsafe { archived_root::(&aligned_bytes[..]) } - .deserialize(&mut SharedDeserializeMap::new()) + .deserialize(&mut Deserializer::default()) .unwrap() } diff --git a/crates/dbsp/src/trace/spine_async.rs b/crates/dbsp/src/trace/spine_async.rs index 6726124089..e0548f66dc 100644 --- a/crates/dbsp/src/trace/spine_async.rs +++ b/crates/dbsp/src/trace/spine_async.rs @@ -26,17 +26,14 @@ use crate::{ }, }; -use crate::storage::file::to_bytes; +use crate::storage::file::{Deserializer, to_bytes}; use crate::trace::CommittedSpine; use enum_map::EnumMap; use feldera_storage::{FileCommitter, StoragePath}; use feldera_types::checkpoint::PSpineBatches; use ouroboros::self_referencing; use rand::Rng; -use rkyv::{ - Archive, Archived, Deserialize, Fallible, Serialize, de::deserializers::SharedDeserializeMap, - ser::Serializer, -}; +use rkyv::{Archive, Archived, Deserialize, Fallible, Serialize, ser::Serializer}; use size_of::{Context, SizeOf}; use std::sync::{Arc, MutexGuard}; use std::time::{Duration, Instant}; @@ -1508,7 +1505,7 @@ where let archived = unsafe { rkyv::archived_root::(&content) }; let committed: CommittedSpine = archived - .deserialize(&mut SharedDeserializeMap::new()) + .deserialize(&mut Deserializer::default()) .unwrap(); self.dirty = committed.dirty; self.key_filter = None; diff --git a/crates/dbsp/src/typed_batch.rs b/crates/dbsp/src/typed_batch.rs index 3a534f8a2f..01a633282f 100644 --- a/crates/dbsp/src/typed_batch.rs +++ b/crates/dbsp/src/typed_batch.rs @@ -703,7 +703,7 @@ where #[cfg(test)] #[test] fn test_typedbox_rkyv() { - use rkyv::{archived_value, de::deserializers::SharedDeserializeMap}; + use rkyv::archived_value; let tbox = TypedBox::::new(12345u64); @@ -715,9 +715,7 @@ fn test_typedbox_rkyv() { let archived: & as Archive>::Archived = unsafe { archived_value::>(bytes.as_slice(), 0) }; - let tbox2 = archived - .deserialize(&mut SharedDeserializeMap::new()) - .unwrap(); + let tbox2 = archived.deserialize(&mut Deserializer::default()).unwrap(); assert_eq!(tbox, tbox2); } diff --git a/crates/feldera-macros/Cargo.toml b/crates/feldera-macros/Cargo.toml index cfa45da1c9..d6acb3a795 100644 --- a/crates/feldera-macros/Cargo.toml +++ b/crates/feldera-macros/Cargo.toml @@ -24,6 +24,8 @@ derive_more = { version = "1.0", features = ["not"] } rkyv = { workspace = true, features = ["std", "size_64", "validation"] } serde = { workspace = true, features = ["derive"] } size-of = { workspace = true } +dbsp = { workspace = true } +feldera-sqllib = { workspace = true } [lib] proc-macro = true diff --git a/crates/feldera-macros/src/tuples.rs b/crates/feldera-macros/src/tuples.rs index 1ee055188f..23551c5ada 100644 --- a/crates/feldera-macros/src/tuples.rs +++ b/crates/feldera-macros/src/tuples.rs @@ -18,17 +18,20 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { .enumerate() .map(|(idx, _e)| format_ident!("other_t{}", idx)) // Generate lowercase t0, t1, ... .collect::>(); - let archive_bounds = elements - .iter() - .map(|e| quote!(#e: rkyv::Archive, <#e as rkyv::Archive>::Archived: Ord,)) - .map(|e| e.to_string()) - .fold(String::new(), |a, b| format!("{} {}", a, b)); let self_indexes = elements .iter() .enumerate() .map(|(idx, _e)| Index::from(idx)) .collect::>(); let num_elements = elements.len(); + let bitmap_words = num_elements.div_ceil(64); + let bitmap_word_indexes = (0..bitmap_words).map(Index::from).collect::>(); + let field_ptr_name = format_ident!("{}FieldPtr", name); + let archived_name = format_ident!("Archived{}", name); + let archived_v3_name = format_ident!("Archived{}V3", name); + let resolver_name = format_ident!("{}Resolver", name); + let archived_none_ptr_name = + format_ident!("__{}_archived_none_ptr", name.to_string().to_lowercase()); // Struct definition let struct_def = quote! { @@ -36,13 +39,7 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { Default, Eq, Ord, Clone, Hash, PartialEq, PartialOrd, derive_more::Neg, serde::Serialize, serde::Deserialize, - size_of::SizeOf, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize - )] - #[archive_attr( - derive(Ord, Eq, PartialEq, PartialOrd), - )] - #[archive( - bound(archive = #archive_bounds) + size_of::SizeOf )] pub struct #name<#(#generics),*>( #(pub #generics),* ); }; @@ -204,6 +201,342 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { } }; + let v3_archived_struct = quote! { + #[repr(C)] + pub struct #archived_v3_name<#(#generics),*> + where + #(#generics: ::rkyv::Archive,)* + { + #(pub #fields: ::rkyv::Archived<#generics>),* + } + }; + + let v3_deserialize_impl = quote! { + impl ::rkyv::Deserialize<#name<#(#generics),*>, D> + for #archived_v3_name<#(#generics),*> + where + D: ::rkyv::Fallible + ?Sized, + #(#generics: ::rkyv::Archive,)* + #(::rkyv::Archived<#generics>: ::rkyv::Deserialize<#generics, D>,)* + { + #[inline] + fn deserialize( + &self, + deserializer: &mut D, + ) -> Result<#name<#(#generics),*>, D::Error> { + Ok(#name( #(self.#fields.deserialize(deserializer)?),* )) + } + } + }; + + let get_methods = fields + .iter() + .enumerate() + .zip(generics.iter()) + .map(|((idx, _field), ty)| { + let get_name = format_ident!("get_t{}", idx); + let idx_lit = Index::from(idx); + quote! { + #[inline] + pub fn #get_name(&self) -> &::rkyv::Archived<#ty> { + if self.none_bit_set(#idx_lit) { + // SAFETY: The bitmap only marks `None` for types whose archived + // representation is `ArchivedOption<...>`; a zeroed archived + // option is valid for the `None` variant. + unsafe { &*#archived_none_ptr_name::<#ty>() } + } else { + let ptr_idx = self.idx_for_field(#idx_lit); + debug_assert!(ptr_idx < self.ptrs.len()); + // SAFETY: `ptrs[ptr_idx]` points at the archived field when the bit is clear. + unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(ptr_idx) + .as_ptr() + .cast::<::rkyv::Archived<#ty>>() + } + } + } + } + }); + + let eq_checks = fields.iter().enumerate().map(|(idx, _)| { + let get_name = format_ident!("get_t{}", idx); + quote!(self.#get_name() == other.#get_name()) + }); + + let cmp_checks = fields.iter().enumerate().map(|(idx, _)| { + let get_name = format_ident!("get_t{}", idx); + quote! { + let cmp = self.#get_name().cmp(other.#get_name()); + if cmp != core::cmp::Ordering::Equal { + return cmp; + } + } + }); + + let serialize_fields = + fields + .iter() + .enumerate() + .zip(self_indexes.iter()) + .map(|((idx, _), self_idx)| { + let word_idx = Index::from(idx / 64); + let bit_idx = idx % 64; + quote! { + if ::dbsp::utils::IsNone::is_none(&self.#self_idx) { + bitmap[#word_idx] |= 1u64 << #bit_idx; + } else { + let pos = serializer.serialize_value(&self.#self_idx)?; + ptrs[ptrs_len] = #field_ptr_name { pos }; + ptrs_len += 1; + } + } + }); + + let deserialize_fields = + fields + .iter() + .enumerate() + .zip(generics.iter()) + .map(|((idx, _), ty)| { + let field_name = format_ident!("t{}", idx); + let idx_lit = Index::from(idx); + quote! { + let #field_name = if self.none_bit_set(#idx_lit) { + #ty::default() + } else { + let archived = unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(ptr_idx) + .as_ptr() + .cast::<::rkyv::Archived<#ty>>() + }; + ptr_idx += 1; + archived.deserialize(deserializer)? + }; + } + }); + + let rkyv_impls = quote! { + #[derive(Copy, Clone)] + struct #field_ptr_name { + pos: usize, + } + + impl ::rkyv::Archive for #field_ptr_name { + type Archived = ::rkyv::RawRelPtr; + type Resolver = usize; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + ::rkyv::RawRelPtr::emplace(pos, resolver, out); + } + } + + impl ::rkyv::Serialize for #field_ptr_name + where + S: ::rkyv::ser::Serializer + ?Sized, + { + #[inline] + fn serialize(&self, _serializer: &mut S) -> Result { + Ok(self.pos) + } + } + + #[inline] + unsafe fn #archived_none_ptr_name() -> *const ::rkyv::Archived { + static NONE: ::std::sync::OnceLock = ::std::sync::OnceLock::new(); + let ptr = *NONE.get_or_init(|| { + // This keeps a per-type, properly aligned `Archived` that we can + // reuse when the bitmap indicates a `None` value. + // SAFETY: This is only valid when `Archived` is `ArchivedOption<...>`. + let boxed: Box<::rkyv::Archived> = Box::new(unsafe { ::core::mem::zeroed() }); + Box::into_raw(boxed) as usize + }); + ptr as *const ::rkyv::Archived + } + + #[repr(C)] + pub struct #archived_name<#(#generics),*> + where + #(#generics: ::rkyv::Archive,)* + { + // Bitmap layout: each bit marks a field that was `None` (per `IsNone`). + // `ptrs` stores only the non-`None` values in field order; `idx_for_field` + // computes the offset by counting unset bits before each field. + bitmap: [u64; #bitmap_words], + ptrs: ::rkyv::vec::ArchivedVec<::rkyv::RawRelPtr>, + _phantom: core::marker::PhantomData (#(#generics),*)>, + } + + impl<#(#generics),*> #archived_name<#(#generics),*> + where + #(#generics: ::rkyv::Archive,)* + { + #[inline] + fn none_bit_set(&self, idx: usize) -> bool { + debug_assert!(idx < #num_elements); + let word = idx / 64; + let bit = idx % 64; + (self.bitmap[word] & (1u64 << bit)) != 0 + } + + #[inline] + fn idx_for_field(&self, field_idx: usize) -> usize { + debug_assert!(field_idx < #num_elements); + let word = field_idx / 64; + let bit = field_idx % 64; + let mut idx = 0usize; + let mut w = 0usize; + while w < word { + idx += 64usize - (self.bitmap[w].count_ones() as usize); + w += 1; + } + let mask = if bit == 0 { 0 } else { (1u64 << bit) - 1 }; + let none_before = (self.bitmap[word] & mask).count_ones() as usize; + idx + bit - none_before + } + + #(#get_methods)* + } + + impl<#(#generics),*> core::cmp::PartialEq for #archived_name<#(#generics),*> + where + #(#generics: ::rkyv::Archive,)* + #(::rkyv::Archived<#generics>: core::cmp::PartialEq,)* + { + #[inline] + fn eq(&self, other: &Self) -> bool { + true #(&& #eq_checks)* + } + } + + impl<#(#generics),*> core::cmp::Eq for #archived_name<#(#generics),*> + where + #(#generics: ::rkyv::Archive,)* + #(::rkyv::Archived<#generics>: core::cmp::Eq,)* + {} + + impl<#(#generics),*> core::cmp::PartialOrd for #archived_name<#(#generics),*> + where + #(#generics: ::rkyv::Archive,)* + #(::rkyv::Archived<#generics>: core::cmp::Ord,)* + { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + impl<#(#generics),*> core::cmp::Ord for #archived_name<#(#generics),*> + where + #(#generics: ::rkyv::Archive,)* + #(::rkyv::Archived<#generics>: core::cmp::Ord,)* + { + #[inline] + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + #(#cmp_checks)* + core::cmp::Ordering::Equal + } + } + + pub struct #resolver_name { + bitmap: [u64; #bitmap_words], + ptrs_resolver: ::rkyv::vec::VecResolver, + ptrs_len: usize, + } + + impl<#(#generics),*> ::rkyv::Archive for #name<#(#generics),*> + where + #(#generics: ::rkyv::Archive,)* + { + type Archived = #archived_name<#(#generics),*>; + type Resolver = #resolver_name; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + let (fp, fo) = ::rkyv::out_field!(out.bitmap); + let bitmap_out = fo.cast::(); + #( + u64::resolve( + &resolver.bitmap[#bitmap_word_indexes], + pos + fp + (#bitmap_word_indexes * ::core::mem::size_of::()), + (), + bitmap_out.add(#bitmap_word_indexes), + ); + )* + + let (fp, fo) = ::rkyv::out_field!(out.ptrs); + let vec_pos = pos + fp; + ::rkyv::vec::ArchivedVec::<::rkyv::RawRelPtr>::resolve_from_len( + resolver.ptrs_len, + vec_pos, + resolver.ptrs_resolver, + fo, + ); + + let (_fp, fo) = ::rkyv::out_field!(out._phantom); + fo.write(core::marker::PhantomData); + } + } + + impl ::rkyv::Serialize for #name<#(#generics),*> + where + S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, + #(#generics: ::rkyv::Archive + ::rkyv::Serialize + ::dbsp::utils::IsNone,)* + { + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + let mut bitmap = [0u64; #bitmap_words]; + let mut ptrs: [#field_ptr_name; #num_elements] = + [#field_ptr_name { pos: 0 }; #num_elements]; + let mut ptrs_len = 0usize; + + #(#serialize_fields)* + + let ptrs_resolver = ::rkyv::vec::ArchivedVec::<::rkyv::RawRelPtr>::serialize_from_slice( + &ptrs[..ptrs_len], + serializer, + )?; + + Ok(#resolver_name { + bitmap, + ptrs_resolver, + ptrs_len, + }) + } + } + + impl ::rkyv::Deserialize<#name<#(#generics),*>, D> for #archived_name<#(#generics),*> + where + D: ::rkyv::Fallible + ::core::any::Any, + #(#generics: ::rkyv::Archive + Default,)* + #(::rkyv::Archived<#generics>: ::rkyv::Deserialize<#generics, D>,)* + { + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result<#name<#(#generics),*>, D::Error> { + let version = (deserializer as &mut dyn ::core::any::Any) + .downcast_mut::<::dbsp::storage::file::Deserializer>() + .map(|deserializer| deserializer.version()) + .unwrap_or(::dbsp::storage::file::format::VERSION_NUMBER); + if version < ::dbsp::storage::file::format::VERSION_NUMBER { + // SAFETY: V3 files store tuples with the old archived layout. + let legacy = unsafe { + &*(self as *const _ as *const #archived_v3_name<#(#generics),*>) + }; + return legacy.deserialize(deserializer); + } + let mut ptr_idx = 0usize; + #(#deserialize_fields)* + Ok(#name( #(#fields),* )) + } + } + }; + let checkpoint_impl = quote! { impl<#(#generics),*> ::dbsp::circuit::checkpointer::Checkpoint for #name<#(#generics),*> where @@ -228,6 +561,9 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { #struct_def #constructor #getter_setter + #v3_archived_struct + #v3_deserialize_impl + #rkyv_impls #algebra_traits #conversion_traits #num_entries_impl diff --git a/crates/feldera-macros/tests/compile.rs b/crates/feldera-macros/tests/compile.rs new file mode 100644 index 0000000000..f1af3c05d0 --- /dev/null +++ b/crates/feldera-macros/tests/compile.rs @@ -0,0 +1,897 @@ +#![allow(unused)] + +use dbsp::utils::IsNone; +use feldera_macros::IsNone; +use rkyv::{out_field, Archived}; +use std::sync::OnceLock; + +#[derive( + Default, + Eq, + Ord, + Clone, + Hash, + PartialEq, + PartialOrd, + derive_more::Neg, + serde::Serialize, + serde::Deserialize, + size_of::SizeOf, + IsNone, +)] +pub struct Tup1(pub T0); +impl Tup1 { + #[allow(clippy::too_many_arguments)] + pub fn new(t0: T0) -> Self { + Self(t0) + } +} +impl Tup1 { + #[inline] + pub fn get_0(&self) -> &T0 { + &self.0 + } + #[inline] + pub fn get_0_mut(&mut self) -> &mut T0 { + &mut self.0 + } +} +impl dbsp::algebra::MulByRef for Tup1 +where + T0: dbsp::algebra::MulByRef, + W: dbsp::algebra::ZRingValue, +{ + type Output = Self; + fn mul_by_ref(&self, other: &W) -> Self::Output { + let Tup1(t0) = self; + Tup1(t0.mul_by_ref(other)) + } +} +impl dbsp::algebra::HasZero for Tup1 +where + T0: dbsp::algebra::HasZero, +{ + fn zero() -> Self { + Tup1(T0::zero()) + } + fn is_zero(&self) -> bool { + let mut result = true; + let Tup1(t0) = self; + result = result && t0.is_zero(); + result + } +} +impl dbsp::algebra::AddByRef for Tup1 +where + T0: dbsp::algebra::AddByRef, +{ + fn add_by_ref(&self, other: &Self) -> Self { + let Tup1(t0) = self; + let Tup1(other_t0) = other; + Tup1(t0.add_by_ref(other_t0)) + } +} +impl dbsp::algebra::AddAssignByRef for Tup1 +where + T0: dbsp::algebra::AddAssignByRef, +{ + fn add_assign_by_ref(&mut self, other: &Self) { + let Tup1(ref mut t0) = self; + let Tup1(ref other_t0) = other; + t0.add_assign_by_ref(other_t0); + } +} +impl dbsp::algebra::NegByRef for Tup1 +where + T0: dbsp::algebra::NegByRef, +{ + fn neg_by_ref(&self) -> Self { + let Tup1(t0) = self; + Tup1(t0.neg_by_ref()) + } +} +impl From<(T0)> for Tup1 { + fn from((t0): (T0)) -> Self { + Self(t0) + } +} +impl<'a, T0> Into<(&'a T0,)> for &'a Tup1 { + #[allow(clippy::from_over_into)] + fn into(self) -> (&'a T0,) { + let Tup1(t0) = &self; + (t0,) + } +} +impl Into<(T0,)> for Tup1 { + #[allow(clippy::from_over_into)] + fn into(self) -> (T0,) { + let Tup1(t0) = self; + (t0,) + } +} +impl dbsp::NumEntries for Tup1 +where + T0: dbsp::NumEntries, +{ + const CONST_NUM_ENTRIES: Option = None; + fn num_entries_shallow(&self) -> usize { + 1usize + } + fn num_entries_deep(&self) -> usize { + let Tup1(t0) = self; + 0 + (t0).num_entries_deep() + } +} +impl core::fmt::Debug for Tup1 { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { + let Tup1(t0) = self; + f.debug_tuple(stringify!(Tup1)).field(&t0).finish() + } +} +impl Copy for Tup1 {} + +#[repr(C)] +pub struct ArchivedTup1V3 +where + T0: rkyv::Archive, +{ + pub t0: Archived, +} + +impl rkyv::Deserialize, D> for ArchivedTup1V3 +where + D: rkyv::Fallible + ?Sized, + T0: rkyv::Archive, + Archived: rkyv::Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Tup1(self.t0.deserialize(deserializer)?)) + } +} + +#[derive( + Default, + Eq, + Ord, + Clone, + Hash, + PartialEq, + PartialOrd, + derive_more::Neg, + serde::Serialize, + serde::Deserialize, + size_of::SizeOf, + IsNone, +)] +pub struct Tup2(pub T0, pub T1); +impl Tup2 { + #[allow(clippy::too_many_arguments)] + pub fn new(t0: T0, t1: T1) -> Self { + Self(t0, t1) + } +} +impl core::fmt::Debug for Tup2 { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { + let Tup2(t0, t1) = self; + f.debug_tuple("").field(&t0).field(&t1).finish() + } +} +impl Copy for Tup2 {} + +// ------------------------------------------------------------------------------------------------ +// Compact `rkyv` format for `Tup1` +// +// Motivation: `Archived>` is always `size_of::>()` even when the option is +// `None`. For very wide tuples (`Tup370`, ...), a large fraction of `None`s can otherwise dominate +// checkpoint size. This format stores a bitmap and only serializes values whose bit is *not* set +// according to `IsNone`. +// ------------------------------------------------------------------------------------------------ + +#[repr(C)] +pub struct ArchivedTup1 +where + T0: rkyv::Archive, +{ + bitmap: u8, + ptrs: rkyv::vec::ArchivedVec, + _phantom: core::marker::PhantomData T0>, +} + +#[inline] +unsafe fn archived_none_ptr() -> *const Archived { + static NONE: OnceLock = OnceLock::new(); + let ptr = *NONE.get_or_init(|| { + // This keeps a per-type, properly aligned `Archived` that we can + // reuse when the bitmap indicates a `None` value. + // SAFETY: This is only valid when `Archived` is `ArchivedOption<...>`. + let boxed: Box> = Box::new(unsafe { core::mem::zeroed() }); + Box::into_raw(boxed) as usize + }); + ptr as *const Archived +} + +impl ArchivedTup1 +where + T0: rkyv::Archive, +{ + #[inline] + fn none_bit_set(&self, idx: usize) -> bool { + debug_assert!(idx < 8); + (self.bitmap & (1u8 << idx)) != 0 + } + + #[inline] + fn idx_for_field(&self, field_idx: usize) -> usize { + debug_assert!(field_idx == 0); + 0 + } + + #[inline] + fn get_t0(&self) -> &Archived { + if self.none_bit_set(0) { + // SAFETY: The bitmap only marks `None` for types whose archived + // representation is `ArchivedOption<...>`; a zeroed archived + // option is valid for the `None` variant. + unsafe { &*archived_none_ptr::() } + } else { + debug_assert!(!self.ptrs.is_empty()); + // SAFETY: `ptrs[0]` points at the archived `T0` when the bit is clear. + unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(0) + .as_ptr() + .cast::>() + } + } + } +} + +impl core::cmp::PartialEq for ArchivedTup1 +where + T0: rkyv::Archive, + Archived: core::cmp::PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.get_t0() == other.get_t0() + } +} + +impl core::cmp::Eq for ArchivedTup1 +where + T0: rkyv::Archive, + Archived: core::cmp::Eq, +{ +} + +impl core::cmp::PartialOrd for ArchivedTup1 +where + T0: rkyv::Archive, + Archived: core::cmp::Ord, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl core::cmp::Ord for ArchivedTup1 +where + T0: rkyv::Archive, + Archived: core::cmp::Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.get_t0().cmp(other.get_t0()) + } +} + +pub struct Tup1Resolver { + bitmap: u8, + ptrs_resolver: rkyv::vec::VecResolver, + ptrs_len: usize, +} + +struct FieldPtr { + pos: usize, +} + +impl rkyv::Archive for FieldPtr { + type Archived = rkyv::RawRelPtr; + type Resolver = usize; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + rkyv::RawRelPtr::emplace(pos, resolver, out); + } +} + +impl rkyv::Serialize for FieldPtr +where + S: rkyv::ser::Serializer + ?Sized, +{ + #[inline] + fn serialize(&self, _serializer: &mut S) -> Result { + Ok(self.pos) + } +} + +impl rkyv::Archive for Tup1 +where + T0: rkyv::Archive, +{ + type Archived = ArchivedTup1; + type Resolver = Tup1Resolver; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + let (fp, fo) = out_field!(out.bitmap); + u8::resolve(&resolver.bitmap, pos + fp, (), fo); + + let (fp, fo) = out_field!(out.ptrs); + let vec_pos = pos + fp; + rkyv::vec::ArchivedVec::::resolve_from_len( + resolver.ptrs_len, + vec_pos, + resolver.ptrs_resolver, + fo, + ); + } +} + +impl rkyv::Serialize for Tup1 +where + S: rkyv::ser::Serializer + rkyv::ser::ScratchSpace + ?Sized, + T0: rkyv::Archive + rkyv::Serialize + IsNone, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + if self.0.is_none() { + Ok(Tup1Resolver { + bitmap: 1, + ptrs_resolver: rkyv::vec::ArchivedVec::::serialize_from_slice( + &[] as &[FieldPtr], + serializer, + )?, + ptrs_len: 0, + }) + } else { + let t0_pos = serializer.serialize_value(&self.0)?; + let ptrs = [FieldPtr { pos: t0_pos }]; + let ptrs_resolver = + rkyv::vec::ArchivedVec::::serialize_from_slice(&ptrs, serializer)?; + Ok(Tup1Resolver { + bitmap: 0, + ptrs_resolver, + ptrs_len: 1, + }) + } + } +} + +impl rkyv::Deserialize, D> for ArchivedTup1 +where + D: rkyv::Fallible + core::any::Any, + T0: rkyv::Archive + Default, + Archived: rkyv::Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let version = (deserializer as &mut dyn core::any::Any) + .downcast_mut::() + .map(|deserializer| deserializer.version()) + .unwrap_or(dbsp::storage::file::format::VERSION_NUMBER); + if version < dbsp::storage::file::format::VERSION_NUMBER { + // SAFETY: V3 files store tuples with the old archived layout. + let v3 = unsafe { &*(self as *const _ as *const ArchivedTup1V3) }; + return v3.deserialize(deserializer); + } + if self.none_bit_set(0) { + Ok(Tup1(T0::default())) + } else { + let archived = unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(0) + .as_ptr() + .cast::>() + }; + Ok(Tup1(archived.deserialize(deserializer)?)) + } + } +} + +#[repr(C)] +pub struct ArchivedTup2V3 +where + T0: rkyv::Archive, + T1: rkyv::Archive, +{ + pub t0: Archived, + pub t1: Archived, +} + +impl rkyv::Deserialize, D> for ArchivedTup2V3 +where + D: rkyv::Fallible + ?Sized, + T0: rkyv::Archive, + T1: rkyv::Archive, + Archived: rkyv::Deserialize, + Archived: rkyv::Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Tup2( + self.t0.deserialize(deserializer)?, + self.t1.deserialize(deserializer)?, + )) + } +} + +// ------------------------------------------------------------------------------------------------ +// Compact `rkyv` format for `Tup2` +// +// Uses `ArchivedVec` so the pointer list can be empty when all fields are `None` +// according to `IsNone`. +// ------------------------------------------------------------------------------------------------ + +#[repr(C)] +pub struct ArchivedTup2 +where + T0: rkyv::Archive, + T1: rkyv::Archive, +{ + bitmap: u8, + ptrs: rkyv::vec::ArchivedVec, + _phantom: core::marker::PhantomData (T0, T1)>, +} + +impl ArchivedTup2 +where + T0: rkyv::Archive, + T1: rkyv::Archive, +{ + #[inline] + fn idx_for_field(&self, field_idx: usize) -> usize { + debug_assert!(field_idx <= 1); + match field_idx { + 0 => 0, + _ => { + if self.none_bit_set(0) { + 0 + } else { + 1 + } + } + } + } + + #[inline] + fn none_bit_set(&self, idx: usize) -> bool { + debug_assert!(idx < 8); + (self.bitmap & (1u8 << idx)) != 0 + } + + #[inline] + fn get_t0(&self) -> &Archived { + if self.none_bit_set(0) { + // SAFETY: See `ArchivedTup1::get_t0` for the `ArchivedOption` reasoning. + unsafe { &*archived_none_ptr::() } + } else { + debug_assert!(!self.ptrs.is_empty()); + // SAFETY: `ptrs[0]` points at the archived `T0` when the bit is clear. + unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(0) + .as_ptr() + .cast::>() + } + } + } + + #[inline] + fn get_t1(&self) -> &Archived { + if self.none_bit_set(1) { + // SAFETY: See `ArchivedTup1::get_t0` for the `ArchivedOption` reasoning. + unsafe { &*archived_none_ptr::() } + } else { + let idx = self.idx_for_field(1); + debug_assert!(idx < self.ptrs.len()); + // SAFETY: `ptrs[idx]` points at the archived `T1` when its bit is clear. + unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(idx) + .as_ptr() + .cast::>() + } + } + } +} + +impl core::cmp::PartialEq for ArchivedTup2 +where + T0: rkyv::Archive, + T1: rkyv::Archive, + Archived: core::cmp::PartialEq, + Archived: core::cmp::PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + unsafe { self.get_t0() == other.get_t0() && self.get_t1() == other.get_t1() } + } +} + +impl core::cmp::Eq for ArchivedTup2 +where + T0: rkyv::Archive, + T1: rkyv::Archive, + Archived: core::cmp::Eq, + Archived: core::cmp::Eq, +{ +} + +impl core::cmp::PartialOrd for ArchivedTup2 +where + T0: rkyv::Archive, + T1: rkyv::Archive, + Archived: core::cmp::Ord, + Archived: core::cmp::Ord, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl core::cmp::Ord for ArchivedTup2 +where + T0: rkyv::Archive, + T1: rkyv::Archive, + Archived: core::cmp::Ord, + Archived: core::cmp::Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let t0_cmp = unsafe { self.get_t0().cmp(other.get_t0()) }; + if t0_cmp != core::cmp::Ordering::Equal { + return t0_cmp; + } + unsafe { self.get_t1().cmp(other.get_t1()) } + } +} + +pub struct Tup2Resolver { + bitmap: u8, + ptrs_resolver: rkyv::vec::VecResolver, + ptrs_len: usize, +} + +impl rkyv::Archive for Tup2 +where + T0: rkyv::Archive, + T1: rkyv::Archive, +{ + type Archived = ArchivedTup2; + type Resolver = Tup2Resolver; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + let (fp, fo) = out_field!(out.bitmap); + u8::resolve(&resolver.bitmap, pos + fp, (), fo); + + let (fp, fo) = out_field!(out.ptrs); + let vec_pos = pos + fp; + rkyv::vec::ArchivedVec::::resolve_from_len( + resolver.ptrs_len, + vec_pos, + resolver.ptrs_resolver, + fo, + ); + + let (_fp, fo) = out_field!(out._phantom); + fo.write(core::marker::PhantomData); + } +} + +impl rkyv::Serialize for Tup2 +where + S: rkyv::ser::Serializer + rkyv::ser::ScratchSpace + ?Sized, + T0: rkyv::Archive + rkyv::Serialize + IsNone, + T1: rkyv::Archive + rkyv::Serialize + IsNone, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + let mut bitmap = 0u8; + let mut ptrs = [FieldPtr { pos: 0 }, FieldPtr { pos: 0 }]; + let mut ptrs_len = 0usize; + + if self.0.is_none() { + bitmap |= 1; + } else { + let pos = serializer.serialize_value(&self.0)?; + ptrs[ptrs_len] = FieldPtr { pos }; + ptrs_len += 1; + } + + if self.1.is_none() { + bitmap |= 2; + } else { + let pos = serializer.serialize_value(&self.1)?; + ptrs[ptrs_len] = FieldPtr { pos }; + ptrs_len += 1; + } + + let ptrs_resolver = rkyv::vec::ArchivedVec::::serialize_from_slice( + &ptrs[..ptrs_len], + serializer, + )?; + + Ok(Tup2Resolver { + bitmap, + ptrs_resolver, + ptrs_len, + }) + } +} + +impl rkyv::Deserialize, D> for ArchivedTup2 +where + D: rkyv::Fallible + core::any::Any, + T0: rkyv::Archive + Default, + T1: rkyv::Archive + Default, + Archived: rkyv::Deserialize, + Archived: rkyv::Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let version = (deserializer as &mut dyn core::any::Any) + .downcast_mut::() + .map(|deserializer| deserializer.version()) + .unwrap_or(dbsp::storage::file::format::VERSION_NUMBER); + if version < dbsp::storage::file::format::VERSION_NUMBER { + // SAFETY: V3 files store tuples with the old archived layout. + let v3 = unsafe { &*(self as *const _ as *const ArchivedTup2V3) }; + return v3.deserialize(deserializer); + } + let mut idx = 0usize; + + let t0 = if self.none_bit_set(0) { + T0::default() + } else { + let archived = unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(idx) + .as_ptr() + .cast::>() + }; + idx += 1; + archived.deserialize(deserializer)? + }; + + let t1 = if self.none_bit_set(1) { + T1::default() + } else { + let archived = unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(idx) + .as_ptr() + .cast::>() + }; + idx += 1; + archived.deserialize(deserializer)? + }; + + debug_assert_eq!(idx, self.ptrs.len()); + Ok(Tup2(t0, t1)) + } +} + +impl dbsp::circuit::checkpointer::Checkpoint for Tup1 +where + Tup1: + ::rkyv::Serialize + dbsp::storage::file::Deserializable, +{ + fn checkpoint(&self) -> Result, dbsp::Error> { + let mut s = dbsp::storage::file::Serializer::default(); + let _offset = ::rkyv::ser::Serializer::serialize_value(&mut s, self).unwrap(); + let data = s.into_serializer().into_inner().into_vec(); + Ok(data) + } + fn restore(&mut self, data: &[u8]) -> Result<(), dbsp::Error> { + *self = dbsp::trace::unaligned_deserialize(data); + Ok(()) + } +} + +impl dbsp::circuit::checkpointer::Checkpoint for Tup2 +where + Tup2: + ::rkyv::Serialize + dbsp::storage::file::Deserializable, +{ + fn checkpoint(&self) -> Result, dbsp::Error> { + let mut s = dbsp::storage::file::Serializer::default(); + let _offset = ::rkyv::ser::Serializer::serialize_value(&mut s, self).unwrap(); + let data = s.into_serializer().into_inner().into_vec(); + Ok(data) + } + fn restore(&mut self, data: &[u8]) -> Result<(), dbsp::Error> { + *self = dbsp::trace::unaligned_deserialize(data); + Ok(()) + } +} + +#[test] +fn compile_tup1() { + let t1 = Tup1::new(Some(32i32)); +} + +#[test] +fn compile_tup2() { + let t2 = Tup2::new(Some(32i32), Some(64i32)); +} + +#[test] +fn rkyv_compact_tup1_option_roundtrip() { + use feldera_sqllib::SqlString; + + let tup_some = Tup1::new(Some(SqlString::from_ref("hello"))); + let bytes_some = dbsp::storage::file::to_bytes(&tup_some).unwrap(); + let restored_some: Tup1> = + dbsp::trace::unaligned_deserialize(&bytes_some[..]); + assert_eq!(restored_some, tup_some); + + let tup_none: Tup1> = Tup1::new(None); + let bytes_none = dbsp::storage::file::to_bytes(&tup_none).unwrap(); + let restored_none: Tup1> = + dbsp::trace::unaligned_deserialize(&bytes_none[..]); + assert_eq!(restored_none, tup_none); + assert_eq!( + bytes_none.len(), + core::mem::size_of::>>() + ); + + assert!( + bytes_none.len() < bytes_some.len(), + "expected `None` to serialize smaller than `Some`, got None={} Some={}", + bytes_none.len(), + bytes_some.len() + ); +} + +#[test] +fn rkyv_compact_tup1_archived_get_t0() { + use feldera_sqllib::SqlString; + + let tup_none: Tup1> = Tup1::new(None); + let bytes_none = dbsp::storage::file::to_bytes(&tup_none).unwrap(); + let archived_none = unsafe { rkyv::archived_root::>>(&bytes_none[..]) }; + let archived_t0_none = archived_none.get_t0(); + assert!(archived_t0_none.is_none()); + + let tup_some = Tup1::new(Some(SqlString::from_ref("hello"))); + let bytes_some = dbsp::storage::file::to_bytes(&tup_some).unwrap(); + let archived_some = unsafe { rkyv::archived_root::>>(&bytes_some[..]) }; + let archived_t0_some = archived_some.get_t0(); + assert!(archived_t0_some.is_some()); + assert_eq!(archived_t0_some.as_ref().unwrap().as_str(), "hello"); +} + +#[test] +fn rkyv_compact_tup1_option_checkpoint_roundtrip() { + use dbsp::circuit::checkpointer::Checkpoint; + use feldera_sqllib::SqlString; + + let tup_some = Tup1::new(Some(SqlString::from_ref("hello"))); + let bytes_some = tup_some.checkpoint().unwrap(); + let mut restored_some: Tup1> = Tup1::new(None); + restored_some.restore(&bytes_some).unwrap(); + assert_eq!(restored_some, tup_some); + + let tup_none: Tup1> = Tup1::new(None); + let bytes_none = tup_none.checkpoint().unwrap(); + let mut restored_none: Tup1> = Tup1::new(Some(SqlString::from_ref("x"))); + restored_none.restore(&bytes_none).unwrap(); + assert_eq!(restored_none, tup_none); + + assert_eq!( + bytes_none.len(), + core::mem::size_of::>>() + ); +} + +#[test] +fn rkyv_compact_tup2_roundtrip() { + use feldera_sqllib::SqlString; + + let tup_vals: Tup2 = Tup2::new(SqlString::from_ref("hi"), 8i32); + let bytes_vals = dbsp::storage::file::to_bytes(&tup_vals).unwrap(); + let restored_vals: Tup2 = dbsp::trace::unaligned_deserialize(&bytes_vals[..]); + assert_eq!(restored_vals, tup_vals); + assert!( + bytes_vals.len() > core::mem::size_of::>(), + "expected serialized bytes to include out-of-line data, got bytes={} archived={}", + bytes_vals.len(), + core::mem::size_of::>() + ); +} + +#[test] +fn rkyv_compact_tup2_option_roundtrip() { + use feldera_sqllib::SqlString; + + let tup_none: Tup2, Option> = Tup2::new(None, None); + let bytes_none = dbsp::storage::file::to_bytes(&tup_none).unwrap(); + let restored_none: Tup2, Option> = + dbsp::trace::unaligned_deserialize(&bytes_none[..]); + assert_eq!(restored_none, tup_none); + eprintln!("bytes_none.len() = {}", bytes_none.len()); + assert_eq!( + bytes_none.len(), + core::mem::size_of::, Option>>() + ); + + let tup_10: Tup2, Option> = + Tup2::new(Some(SqlString::from_ref("hi")), None); + let bytes_10 = dbsp::storage::file::to_bytes(&tup_10).unwrap(); + let restored_10: Tup2, Option> = + dbsp::trace::unaligned_deserialize(&bytes_10[..]); + assert_eq!(restored_10, tup_10); + + let tup_01: Tup2, Option> = Tup2::new(None, Some(42)); + let bytes_01 = dbsp::storage::file::to_bytes(&tup_01).unwrap(); + let restored_01: Tup2, Option> = + dbsp::trace::unaligned_deserialize(&bytes_01[..]); + assert_eq!(restored_01, tup_01); + + let tup_11: Tup2, Option> = + Tup2::new(Some(SqlString::from_ref("hello")), Some(42)); + let bytes_11 = dbsp::storage::file::to_bytes(&tup_11).unwrap(); + let restored_11: Tup2, Option> = + dbsp::trace::unaligned_deserialize(&bytes_11[..]); + assert_eq!(restored_11, tup_11); + + assert!( + bytes_none.len() < bytes_11.len(), + "expected `(None, None)` to serialize smaller than `(Some, Some)`, got None={} Some={}", + bytes_none.len(), + bytes_11.len() + ); +} + +#[test] +fn rkyv_compact_tup2_archived_get_t0_t1() { + use feldera_sqllib::SqlString; + + let tup_10: Tup2, Option> = + Tup2::new(Some(SqlString::from_ref("hi")), None); + let bytes_10 = dbsp::storage::file::to_bytes(&tup_10).unwrap(); + let archived_10 = + unsafe { rkyv::archived_root::, Option>>(&bytes_10[..]) }; + let t0_10 = archived_10.get_t0(); + let t1_10 = archived_10.get_t1(); + assert!(t0_10.is_some()); + assert!(t1_10.is_none()); + assert_eq!(t0_10.as_ref().unwrap().as_str(), "hi"); + + let tup_01: Tup2, Option> = Tup2::new(None, Some(42)); + let bytes_01 = dbsp::storage::file::to_bytes(&tup_01).unwrap(); + let archived_01 = + unsafe { rkyv::archived_root::, Option>>(&bytes_01[..]) }; + let t0_01 = archived_01.get_t0(); + let t1_01 = archived_01.get_t1(); + assert!(t0_01.is_none()); + assert!(t1_01.is_some()); + assert_eq!(*t1_01.as_ref().unwrap(), 42); +} diff --git a/crates/feldera-macros/tests/declare_tuple_rkyv.rs b/crates/feldera-macros/tests/declare_tuple_rkyv.rs new file mode 100644 index 0000000000..fd2452fe26 --- /dev/null +++ b/crates/feldera-macros/tests/declare_tuple_rkyv.rs @@ -0,0 +1,107 @@ +use feldera_sqllib::SqlString; + +feldera_macros::declare_tuple! { Tup1 } +feldera_macros::declare_tuple! { Tup2 } +feldera_macros::declare_tuple! { Tup12 } + +type OptStr = Option; +type Tup12Opt = Tup12< + OptStr, + OptStr, + OptStr, + OptStr, + OptStr, + OptStr, + OptStr, + OptStr, + OptStr, + OptStr, + OptStr, + OptStr, +>; + +#[test] +fn rkyv_roundtrip_with_option_sqlstring() { + let tup1_some = Tup1::new(Some(SqlString::from_ref("hello"))); + assert_eq!(tup1_some.get_0().as_ref().cloned().unwrap().str(), "hello"); + + let bytes1_some = dbsp::storage::file::to_bytes(&tup1_some).unwrap(); + let restored1_some: Tup1> = + dbsp::trace::unaligned_deserialize(&bytes1_some[..]); + assert_eq!(restored1_some, tup1_some); + + let tup1_none: Tup1> = Tup1::new(None); + let bytes1_none = dbsp::storage::file::to_bytes(&tup1_none).unwrap(); + let restored1_none: Tup1> = + dbsp::trace::unaligned_deserialize(&bytes1_none[..]); + assert_eq!(restored1_none, tup1_none); + assert_eq!( + bytes1_none.len(), + core::mem::size_of::>>() + ); + assert!(bytes1_none.len() < bytes1_some.len()); + + let tup2_some = Tup2::new( + Some(SqlString::from_ref("hello")), + Some(SqlString::from_ref("world")), + ); + assert_eq!(tup2_some.get_0().as_ref().cloned().unwrap().str(), "hello"); + assert_eq!(tup2_some.get_1().as_ref().cloned().unwrap().str(), "world"); + + let bytes2_some = dbsp::storage::file::to_bytes(&tup2_some).unwrap(); + let restored2_some: Tup2, Option> = + dbsp::trace::unaligned_deserialize(&bytes2_some[..]); + assert_eq!(restored2_some, tup2_some); + + let tup2_none: Tup2, Option> = Tup2::new(None, None); + let bytes2_none = dbsp::storage::file::to_bytes(&tup2_none).unwrap(); + let restored2_none: Tup2, Option> = + dbsp::trace::unaligned_deserialize(&bytes2_none[..]); + assert_eq!(restored2_none, tup2_none); + assert_eq!( + bytes2_none.len(), + core::mem::size_of::, Option>>() + ); + assert!(bytes2_none.len() < bytes2_some.len()); +} + +#[test] +fn rkyv_archived_getters() { + let tup1_none: Tup1> = Tup1::new(None); + let bytes1_none = dbsp::storage::file::to_bytes(&tup1_none).unwrap(); + let archived1_none = + unsafe { rkyv::archived_root::>>(&bytes1_none[..]) }; + let t0_none = archived1_none.get_t0(); + assert!(t0_none.is_none()); + + let tup2_10: Tup2, Option> = + Tup2::new(Some(SqlString::from_ref("hi")), None); + let bytes2_10 = dbsp::storage::file::to_bytes(&tup2_10).unwrap(); + let archived2_10 = + unsafe { rkyv::archived_root::, Option>>(&bytes2_10[..]) }; + let t0_10 = archived2_10.get_t0(); + let t1_10 = archived2_10.get_t1(); + assert!(t0_10.is_some()); + assert!(t1_10.is_none()); + assert_eq!(t0_10.as_ref().unwrap().as_str(), "hi"); +} + +#[test] +fn rkyv_tup12_all_none_size() { + let tup: Tup12Opt = Tup12Opt { + 11: Some(SqlString::from("12345678")), + ..Default::default() + }; + let bytes = dbsp::storage::file::to_bytes(&tup).unwrap(); + assert_eq!( + bytes.len(), + 56, + "expected compact encoding, got {} bytes", + bytes.len() + ); + let tup_archived = unsafe { rkyv::archived_root::(&bytes[..]) }; + assert_eq!( + tup_archived.get_t11().as_ref().unwrap().as_str(), + "12345678" + ); +} From a01405900fc50150a141f1d1175a197f257fe718 Mon Sep 17 00:00:00 2001 From: Gerd Zellweger Date: Sat, 10 Jan 2026 13:06:24 -0800 Subject: [PATCH 2/6] [dbsp] remove unused benchmarking code. Signed-off-by: Gerd Zellweger --- crates/dbsp/src/storage/bin/bench.py | 133 ---------- crates/dbsp/src/storage/bin/bench.rs | 368 --------------------------- 2 files changed, 501 deletions(-) delete mode 100644 crates/dbsp/src/storage/bin/bench.py delete mode 100644 crates/dbsp/src/storage/bin/bench.rs diff --git a/crates/dbsp/src/storage/bin/bench.py b/crates/dbsp/src/storage/bin/bench.py deleted file mode 100644 index 07ba1f4559..0000000000 --- a/crates/dbsp/src/storage/bin/bench.py +++ /dev/null @@ -1,133 +0,0 @@ -import subprocess -import plotnine as p9 -import pandas as pd -import humanize as hm - -from io import StringIO - -BACKEND = "Posix" -PATH = "/tmp/feldera-storage-bench" -MEASURE = True - -ONE_MIB = 1024 * 1024 -ONE_GIB = 1024 * 1024 * 1024 - -if True: - # Big config - TOTAL_SIZE = str(256 * ONE_GIB) - THREAD_SHIFT_RANGE = range(0, 6) - BUFFER_SHIFT_RANGE = range(12, 22) -else: - # Small config - TOTAL_SIZE = str(32 * ONE_MIB) - THREAD_SHIFT_RANGE = range(0, 2) - BUFFER_SHIFT_RANGE = range(12, 14) - - -def plot(results): - results["per_thread_file_size"] = results["per_thread_file_size"].map( - lambda x: int(x) - ) - results["threads"] = results["threads"].map(lambda x: int(x)) - results["read_time"] = results["read_time"].map(lambda x: float(x)) - results["write_time"] = results["write_time"].map(lambda x: float(x)) - - results["buffer_size_str"] = results["buffer_size"].map( - lambda x: hm.naturalsize(x, binary=True) - ) - results["buffer_size_str"] = pd.Categorical( - results["buffer_size_str"], - categories=[hm.naturalsize(1 << x, binary=True) for x in BUFFER_SHIFT_RANGE], - ) - - results["Read"] = ( - (results["per_thread_file_size"] * results["threads"]) / ONE_MIB - ) / results["read_time"] - results["Write"] = ( - (results["per_thread_file_size"] * results["threads"]) / ONE_MIB - ) / results["write_time"] - - # Melt the DataFrame to long format - df_long = pd.melt( - results, - id_vars=["buffer_size", "threads", "buffer_size_str"], - value_vars=["Read", "Write"], - var_name="operation", - value_name="tput", - ) - - print(df_long) - - plot = ( - p9.ggplot( - data=df_long, - mapping=p9.aes( - x="threads", - y="tput", - group="buffer_size_str", - color="buffer_size_str", - ), - ) - + p9.labs(y="Throughput [MiB/s]") - + p9.scale_x_continuous( - breaks=[1 << x for x in THREAD_SHIFT_RANGE], name="# Threads" - ) - + p9.theme_538() - + p9.theme( - legend_position="top", - legend_title=p9.element_blank(), - subplots_adjust={"wspace": 0.25}, - ) - + p9.scale_color_brewer(type="qual", palette="Set2") - + p9.geom_point() - + p9.geom_line() - + p9.facet_wrap("~operation", scales="free_y") - ) - plot.save("disk_throughput_plot.png", width=12, height=5, dpi=300, verbose=False) - - -if __name__ == "__main__": - if MEASURE: - results = pd.DataFrame() - for thread_shift in THREAD_SHIFT_RANGE: - for buf_shift in BUFFER_SHIFT_RANGE: - thread_cnt = 1 << thread_shift - buf_size = 1 << buf_shift - per_thread_size = int(int(TOTAL_SIZE) / thread_cnt) - - print( - f"thread_cnt={thread_cnt} buf_size={buf_size} per_thread_size={per_thread_size} backend={BACKEND} path={PATH}" - ) - cmd = [ - "cargo", - "run", - "--release", - "--bin", - "bench", - "--", - "--backend", - BACKEND, - "--per-thread-file-size", - str(per_thread_size), - "--threads", - str(thread_cnt), - "--buffer-size", - str(buf_size), - "--path", - PATH, - "--csv", - ] - result = subprocess.run(cmd, capture_output=True, text=True) - - if result.returncode != 0: - print("Error in subprocess:", result.stderr) - else: - # Parse CSV data into pandas DataFrame - csv_data = pd.read_csv(StringIO(result.stdout)) - results = pd.concat([results, csv_data], ignore_index=True) - - results.to_csv("results.csv", index=False) - else: - results = pd.read_csv("results.csv") - - plot(results) diff --git a/crates/dbsp/src/storage/bin/bench.rs b/crates/dbsp/src/storage/bin/bench.rs deleted file mode 100644 index 947ae70948..0000000000 --- a/crates/dbsp/src/storage/bin/bench.rs +++ /dev/null @@ -1,368 +0,0 @@ -//! A simple CLI app to benchmark different storage backends/scenarios. -//! -//! An example invocation: -//! -//! ```shell -//! cargo run --release --bin bench -- --cache --threads 2 --total-size 4294967296 --path /path/to/disk -//! ``` -//! -//! Run `metrics-observer` in another terminal to see the metrics. -//! -//! There are still some issues with this benchmark to make it useful: -//! - Threads indicate they're done writing but are still writing. - -use libc::timespec; -use std::fs::create_dir_all; -use std::sync::{Arc, Barrier}; -use std::thread; -use std::time::{Duration, Instant}; - -use clap::Parser; - -use feldera_storage::backend::posixio_impl::PosixBackend; -use feldera_storage::backend::{AtomicIncrementOnlyI64, Storage}; -use feldera_storage::buffer_cache::FBuf; - -#[derive(Debug, Clone, Default)] -struct ThreadBenchResult { - read_time: Duration, - write_time: Duration, - cpu_time: Duration, -} - -#[derive(Debug, Clone, Default)] -struct BenchResult { - times: Vec, -} - -fn mean(data: &[f64]) -> Option { - let sum = data.iter().sum::(); - let count = data.len(); - - match count { - positive if positive > 0 => Some(sum / count as f64), - _ => None, - } -} - -fn std_deviation(data: &[f64]) -> Option { - match (mean(data), data.len()) { - (Some(data_mean), count) if count > 0 => { - let variance = data - .iter() - .map(|value| { - let diff = data_mean - *value; - - diff * diff - }) - .sum::() - / count as f64; - - Some(variance.sqrt()) - } - _ => None, - } -} - -impl BenchResult { - fn validate(&self) -> Result<(), String> { - if self.times.is_empty() { - return Err("No results found.".to_string()); - } - assert!(!self.times.is_empty()); - - if self.read_time_std() >= 2.0 { - return Err("Read times are not stable.".to_string()); - } - if self.write_time_std() >= 5.0 { - return Err("Write times are not stable.".to_string()); - } - Ok(()) - } - - fn read_time_std(&self) -> f64 { - std_deviation( - &self - .times - .iter() - .map(|t| t.read_time.as_secs_f64()) - .collect::>(), - ) - .unwrap() - } - - fn write_time_std(&self) -> f64 { - std_deviation( - &self - .times - .iter() - .map(|t| t.write_time.as_secs_f64()) - .collect::>(), - ) - .unwrap() - } - - fn read_time_mean(&self) -> f64 { - mean( - &self - .times - .iter() - .map(|t| t.read_time.as_secs_f64()) - .collect::>(), - ) - .unwrap() - } - - fn write_time_mean(&self) -> f64 { - mean( - &self - .times - .iter() - .map(|t| t.write_time.as_secs_f64()) - .collect::>(), - ) - .unwrap() - } - - fn cpu_time_mean(&self) -> f64 { - mean( - &self - .times - .iter() - .map(|t| t.cpu_time.as_secs_f64()) - .collect::>(), - ) - .unwrap() - } - - fn display(&self, args: Args) { - let read_time = self.read_time_mean(); - let write_time = self.write_time_mean(); - let cpu_time = self.cpu_time_mean(); - const ONE_MIB: f64 = 1024f64 * 1024f64; - - if !args.csv { - if !args.write_only { - println!( - "read: {} MiB/s (mean: {}s, std: {}s)", - ((args.per_thread_file_size * args.threads) as f64 / ONE_MIB) / read_time, - read_time, - self.read_time_std() - ); - } - println!( - "write: {} MiB/s (mean: {}s, std: {}s)", - ((args.per_thread_file_size * args.threads) as f64 / ONE_MIB) / write_time, - write_time, - self.write_time_std() - ); - println!("cpu: {}s (mean))", cpu_time,); - } else { - println!( - "backend,cache,per_thread_file_size,threads,buffer_size,read_time,read_time_std,write_time,write_time_std", - ); - println!( - "{:?},{:?},{},{},{},{},{},{},{}", - args.backend, - args.cache, - args.per_thread_file_size, - args.threads, - args.buffer_size, - read_time, - self.read_time_std(), - write_time, - self.write_time_std(), - ) - } - } -} - -#[derive(Debug, Clone)] -enum Backend { - Posix, -} - -impl From for Backend { - fn from(s: String) -> Self { - match s.as_str() { - "Posix" => Backend::Posix, - _ => panic!("invalid backend"), - } - } -} - -/// Simple program to benchmark files. -/// -/// Spawns multiple threads, each thread writes one file sequentially -/// and then reads it back. -/// -/// The program prints read and write throughput, and the CPU time used by the -/// benchmark threads, which includes system and user time for those threads -/// (but not for other user or kernel threads spawned by them for I/O, if any). -#[derive(Parser, Debug, Clone)] -#[command(author, version)] -struct Args { - /// Path to a file or directory - #[clap(short, long, default_value = "/tmp/feldera-storage")] - path: std::path::PathBuf, - - /// Which backend to use. - #[clap(long, default_value = "Posix")] - backend: Backend, - - /// Number of threads to use - #[clap(long, default_value = "1")] - threads: usize, - - /// Buffer size - #[clap(long, default_value = "4096")] - buffer_size: usize, - - /// Size that is to be written (per-thread) - #[clap(long, default_value = "1073741824")] - per_thread_file_size: usize, - - /// Verify file-operations are performed correctly. - #[clap(long, default_value = "false")] - verify: bool, - - /// Adds a buffer cache with given bytes of capacity. - #[clap(long)] - cache: Option, - - /// Write without reading back? - #[clap(long, default_value = "false")] - write_only: bool, - - /// Print data as CSV. - #[clap(long, default_value = "false")] - csv: bool, -} - -fn allocate_buffer(sz: usize) -> FBuf { - FBuf::with_capacity(sz) -} - -/// Returns the amount of CPU time (user + system) used by the current thread. -/// -/// It was difficult to determine that the result includes both user and system -/// time, so for future reference, see [the original commit] that added support, -/// which includes: -/// -/// ```patch -/// +static inline unsigned long thread_ticks(task_t *p) { -/// + return p->utime + current->stime; -/// +} -/// ``` -/// -/// [the original commit]: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git/commit/?id=bb82e8a53042a91688fd819d0c475a1c9a2b982a -fn thread_cpu_time() -> Duration { - let mut tp = timespec { - tv_sec: 0, - tv_nsec: 0, - }; - unsafe { libc::clock_gettime(libc::CLOCK_THREAD_CPUTIME_ID, &mut tp as *mut timespec) }; - Duration::new(tp.tv_sec as u64, tp.tv_nsec as u32) -} - -fn benchmark(backend: &T, barrier: Arc) -> ThreadBenchResult { - let args = Args::parse(); - let file = backend.create().unwrap(); - - barrier.wait(); - let start_write = Instant::now(); - for i in 0..args.per_thread_file_size / args.buffer_size { - let mut wb = allocate_buffer(args.buffer_size); - wb.resize(args.buffer_size, 0xff); - - debug_assert!(i * args.buffer_size < args.per_thread_file_size); - debug_assert!(wb.len() == args.buffer_size); - backend - .write_block(&file, (i * args.buffer_size) as u64, wb) - .expect("write failed"); - } - let (ih, _path) = backend.complete(file).expect("complete failed"); - ih.commit().unwrap(); - let write_time = start_write.elapsed(); - - barrier.wait(); - let start_read = Instant::now(); - if !args.write_only { - for i in 0..args.per_thread_file_size / args.buffer_size { - let rr = backend - .read_block(&ih, (i * args.buffer_size) as u64, args.buffer_size) - .expect("read failed"); - if args.verify { - assert_eq!(rr.len(), args.buffer_size); - assert_eq!( - rr.iter().as_slice(), - vec![0xffu8; args.buffer_size].as_slice() - ); - } - } - } - let read_time = start_read.elapsed(); - - backend.delete(ih).expect("delete failed"); - ThreadBenchResult { - write_time, - read_time, - cpu_time: thread_cpu_time(), - } -} - -fn posixio_main(args: Args) -> BenchResult { - let counter: Arc = Default::default(); - let barrier = Arc::new(Barrier::new(args.threads)); - // spawn n-1 threads - let threads: Vec<_> = (1..args.threads) - .map(|_| { - let args = args.clone(); - let barrier = barrier.clone(); - let counter = counter.clone(); - thread::spawn(move || { - let barrier = barrier.clone(); - let posixio_backend = PosixBackend::new(args.path.clone(), counter); - benchmark(&posixio_backend, barrier) - }) - }) - .collect(); - - // Run on main thread - let posixio_backend = PosixBackend::new(args.path.clone(), counter); - - let mut br = BenchResult::default(); - let main_res = benchmark(&posixio_backend, barrier); - br.times.push(main_res); - - // Wait for other n-1 threads - threads.into_iter().for_each(|t| { - let tres = t.join().expect("thread panicked"); - br.times.push(tres); - }); - - br -} - -fn main() { - let args = Args::parse(); - assert!(args.per_thread_file_size > 0); - assert!(args.buffer_size > 0); - assert!(args.per_thread_file_size >= args.buffer_size); - assert!(args.threads > 0); - if !args.path.exists() { - create_dir_all(&args.path).expect("failed to create directory"); - } - - let br = match args.backend { - Backend::Posix => posixio_main(args.clone()), - }; - - br.display(args.clone()); - if !args.csv { - if let Err(e) = br.validate() { - println!("Result validation failed: {}", e); - std::process::exit(1); - } - } -} From 9371b7ab1ce26a6918cc21430fce5b6e8f298115 Mon Sep 17 00:00:00 2001 From: Gerd Zellweger Date: Sat, 10 Jan 2026 13:07:07 -0800 Subject: [PATCH 3/6] [storage] Tests for storage format compatibility. Add code to generate batch files in different formats and makes sure we can read them correctly in the future. Signed-off-by: Gerd Zellweger --- Cargo.toml | 1 + crates/dbsp/src/storage/file.rs | 2 +- crates/dbsp/src/storage/file/format.rs | 6 +- crates/dbsp/src/storage/file/reader.rs | 2 +- crates/dbsp/src/storage/file/test.rs | 3 +- crates/feldera-macros/src/tuples.rs | 32 +- crates/feldera-macros/tests/compile.rs | 942 ++++++++++-------- crates/storage-test-compat/Cargo.toml | 22 + .../golden-batch-v3-snappy.feldera | Bin 0 -> 84992 bytes .../golden-files/golden-batch-v3.feldera | Bin 0 -> 337408 bytes .../golden-batch-v4-snappy.feldera | Bin 0 -> 98304 bytes .../golden-files/golden-batch-v4.feldera | Bin 0 -> 384000 bytes .../src/bin/golden-writer.rs | 97 ++ crates/storage-test-compat/src/lib.rs | 419 ++++++++ 14 files changed, 1093 insertions(+), 433 deletions(-) create mode 100644 crates/storage-test-compat/Cargo.toml create mode 100644 crates/storage-test-compat/golden-files/golden-batch-v3-snappy.feldera create mode 100644 crates/storage-test-compat/golden-files/golden-batch-v3.feldera create mode 100644 crates/storage-test-compat/golden-files/golden-batch-v4-snappy.feldera create mode 100644 crates/storage-test-compat/golden-files/golden-batch-v4.feldera create mode 100644 crates/storage-test-compat/src/bin/golden-writer.rs create mode 100644 crates/storage-test-compat/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index f11c2df949..9766cb7163 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ members = [ "crates/rest-api", "crates/ir", "crates/fxp", + "crates/storage-test-compat", ] exclude = [ "sql-to-dbsp-compiler/temp", diff --git a/crates/dbsp/src/storage/file.rs b/crates/dbsp/src/storage/file.rs index 5d936bf278..0e13f2cc28 100644 --- a/crates/dbsp/src/storage/file.rs +++ b/crates/dbsp/src/storage/file.rs @@ -165,7 +165,7 @@ where /// are unknown. /// /// See documentation of [`AnyFactories`]. - pub(crate) fn any_factories(&self) -> AnyFactories { + pub fn any_factories(&self) -> AnyFactories { AnyFactories { key_factory: Arc::new(self.key_factory), item_factory: Arc::new(self.item_factory), diff --git a/crates/dbsp/src/storage/file/format.rs b/crates/dbsp/src/storage/file/format.rs index 1b35838c8a..556e5a1145 100644 --- a/crates/dbsp/src/storage/file/format.rs +++ b/crates/dbsp/src/storage/file/format.rs @@ -87,7 +87,11 @@ use num_traits::FromPrimitive; use size_of::SizeOf; /// Increment this on each incompatible change. -pub const VERSION_NUMBER: u32 = 3; +/// +/// When a new version is created, make sure to generate new golden +/// files for it in crate `storage-test-compat` to check for +/// backwards compatibility. +pub const VERSION_NUMBER: u32 = 4; /// Magic number for data blocks. pub const DATA_BLOCK_MAGIC: [u8; 4] = *b"LFDB"; diff --git a/crates/dbsp/src/storage/file/reader.rs b/crates/dbsp/src/storage/file/reader.rs index 319a850351..f8e203f7c9 100644 --- a/crates/dbsp/src/storage/file/reader.rs +++ b/crates/dbsp/src/storage/file/reader.rs @@ -1548,7 +1548,7 @@ where warn!("{}: reading old format storage file, performance may be reduced due to incompatible Bloom filters", file.path()); Some(false) } - VERSION_NUMBER => Some(true), + x if x >= 3 => Some(true), _ => None, } .ok_or_else(|| CorruptionError::InvalidVersion { diff --git a/crates/dbsp/src/storage/file/test.rs b/crates/dbsp/src/storage/file/test.rs index 7f53e69159..b966f65c55 100644 --- a/crates/dbsp/src/storage/file/test.rs +++ b/crates/dbsp/src/storage/file/test.rs @@ -1038,9 +1038,8 @@ fn test_tuple() { #[test] fn test_tup65_option_string() { init_test_logger(); - let n = 10_000usize; for_each_compression_type(Parameters::default(), |parameters| { - test_one_column(n, |row| { + test_one_column(1_000usize, |row| { let bits = row as u128 * 2 + 1; let before = tup65_from_bits(bits - 1); let key = tup65_from_bits(bits); diff --git a/crates/feldera-macros/src/tuples.rs b/crates/feldera-macros/src/tuples.rs index 23551c5ada..6657162c59 100644 --- a/crates/feldera-macros/src/tuples.rs +++ b/crates/feldera-macros/src/tuples.rs @@ -202,7 +202,6 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { }; let v3_archived_struct = quote! { - #[repr(C)] pub struct #archived_v3_name<#(#generics),*> where #(#generics: ::rkyv::Archive,)* @@ -235,8 +234,8 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { .zip(generics.iter()) .map(|((idx, _field), ty)| { let get_name = format_ident!("get_t{}", idx); - let idx_lit = Index::from(idx); - quote! { + let idx_lit = Index::from(idx); + quote! { #[inline] pub fn #get_name(&self) -> &::rkyv::Archived<#ty> { if self.none_bit_set(#idx_lit) { @@ -328,12 +327,12 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { } impl ::rkyv::Archive for #field_ptr_name { - type Archived = ::rkyv::RawRelPtr; + type Archived = ::rkyv::rel_ptr::RawRelPtrI32; type Resolver = usize; #[inline] unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - ::rkyv::RawRelPtr::emplace(pos, resolver, out); + ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos, resolver, out); } } @@ -360,7 +359,6 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { ptr as *const ::rkyv::Archived } - #[repr(C)] pub struct #archived_name<#(#generics),*> where #(#generics: ::rkyv::Archive,)* @@ -369,7 +367,7 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { // `ptrs` stores only the non-`None` values in field order; `idx_for_field` // computes the offset by counting unset bits before each field. bitmap: [u64; #bitmap_words], - ptrs: ::rkyv::vec::ArchivedVec<::rkyv::RawRelPtr>, + ptrs: ::rkyv::vec::ArchivedVec<::rkyv::rel_ptr::RawRelPtrI32>, _phantom: core::marker::PhantomData (#(#generics),*)>, } @@ -472,7 +470,7 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { let (fp, fo) = ::rkyv::out_field!(out.ptrs); let vec_pos = pos + fp; - ::rkyv::vec::ArchivedVec::<::rkyv::RawRelPtr>::resolve_from_len( + ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::resolve_from_len( resolver.ptrs_len, vec_pos, resolver.ptrs_resolver, @@ -498,7 +496,7 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { #(#serialize_fields)* - let ptrs_resolver = ::rkyv::vec::ArchivedVec::<::rkyv::RawRelPtr>::serialize_from_slice( + let ptrs_resolver = ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::serialize_from_slice( &ptrs[..ptrs_len], serializer, )?; @@ -522,9 +520,10 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { let version = (deserializer as &mut dyn ::core::any::Any) .downcast_mut::<::dbsp::storage::file::Deserializer>() .map(|deserializer| deserializer.version()) - .unwrap_or(::dbsp::storage::file::format::VERSION_NUMBER); - if version < ::dbsp::storage::file::format::VERSION_NUMBER { - // SAFETY: V3 files store tuples with the old archived layout. + .expect("passed wrong deserializer"); + if version <= 3 { + // SAFETY: Before V4 files store tuples in the naive (standard rkyv) form that + // does not have a bitfield to optimize None values. let legacy = unsafe { &*(self as *const _ as *const #archived_v3_name<#(#generics),*>) }; @@ -616,9 +615,14 @@ mod tests { let expanded = declare_tuple_impl(tuple); let parsed_file: syn::File = syn::parse2(expanded).expect("Failed to parse output"); let formatted = prettyplease::unparse(&parsed_file); - println!("{formatted}"); - assert!(formatted.contains("pub struct Tup1")); + + let tuple: TupleDef = syn::parse2(quote!(Tup2)).expect("Failed to parse TupleDef"); + let expanded = declare_tuple_impl(tuple); + let parsed_file: syn::File = syn::parse2(expanded).expect("Failed to parse output"); + let formatted = prettyplease::unparse(&parsed_file); + println!("{formatted}"); + assert!(formatted.contains("pub struct Tup2")); } } diff --git a/crates/feldera-macros/tests/compile.rs b/crates/feldera-macros/tests/compile.rs index f1af3c05d0..28c4399377 100644 --- a/crates/feldera-macros/tests/compile.rs +++ b/crates/feldera-macros/tests/compile.rs @@ -17,7 +17,6 @@ use std::sync::OnceLock; serde::Serialize, serde::Deserialize, size_of::SizeOf, - IsNone, )] pub struct Tup1(pub T0); impl Tup1 { @@ -36,10 +35,245 @@ impl Tup1 { &mut self.0 } } -impl dbsp::algebra::MulByRef for Tup1 +pub struct ArchivedTup1V3 +where + T0: ::rkyv::Archive, +{ + pub t0: ::rkyv::Archived, +} +impl ::rkyv::Deserialize, D> for ArchivedTup1V3 +where + D: ::rkyv::Fallible + ?Sized, + T0: ::rkyv::Archive, + ::rkyv::Archived: ::rkyv::Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Tup1(self.t0.deserialize(deserializer)?)) + } +} +#[derive(Copy, Clone)] +struct Tup1FieldPtr { + pos: usize, +} +impl ::rkyv::Archive for Tup1FieldPtr { + type Archived = ::rkyv::rel_ptr::RawRelPtrI32; + type Resolver = usize; + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos, resolver, out); + } +} +impl ::rkyv::Serialize for Tup1FieldPtr +where + S: ::rkyv::ser::Serializer + ?Sized, +{ + #[inline] + fn serialize(&self, _serializer: &mut S) -> Result { + Ok(self.pos) + } +} +#[inline] +unsafe fn __tup1_archived_none_ptr() -> *const ::rkyv::Archived { + static NONE: ::std::sync::OnceLock = ::std::sync::OnceLock::new(); + let ptr = *NONE.get_or_init(|| { + let boxed: Box<::rkyv::Archived> = Box::new(unsafe { ::core::mem::zeroed() }); + Box::into_raw(boxed) as usize + }); + ptr as *const ::rkyv::Archived +} +pub struct ArchivedTup1 +where + T0: ::rkyv::Archive, +{ + bitmap: [u64; 1usize], + ptrs: ::rkyv::vec::ArchivedVec<::rkyv::rel_ptr::RawRelPtrI32>, + _phantom: core::marker::PhantomData (T0)>, +} +impl ArchivedTup1 +where + T0: ::rkyv::Archive, +{ + #[inline] + fn none_bit_set(&self, idx: usize) -> bool { + debug_assert!(idx < 1usize); + let word = idx / 64; + let bit = idx % 64; + (self.bitmap[word] & (1u64 << bit)) != 0 + } + #[inline] + fn idx_for_field(&self, field_idx: usize) -> usize { + debug_assert!(field_idx < 1usize); + let word = field_idx / 64; + let bit = field_idx % 64; + let mut idx = 0usize; + let mut w = 0usize; + while w < word { + idx += 64usize - (self.bitmap[w].count_ones() as usize); + w += 1; + } + let mask = if bit == 0 { 0 } else { (1u64 << bit) - 1 }; + let none_before = (self.bitmap[word] & mask).count_ones() as usize; + idx + bit - none_before + } + #[inline] + pub fn get_t0(&self) -> &::rkyv::Archived { + if self.none_bit_set(0) { + unsafe { &*__tup1_archived_none_ptr::() } + } else { + let ptr_idx = self.idx_for_field(0); + debug_assert!(ptr_idx < self.ptrs.len()); + unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(ptr_idx) + .as_ptr() + .cast::<::rkyv::Archived>() + } + } + } +} +impl core::cmp::PartialEq for ArchivedTup1 +where + T0: ::rkyv::Archive, + ::rkyv::Archived: core::cmp::PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + true && self.get_t0() == other.get_t0() + } +} +impl core::cmp::Eq for ArchivedTup1 +where + T0: ::rkyv::Archive, + ::rkyv::Archived: core::cmp::Eq, +{ +} +impl core::cmp::PartialOrd for ArchivedTup1 +where + T0: ::rkyv::Archive, + ::rkyv::Archived: core::cmp::Ord, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl core::cmp::Ord for ArchivedTup1 +where + T0: ::rkyv::Archive, + ::rkyv::Archived: core::cmp::Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let cmp = self.get_t0().cmp(other.get_t0()); + if cmp != core::cmp::Ordering::Equal { + return cmp; + } + core::cmp::Ordering::Equal + } +} +pub struct Tup1Resolver { + bitmap: [u64; 1usize], + ptrs_resolver: ::rkyv::vec::VecResolver, + ptrs_len: usize, +} +impl ::rkyv::Archive for Tup1 +where + T0: ::rkyv::Archive, +{ + type Archived = ArchivedTup1; + type Resolver = Tup1Resolver; + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + let (fp, fo) = ::rkyv::out_field!(out.bitmap); + let bitmap_out = fo.cast::(); + u64::resolve( + &resolver.bitmap[0], + pos + fp + (0 * ::core::mem::size_of::()), + (), + bitmap_out.add(0), + ); + let (fp, fo) = ::rkyv::out_field!(out.ptrs); + let vec_pos = pos + fp; + ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::resolve_from_len( + resolver.ptrs_len, + vec_pos, + resolver.ptrs_resolver, + fo, + ); + let (_fp, fo) = ::rkyv::out_field!(out._phantom); + fo.write(core::marker::PhantomData); + } +} +impl ::rkyv::Serialize for Tup1 where - T0: dbsp::algebra::MulByRef, - W: dbsp::algebra::ZRingValue, + S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, + T0: ::rkyv::Archive + ::rkyv::Serialize + ::dbsp::utils::IsNone, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + let mut bitmap = [0u64; 1usize]; + let mut ptrs: [Tup1FieldPtr; 1usize] = [Tup1FieldPtr { pos: 0 }; 1usize]; + let mut ptrs_len = 0usize; + if ::dbsp::utils::IsNone::is_none(&self.0) { + bitmap[0] |= 1u64 << 0usize; + } else { + let pos = serializer.serialize_value(&self.0)?; + ptrs[ptrs_len] = Tup1FieldPtr { pos }; + ptrs_len += 1; + } + let ptrs_resolver = + ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::serialize_from_slice( + &ptrs[..ptrs_len], + serializer, + )?; + Ok(Tup1Resolver { + bitmap, + ptrs_resolver, + ptrs_len, + }) + } +} +impl ::rkyv::Deserialize, D> for ArchivedTup1 +where + D: ::rkyv::Fallible + ::core::any::Any, + T0: ::rkyv::Archive + Default, + ::rkyv::Archived: ::rkyv::Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let version = (deserializer as &mut dyn ::core::any::Any) + .downcast_mut::<::dbsp::storage::file::Deserializer>() + .map(|deserializer| deserializer.version()) + .expect("passed wrong deserializer"); + if version <= 3 { + let legacy = unsafe { &*(self as *const _ as *const ArchivedTup1V3) }; + return legacy.deserialize(deserializer); + } + let mut ptr_idx = 0usize; + let t0 = if self.none_bit_set(0) { + T0::default() + } else { + let archived = unsafe { + &*self + .ptrs + .as_slice() + .get_unchecked(ptr_idx) + .as_ptr() + .cast::<::rkyv::Archived>() + }; + ptr_idx += 1; + archived.deserialize(deserializer)? + }; + Ok(Tup1(t0)) + } +} +impl ::dbsp::algebra::MulByRef for Tup1 +where + T0: ::dbsp::algebra::MulByRef, + W: ::dbsp::algebra::ZRingValue, { type Output = Self; fn mul_by_ref(&self, other: &W) -> Self::Output { @@ -47,9 +281,9 @@ where Tup1(t0.mul_by_ref(other)) } } -impl dbsp::algebra::HasZero for Tup1 +impl ::dbsp::algebra::HasZero for Tup1 where - T0: dbsp::algebra::HasZero, + T0: ::dbsp::algebra::HasZero, { fn zero() -> Self { Tup1(T0::zero()) @@ -61,9 +295,9 @@ where result } } -impl dbsp::algebra::AddByRef for Tup1 +impl ::dbsp::algebra::AddByRef for Tup1 where - T0: dbsp::algebra::AddByRef, + T0: ::dbsp::algebra::AddByRef, { fn add_by_ref(&self, other: &Self) -> Self { let Tup1(t0) = self; @@ -71,9 +305,9 @@ where Tup1(t0.add_by_ref(other_t0)) } } -impl dbsp::algebra::AddAssignByRef for Tup1 +impl ::dbsp::algebra::AddAssignByRef for Tup1 where - T0: dbsp::algebra::AddAssignByRef, + T0: ::dbsp::algebra::AddAssignByRef, { fn add_assign_by_ref(&mut self, other: &Self) { let Tup1(ref mut t0) = self; @@ -81,9 +315,9 @@ where t0.add_assign_by_ref(other_t0); } } -impl dbsp::algebra::NegByRef for Tup1 +impl ::dbsp::algebra::NegByRef for Tup1 where - T0: dbsp::algebra::NegByRef, + T0: ::dbsp::algebra::NegByRef, { fn neg_by_ref(&self) -> Self { let Tup1(t0) = self; @@ -109,9 +343,9 @@ impl Into<(T0,)> for Tup1 { (t0,) } } -impl dbsp::NumEntries for Tup1 +impl ::dbsp::NumEntries for Tup1 where - T0: dbsp::NumEntries, + T0: ::dbsp::NumEntries, { const CONST_NUM_ENTRIES: Option = None; fn num_entries_shallow(&self) -> usize { @@ -125,28 +359,29 @@ where impl core::fmt::Debug for Tup1 { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { let Tup1(t0) = self; - f.debug_tuple(stringify!(Tup1)).field(&t0).finish() + f.debug_tuple("").field(&t0).finish() } } impl Copy for Tup1 {} - -#[repr(C)] -pub struct ArchivedTup1V3 +impl ::dbsp::circuit::checkpointer::Checkpoint for Tup1 where - T0: rkyv::Archive, + Tup1: ::rkyv::Serialize<::dbsp::storage::file::Serializer> + + ::dbsp::storage::file::Deserializable, { - pub t0: Archived, + fn checkpoint(&self) -> Result, ::dbsp::Error> { + let mut s = ::dbsp::storage::file::Serializer::default(); + let _offset = ::rkyv::ser::Serializer::serialize_value(&mut s, self).unwrap(); + let data = s.into_serializer().into_inner().into_vec(); + Ok(data) + } + fn restore(&mut self, data: &[u8]) -> Result<(), ::dbsp::Error> { + *self = ::dbsp::trace::unaligned_deserialize(data); + Ok(()) + } } - -impl rkyv::Deserialize, D> for ArchivedTup1V3 -where - D: rkyv::Fallible + ?Sized, - T0: rkyv::Archive, - Archived: rkyv::Deserialize, -{ - #[inline] - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Tup1(self.t0.deserialize(deserializer)?)) +impl ::dbsp::utils::IsNone for Tup1 { + fn is_none(&self) -> bool { + false } } @@ -162,7 +397,6 @@ where serde::Serialize, serde::Deserialize, size_of::SizeOf, - IsNone, )] pub struct Tup2(pub T0, pub T1); impl Tup2 { @@ -171,469 +405,267 @@ impl Tup2 { Self(t0, t1) } } -impl core::fmt::Debug for Tup2 { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { - let Tup2(t0, t1) = self; - f.debug_tuple("").field(&t0).field(&t1).finish() - } -} -impl Copy for Tup2 {} - -// ------------------------------------------------------------------------------------------------ -// Compact `rkyv` format for `Tup1` -// -// Motivation: `Archived>` is always `size_of::>()` even when the option is -// `None`. For very wide tuples (`Tup370`, ...), a large fraction of `None`s can otherwise dominate -// checkpoint size. This format stores a bitmap and only serializes values whose bit is *not* set -// according to `IsNone`. -// ------------------------------------------------------------------------------------------------ - -#[repr(C)] -pub struct ArchivedTup1 -where - T0: rkyv::Archive, -{ - bitmap: u8, - ptrs: rkyv::vec::ArchivedVec, - _phantom: core::marker::PhantomData T0>, -} - -#[inline] -unsafe fn archived_none_ptr() -> *const Archived { - static NONE: OnceLock = OnceLock::new(); - let ptr = *NONE.get_or_init(|| { - // This keeps a per-type, properly aligned `Archived` that we can - // reuse when the bitmap indicates a `None` value. - // SAFETY: This is only valid when `Archived` is `ArchivedOption<...>`. - let boxed: Box> = Box::new(unsafe { core::mem::zeroed() }); - Box::into_raw(boxed) as usize - }); - ptr as *const Archived -} - -impl ArchivedTup1 -where - T0: rkyv::Archive, -{ +impl Tup2 { #[inline] - fn none_bit_set(&self, idx: usize) -> bool { - debug_assert!(idx < 8); - (self.bitmap & (1u8 << idx)) != 0 + pub fn get_0(&self) -> &T0 { + &self.0 } - #[inline] - fn idx_for_field(&self, field_idx: usize) -> usize { - debug_assert!(field_idx == 0); - 0 + pub fn get_0_mut(&mut self) -> &mut T0 { + &mut self.0 } - +} +impl Tup2 { #[inline] - fn get_t0(&self) -> &Archived { - if self.none_bit_set(0) { - // SAFETY: The bitmap only marks `None` for types whose archived - // representation is `ArchivedOption<...>`; a zeroed archived - // option is valid for the `None` variant. - unsafe { &*archived_none_ptr::() } - } else { - debug_assert!(!self.ptrs.is_empty()); - // SAFETY: `ptrs[0]` points at the archived `T0` when the bit is clear. - unsafe { - &*self - .ptrs - .as_slice() - .get_unchecked(0) - .as_ptr() - .cast::>() - } - } + pub fn get_1(&self) -> &T1 { + &self.1 } -} - -impl core::cmp::PartialEq for ArchivedTup1 -where - T0: rkyv::Archive, - Archived: core::cmp::PartialEq, -{ #[inline] - fn eq(&self, other: &Self) -> bool { - self.get_t0() == other.get_t0() + pub fn get_1_mut(&mut self) -> &mut T1 { + &mut self.1 } } - -impl core::cmp::Eq for ArchivedTup1 +pub struct ArchivedTup2V3 where - T0: rkyv::Archive, - Archived: core::cmp::Eq, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, { + pub t0: ::rkyv::Archived, + pub t1: ::rkyv::Archived, } - -impl core::cmp::PartialOrd for ArchivedTup1 +impl ::rkyv::Deserialize, D> for ArchivedTup2V3 where - T0: rkyv::Archive, - Archived: core::cmp::Ord, + D: ::rkyv::Fallible + ?Sized, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, + ::rkyv::Archived: ::rkyv::Deserialize, + ::rkyv::Archived: ::rkyv::Deserialize, { #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl core::cmp::Ord for ArchivedTup1 -where - T0: rkyv::Archive, - Archived: core::cmp::Ord, -{ - #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.get_t0().cmp(other.get_t0()) + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Tup2( + self.t0.deserialize(deserializer)?, + self.t1.deserialize(deserializer)?, + )) } } - -pub struct Tup1Resolver { - bitmap: u8, - ptrs_resolver: rkyv::vec::VecResolver, - ptrs_len: usize, -} - -struct FieldPtr { +#[derive(Copy, Clone)] +struct Tup2FieldPtr { pos: usize, } - -impl rkyv::Archive for FieldPtr { - type Archived = rkyv::RawRelPtr; +impl ::rkyv::Archive for Tup2FieldPtr { + type Archived = ::rkyv::rel_ptr::RawRelPtrI32; type Resolver = usize; - #[inline] unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - rkyv::RawRelPtr::emplace(pos, resolver, out); + ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos, resolver, out); } } - -impl rkyv::Serialize for FieldPtr +impl ::rkyv::Serialize for Tup2FieldPtr where - S: rkyv::ser::Serializer + ?Sized, + S: ::rkyv::ser::Serializer + ?Sized, { #[inline] fn serialize(&self, _serializer: &mut S) -> Result { Ok(self.pos) } } - -impl rkyv::Archive for Tup1 -where - T0: rkyv::Archive, -{ - type Archived = ArchivedTup1; - type Resolver = Tup1Resolver; - - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let (fp, fo) = out_field!(out.bitmap); - u8::resolve(&resolver.bitmap, pos + fp, (), fo); - - let (fp, fo) = out_field!(out.ptrs); - let vec_pos = pos + fp; - rkyv::vec::ArchivedVec::::resolve_from_len( - resolver.ptrs_len, - vec_pos, - resolver.ptrs_resolver, - fo, - ); - } -} - -impl rkyv::Serialize for Tup1 -where - S: rkyv::ser::Serializer + rkyv::ser::ScratchSpace + ?Sized, - T0: rkyv::Archive + rkyv::Serialize + IsNone, -{ - #[inline] - fn serialize(&self, serializer: &mut S) -> Result { - if self.0.is_none() { - Ok(Tup1Resolver { - bitmap: 1, - ptrs_resolver: rkyv::vec::ArchivedVec::::serialize_from_slice( - &[] as &[FieldPtr], - serializer, - )?, - ptrs_len: 0, - }) - } else { - let t0_pos = serializer.serialize_value(&self.0)?; - let ptrs = [FieldPtr { pos: t0_pos }]; - let ptrs_resolver = - rkyv::vec::ArchivedVec::::serialize_from_slice(&ptrs, serializer)?; - Ok(Tup1Resolver { - bitmap: 0, - ptrs_resolver, - ptrs_len: 1, - }) - } - } -} - -impl rkyv::Deserialize, D> for ArchivedTup1 -where - D: rkyv::Fallible + core::any::Any, - T0: rkyv::Archive + Default, - Archived: rkyv::Deserialize, -{ - #[inline] - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - let version = (deserializer as &mut dyn core::any::Any) - .downcast_mut::() - .map(|deserializer| deserializer.version()) - .unwrap_or(dbsp::storage::file::format::VERSION_NUMBER); - if version < dbsp::storage::file::format::VERSION_NUMBER { - // SAFETY: V3 files store tuples with the old archived layout. - let v3 = unsafe { &*(self as *const _ as *const ArchivedTup1V3) }; - return v3.deserialize(deserializer); - } - if self.none_bit_set(0) { - Ok(Tup1(T0::default())) - } else { - let archived = unsafe { - &*self - .ptrs - .as_slice() - .get_unchecked(0) - .as_ptr() - .cast::>() - }; - Ok(Tup1(archived.deserialize(deserializer)?)) - } - } -} - -#[repr(C)] -pub struct ArchivedTup2V3 -where - T0: rkyv::Archive, - T1: rkyv::Archive, -{ - pub t0: Archived, - pub t1: Archived, -} - -impl rkyv::Deserialize, D> for ArchivedTup2V3 -where - D: rkyv::Fallible + ?Sized, - T0: rkyv::Archive, - T1: rkyv::Archive, - Archived: rkyv::Deserialize, - Archived: rkyv::Deserialize, -{ - #[inline] - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Tup2( - self.t0.deserialize(deserializer)?, - self.t1.deserialize(deserializer)?, - )) - } +#[inline] +unsafe fn __tup2_archived_none_ptr() -> *const ::rkyv::Archived { + static NONE: ::std::sync::OnceLock = ::std::sync::OnceLock::new(); + let ptr = *NONE.get_or_init(|| { + let boxed: Box<::rkyv::Archived> = Box::new(unsafe { ::core::mem::zeroed() }); + Box::into_raw(boxed) as usize + }); + ptr as *const ::rkyv::Archived } - -// ------------------------------------------------------------------------------------------------ -// Compact `rkyv` format for `Tup2` -// -// Uses `ArchivedVec` so the pointer list can be empty when all fields are `None` -// according to `IsNone`. -// ------------------------------------------------------------------------------------------------ - -#[repr(C)] pub struct ArchivedTup2 where - T0: rkyv::Archive, - T1: rkyv::Archive, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, { - bitmap: u8, - ptrs: rkyv::vec::ArchivedVec, + bitmap: [u64; 1usize], + ptrs: ::rkyv::vec::ArchivedVec<::rkyv::rel_ptr::RawRelPtrI32>, _phantom: core::marker::PhantomData (T0, T1)>, } - impl ArchivedTup2 where - T0: rkyv::Archive, - T1: rkyv::Archive, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, { #[inline] - fn idx_for_field(&self, field_idx: usize) -> usize { - debug_assert!(field_idx <= 1); - match field_idx { - 0 => 0, - _ => { - if self.none_bit_set(0) { - 0 - } else { - 1 - } - } - } + fn none_bit_set(&self, idx: usize) -> bool { + debug_assert!(idx < 2usize); + let word = idx / 64; + let bit = idx % 64; + (self.bitmap[word] & (1u64 << bit)) != 0 } - #[inline] - fn none_bit_set(&self, idx: usize) -> bool { - debug_assert!(idx < 8); - (self.bitmap & (1u8 << idx)) != 0 + fn idx_for_field(&self, field_idx: usize) -> usize { + debug_assert!(field_idx < 2usize); + let word = field_idx / 64; + let bit = field_idx % 64; + let mut idx = 0usize; + let mut w = 0usize; + while w < word { + idx += 64usize - (self.bitmap[w].count_ones() as usize); + w += 1; + } + let mask = if bit == 0 { 0 } else { (1u64 << bit) - 1 }; + let none_before = (self.bitmap[word] & mask).count_ones() as usize; + idx + bit - none_before } - #[inline] - fn get_t0(&self) -> &Archived { + pub fn get_t0(&self) -> &::rkyv::Archived { if self.none_bit_set(0) { - // SAFETY: See `ArchivedTup1::get_t0` for the `ArchivedOption` reasoning. - unsafe { &*archived_none_ptr::() } + unsafe { &*__tup2_archived_none_ptr::() } } else { - debug_assert!(!self.ptrs.is_empty()); - // SAFETY: `ptrs[0]` points at the archived `T0` when the bit is clear. + let ptr_idx = self.idx_for_field(0); + debug_assert!(ptr_idx < self.ptrs.len()); unsafe { &*self .ptrs .as_slice() - .get_unchecked(0) + .get_unchecked(ptr_idx) .as_ptr() - .cast::>() + .cast::<::rkyv::Archived>() } } } - #[inline] - fn get_t1(&self) -> &Archived { + pub fn get_t1(&self) -> &::rkyv::Archived { if self.none_bit_set(1) { - // SAFETY: See `ArchivedTup1::get_t0` for the `ArchivedOption` reasoning. - unsafe { &*archived_none_ptr::() } + unsafe { &*__tup2_archived_none_ptr::() } } else { - let idx = self.idx_for_field(1); - debug_assert!(idx < self.ptrs.len()); - // SAFETY: `ptrs[idx]` points at the archived `T1` when its bit is clear. + let ptr_idx = self.idx_for_field(1); + debug_assert!(ptr_idx < self.ptrs.len()); unsafe { &*self .ptrs .as_slice() - .get_unchecked(idx) + .get_unchecked(ptr_idx) .as_ptr() - .cast::>() + .cast::<::rkyv::Archived>() } } } } - impl core::cmp::PartialEq for ArchivedTup2 where - T0: rkyv::Archive, - T1: rkyv::Archive, - Archived: core::cmp::PartialEq, - Archived: core::cmp::PartialEq, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, + ::rkyv::Archived: core::cmp::PartialEq, + ::rkyv::Archived: core::cmp::PartialEq, { #[inline] fn eq(&self, other: &Self) -> bool { - unsafe { self.get_t0() == other.get_t0() && self.get_t1() == other.get_t1() } + true && self.get_t0() == other.get_t0() && self.get_t1() == other.get_t1() } } - impl core::cmp::Eq for ArchivedTup2 where - T0: rkyv::Archive, - T1: rkyv::Archive, - Archived: core::cmp::Eq, - Archived: core::cmp::Eq, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, + ::rkyv::Archived: core::cmp::Eq, + ::rkyv::Archived: core::cmp::Eq, { } - impl core::cmp::PartialOrd for ArchivedTup2 where - T0: rkyv::Archive, - T1: rkyv::Archive, - Archived: core::cmp::Ord, - Archived: core::cmp::Ord, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, + ::rkyv::Archived: core::cmp::Ord, + ::rkyv::Archived: core::cmp::Ord, { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } - impl core::cmp::Ord for ArchivedTup2 where - T0: rkyv::Archive, - T1: rkyv::Archive, - Archived: core::cmp::Ord, - Archived: core::cmp::Ord, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, + ::rkyv::Archived: core::cmp::Ord, + ::rkyv::Archived: core::cmp::Ord, { #[inline] fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let t0_cmp = unsafe { self.get_t0().cmp(other.get_t0()) }; - if t0_cmp != core::cmp::Ordering::Equal { - return t0_cmp; + let cmp = self.get_t0().cmp(other.get_t0()); + if cmp != core::cmp::Ordering::Equal { + return cmp; + } + let cmp = self.get_t1().cmp(other.get_t1()); + if cmp != core::cmp::Ordering::Equal { + return cmp; } - unsafe { self.get_t1().cmp(other.get_t1()) } + core::cmp::Ordering::Equal } } - pub struct Tup2Resolver { - bitmap: u8, - ptrs_resolver: rkyv::vec::VecResolver, + bitmap: [u64; 1usize], + ptrs_resolver: ::rkyv::vec::VecResolver, ptrs_len: usize, } - -impl rkyv::Archive for Tup2 +impl ::rkyv::Archive for Tup2 where - T0: rkyv::Archive, - T1: rkyv::Archive, + T0: ::rkyv::Archive, + T1: ::rkyv::Archive, { type Archived = ArchivedTup2; type Resolver = Tup2Resolver; - #[inline] unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let (fp, fo) = out_field!(out.bitmap); - u8::resolve(&resolver.bitmap, pos + fp, (), fo); - - let (fp, fo) = out_field!(out.ptrs); + let (fp, fo) = ::rkyv::out_field!(out.bitmap); + let bitmap_out = fo.cast::(); + u64::resolve( + &resolver.bitmap[0], + pos + fp + (0 * ::core::mem::size_of::()), + (), + bitmap_out.add(0), + ); + let (fp, fo) = ::rkyv::out_field!(out.ptrs); let vec_pos = pos + fp; - rkyv::vec::ArchivedVec::::resolve_from_len( + ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::resolve_from_len( resolver.ptrs_len, vec_pos, resolver.ptrs_resolver, fo, ); - - let (_fp, fo) = out_field!(out._phantom); + let (_fp, fo) = ::rkyv::out_field!(out._phantom); fo.write(core::marker::PhantomData); } } - -impl rkyv::Serialize for Tup2 +impl ::rkyv::Serialize for Tup2 where - S: rkyv::ser::Serializer + rkyv::ser::ScratchSpace + ?Sized, - T0: rkyv::Archive + rkyv::Serialize + IsNone, - T1: rkyv::Archive + rkyv::Serialize + IsNone, + S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, + T0: ::rkyv::Archive + ::rkyv::Serialize + ::dbsp::utils::IsNone, + T1: ::rkyv::Archive + ::rkyv::Serialize + ::dbsp::utils::IsNone, { #[inline] fn serialize(&self, serializer: &mut S) -> Result { - let mut bitmap = 0u8; - let mut ptrs = [FieldPtr { pos: 0 }, FieldPtr { pos: 0 }]; + let mut bitmap = [0u64; 1usize]; + let mut ptrs: [Tup2FieldPtr; 2usize] = [Tup2FieldPtr { pos: 0 }; 2usize]; let mut ptrs_len = 0usize; - - if self.0.is_none() { - bitmap |= 1; + if ::dbsp::utils::IsNone::is_none(&self.0) { + bitmap[0] |= 1u64 << 0usize; } else { let pos = serializer.serialize_value(&self.0)?; - ptrs[ptrs_len] = FieldPtr { pos }; + ptrs[ptrs_len] = Tup2FieldPtr { pos }; ptrs_len += 1; } - - if self.1.is_none() { - bitmap |= 2; + if ::dbsp::utils::IsNone::is_none(&self.1) { + bitmap[0] |= 1u64 << 1usize; } else { let pos = serializer.serialize_value(&self.1)?; - ptrs[ptrs_len] = FieldPtr { pos }; + ptrs[ptrs_len] = Tup2FieldPtr { pos }; ptrs_len += 1; } - - let ptrs_resolver = rkyv::vec::ArchivedVec::::serialize_from_slice( - &ptrs[..ptrs_len], - serializer, - )?; - + let ptrs_resolver = + ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::serialize_from_slice( + &ptrs[..ptrs_len], + serializer, + )?; Ok(Tup2Resolver { bitmap, ptrs_resolver, @@ -641,28 +673,25 @@ where }) } } - -impl rkyv::Deserialize, D> for ArchivedTup2 +impl ::rkyv::Deserialize, D> for ArchivedTup2 where - D: rkyv::Fallible + core::any::Any, - T0: rkyv::Archive + Default, - T1: rkyv::Archive + Default, - Archived: rkyv::Deserialize, - Archived: rkyv::Deserialize, + D: ::rkyv::Fallible + ::core::any::Any, + T0: ::rkyv::Archive + Default, + T1: ::rkyv::Archive + Default, + ::rkyv::Archived: ::rkyv::Deserialize, + ::rkyv::Archived: ::rkyv::Deserialize, { #[inline] fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - let version = (deserializer as &mut dyn core::any::Any) - .downcast_mut::() + let version = (deserializer as &mut dyn ::core::any::Any) + .downcast_mut::<::dbsp::storage::file::Deserializer>() .map(|deserializer| deserializer.version()) - .unwrap_or(dbsp::storage::file::format::VERSION_NUMBER); - if version < dbsp::storage::file::format::VERSION_NUMBER { - // SAFETY: V3 files store tuples with the old archived layout. - let v3 = unsafe { &*(self as *const _ as *const ArchivedTup2V3) }; - return v3.deserialize(deserializer); + .expect("passed wrong deserializer"); + if version <= 3 { + let legacy = unsafe { &*(self as *const _ as *const ArchivedTup2V3) }; + return legacy.deserialize(deserializer); } - let mut idx = 0usize; - + let mut ptr_idx = 0usize; let t0 = if self.none_bit_set(0) { T0::default() } else { @@ -670,14 +699,13 @@ where &*self .ptrs .as_slice() - .get_unchecked(idx) + .get_unchecked(ptr_idx) .as_ptr() - .cast::>() + .cast::<::rkyv::Archived>() }; - idx += 1; + ptr_idx += 1; archived.deserialize(deserializer)? }; - let t1 = if self.none_bit_set(1) { T1::default() } else { @@ -685,52 +713,138 @@ where &*self .ptrs .as_slice() - .get_unchecked(idx) + .get_unchecked(ptr_idx) .as_ptr() - .cast::>() + .cast::<::rkyv::Archived>() }; - idx += 1; + ptr_idx += 1; archived.deserialize(deserializer)? }; - - debug_assert_eq!(idx, self.ptrs.len()); Ok(Tup2(t0, t1)) } } - -impl dbsp::circuit::checkpointer::Checkpoint for Tup1 +impl ::dbsp::algebra::MulByRef for Tup2 where - Tup1: - ::rkyv::Serialize + dbsp::storage::file::Deserializable, + T0: ::dbsp::algebra::MulByRef, + T1: ::dbsp::algebra::MulByRef, + W: ::dbsp::algebra::ZRingValue, { - fn checkpoint(&self) -> Result, dbsp::Error> { - let mut s = dbsp::storage::file::Serializer::default(); - let _offset = ::rkyv::ser::Serializer::serialize_value(&mut s, self).unwrap(); - let data = s.into_serializer().into_inner().into_vec(); - Ok(data) + type Output = Self; + fn mul_by_ref(&self, other: &W) -> Self::Output { + let Tup2(t0, t1) = self; + Tup2(t0.mul_by_ref(other), t1.mul_by_ref(other)) } - fn restore(&mut self, data: &[u8]) -> Result<(), dbsp::Error> { - *self = dbsp::trace::unaligned_deserialize(data); - Ok(()) +} +impl ::dbsp::algebra::HasZero for Tup2 +where + T0: ::dbsp::algebra::HasZero, + T1: ::dbsp::algebra::HasZero, +{ + fn zero() -> Self { + Tup2(T0::zero(), T1::zero()) + } + fn is_zero(&self) -> bool { + let mut result = true; + let Tup2(t0, t1) = self; + result = result && t0.is_zero(); + result = result && t1.is_zero(); + result } } - -impl dbsp::circuit::checkpointer::Checkpoint for Tup2 +impl ::dbsp::algebra::AddByRef for Tup2 +where + T0: ::dbsp::algebra::AddByRef, + T1: ::dbsp::algebra::AddByRef, +{ + fn add_by_ref(&self, other: &Self) -> Self { + let Tup2(t0, t1) = self; + let Tup2(other_t0, other_t1) = other; + Tup2(t0.add_by_ref(other_t0), t1.add_by_ref(other_t1)) + } +} +impl ::dbsp::algebra::AddAssignByRef for Tup2 +where + T0: ::dbsp::algebra::AddAssignByRef, + T1: ::dbsp::algebra::AddAssignByRef, +{ + fn add_assign_by_ref(&mut self, other: &Self) { + let Tup2(ref mut t0, ref mut t1) = self; + let Tup2(ref other_t0, ref other_t1) = other; + t0.add_assign_by_ref(other_t0); + t1.add_assign_by_ref(other_t1); + } +} +impl ::dbsp::algebra::NegByRef for Tup2 +where + T0: ::dbsp::algebra::NegByRef, + T1: ::dbsp::algebra::NegByRef, +{ + fn neg_by_ref(&self) -> Self { + let Tup2(t0, t1) = self; + Tup2(t0.neg_by_ref(), t1.neg_by_ref()) + } +} +impl From<(T0, T1)> for Tup2 { + fn from((t0, t1): (T0, T1)) -> Self { + Self(t0, t1) + } +} +impl<'a, T0, T1> Into<(&'a T0, &'a T1)> for &'a Tup2 { + #[allow(clippy::from_over_into)] + fn into(self) -> (&'a T0, &'a T1) { + let Tup2(t0, t1) = &self; + (t0, t1) + } +} +impl Into<(T0, T1)> for Tup2 { + #[allow(clippy::from_over_into)] + fn into(self) -> (T0, T1) { + let Tup2(t0, t1) = self; + (t0, t1) + } +} +impl ::dbsp::NumEntries for Tup2 +where + T0: ::dbsp::NumEntries, + T1: ::dbsp::NumEntries, +{ + const CONST_NUM_ENTRIES: Option = None; + fn num_entries_shallow(&self) -> usize { + 2usize + } + fn num_entries_deep(&self) -> usize { + let Tup2(t0, t1) = self; + 0 + (t0).num_entries_deep() + (t1).num_entries_deep() + } +} +impl core::fmt::Debug for Tup2 { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { + let Tup2(t0, t1) = self; + f.debug_tuple("").field(&t0).field(&t1).finish() + } +} +impl Copy for Tup2 {} +impl ::dbsp::circuit::checkpointer::Checkpoint for Tup2 where - Tup2: - ::rkyv::Serialize + dbsp::storage::file::Deserializable, + Tup2: ::rkyv::Serialize<::dbsp::storage::file::Serializer> + + ::dbsp::storage::file::Deserializable, { - fn checkpoint(&self) -> Result, dbsp::Error> { - let mut s = dbsp::storage::file::Serializer::default(); + fn checkpoint(&self) -> Result, ::dbsp::Error> { + let mut s = ::dbsp::storage::file::Serializer::default(); let _offset = ::rkyv::ser::Serializer::serialize_value(&mut s, self).unwrap(); let data = s.into_serializer().into_inner().into_vec(); Ok(data) } - fn restore(&mut self, data: &[u8]) -> Result<(), dbsp::Error> { - *self = dbsp::trace::unaligned_deserialize(data); + fn restore(&mut self, data: &[u8]) -> Result<(), ::dbsp::Error> { + *self = ::dbsp::trace::unaligned_deserialize(data); Ok(()) } } +impl ::dbsp::utils::IsNone for Tup2 { + fn is_none(&self) -> bool { + false + } +} #[test] fn compile_tup1() { diff --git a/crates/storage-test-compat/Cargo.toml b/crates/storage-test-compat/Cargo.toml new file mode 100644 index 0000000000..8c8205818f --- /dev/null +++ b/crates/storage-test-compat/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "storage-test-compat" +authors.workspace = true +version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +edition.workspace = true + +[dependencies] +dbsp = { workspace = true } +feldera-sqllib = { workspace = true } +feldera-macros = { workspace = true } +uuid = { workspace = true, features = ["v4", "std"] } +serde = { workspace = true, features = ["derive"] } +size-of = { workspace = true } +rkyv = { workspace = true, features = ["std", "size_64", "validation", "smallvec"] } +derive_more = { version = "1.0", features = ["add", "not", "from", "debug"] } +feldera-types = { workspace = true } diff --git a/crates/storage-test-compat/golden-files/golden-batch-v3-snappy.feldera b/crates/storage-test-compat/golden-files/golden-batch-v3-snappy.feldera new file mode 100644 index 0000000000000000000000000000000000000000..b4ec9ee746818047af10b8e796bfa571d4b99dba GIT binary patch literal 84992 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 literal 0 HcmV?d00001 diff --git a/crates/storage-test-compat/golden-files/golden-batch-v3.feldera b/crates/storage-test-compat/golden-files/golden-batch-v3.feldera new file mode 100644 index 0000000000000000000000000000000000000000..af75d9df3a6b9a8ec5d3b3e09ad0f2adda206abe GIT binary patch literal 337408 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 literal 0 HcmV?d00001 diff --git a/crates/storage-test-compat/golden-files/golden-batch-v4-snappy.feldera b/crates/storage-test-compat/golden-files/golden-batch-v4-snappy.feldera new file mode 100644 index 0000000000000000000000000000000000000000..5dd05dc7f95c9bc2fa95677abda1eea0b83956a4 GIT binary patch literal 98304 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 z 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 ag^0oiZsa!nLtKrvKsdnf`pbo4$4LsZ&+w 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 literal 0 HcmV?d00001 diff --git a/crates/storage-test-compat/src/bin/golden-writer.rs b/crates/storage-test-compat/src/bin/golden-writer.rs new file mode 100644 index 0000000000..d2147a6742 --- /dev/null +++ b/crates/storage-test-compat/src/bin/golden-writer.rs @@ -0,0 +1,97 @@ +/// Generate new golden files by running: +/// `cargo run -p feldera-sqllib-test --bin golden-writer` +/// +/// whenever you increment `VERSION_NUMBER` +use std::path::PathBuf; + +use dbsp::dynamic::DynData; +use dbsp::storage::backend::StorageBackend; +use dbsp::storage::file::Factories; +use dbsp::storage::file::format::Compression; +use dbsp::storage::file::format::VERSION_NUMBER; +use dbsp::storage::file::writer::{Parameters, Writer1}; +use feldera_types::config::{StorageConfig, StorageOptions}; + +use storage_test_compat::{ + DEFAULT_ROWS, GoldenRow, buffer_cache, golden_row, storage_base_and_path, +}; + +struct Config { + rows: usize, + compression: Option, +} + +impl Config { + fn output(&self) -> PathBuf { + let mut file_name = format!("golden-batch-v{VERSION_NUMBER}"); + match self.compression { + Some(Compression::Snappy) => { + file_name += "-snappy"; + } + None => (), + } + file_name += ".feldera"; + + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("golden-files") + .join(file_name) + } +} + +impl Default for Config { + fn default() -> Self { + let rows = DEFAULT_ROWS; + let compression = Some(Compression::Snappy); + + Config { rows, compression } + } +} + +fn main() -> Result<(), Box> { + let mut config = Config::default(); + for compression in [None, Some(Compression::Snappy)] { + config.compression = compression; + + let output = if config.output().is_absolute() { + config.output() + } else { + std::env::current_dir()?.join(config.output()) + }; + let (base_dir, output_storage_path) = storage_base_and_path(&output); + std::fs::create_dir_all(&base_dir)?; + + let storage_backend = ::new( + &StorageConfig { + path: base_dir.to_string_lossy().to_string(), + cache: Default::default(), + }, + &StorageOptions::default(), + )?; + + let factories = Factories::::new::(); + let parameters = Parameters::default().with_compression(config.compression); + let mut writer = Writer1::new( + &factories, + buffer_cache, + &*storage_backend, + parameters, + config.rows, + )?; + + for row in 0..config.rows { + let key = golden_row(row); + let aux = (); + writer.write0((&key, &aux))?; + } + + let tmp_path = writer.path().clone(); + let (_file_handle, _bloom_filter) = writer.close()?; + let content = storage_backend.read(&tmp_path)?; + storage_backend.write(&output_storage_path, (*content).clone())?; + storage_backend.delete(&tmp_path)?; + + println!("wrote {} rows to {}", config.rows, output.display()); + } + + Ok(()) +} diff --git a/crates/storage-test-compat/src/lib.rs b/crates/storage-test-compat/src/lib.rs new file mode 100644 index 0000000000..2f7eb013a1 --- /dev/null +++ b/crates/storage-test-compat/src/lib.rs @@ -0,0 +1,419 @@ +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +use dbsp::algebra::{F32, F64}; +use dbsp::storage::backend::StoragePath; +use dbsp::storage::buffer_cache::BufferCache; +use uuid::Uuid as RawUuid; + +use feldera_sqllib::{ + to_array, to_map, Array, ByteArray, Date, GeoPoint, LongInterval, Map, ShortInterval, + SqlDecimal, SqlString, Time, Timestamp, Uuid, Variant, +}; + +type Opt = Option; +type Dec12_2 = SqlDecimal<12, 2>; +type Dec10_0 = SqlDecimal<10, 0>; +type Dec18_4 = SqlDecimal<18, 4>; + +feldera_macros::declare_tuple! { + Tup65< + T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, + T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, + T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, + T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, + T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, + T50, T51, T52, T53, T54, T55, T56, T57, T58, T59, + T60, T61, T62, T63, T64 + > +} + +pub type GoldenRow = Tup65< + u64, + bool, + i8, + i16, + i32, + i64, + i128, + u8, + u16, + u32, + u128, + isize, + usize, + F32, + F64, + char, + String, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + SqlString, + ByteArray, + GeoPoint, + ShortInterval, + LongInterval, + Timestamp, + Date, + Time, + Uuid, + Variant, + Dec12_2, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt, + Opt

)H{1^iB}X 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 z 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 ag^0oiZsa!nLtY?EA1Z4EsQ%4X)#kiqhl0pwq66 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 V;f!Le51QDGAOFv%?f=Zr|6kFl--!SK literal 384000 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 From f3ff126d161c577ebadb2aa8d9501e1346c4051f Mon Sep 17 00:00:00 2001 From: Gerd Zellweger Date: Wed, 14 Jan 2026 10:30:47 -0800 Subject: [PATCH 5/6] [storage] More extensive testing. Adds more comprehensive test suite for tuples to make sure it's doing the right thing given the complexity of the new formats. Signed-off-by: Gerd Zellweger --- .github/workflows/test-unit.yml | 12 + crates/dbsp/src/dynamic/pair.rs | 6 +- crates/dbsp/src/dynamic/rkyv.rs | 5 +- crates/dbsp/src/operator/group/custom_ord.rs | 10 +- crates/dbsp/src/storage/file/test.rs | 98 +- crates/dbsp/src/trace.rs | 2 +- crates/dbsp/src/trace/spine_async.rs | 4 +- crates/dbsp/src/utils/is_none.rs | 8 +- crates/feldera-macros/Cargo.toml | 1 + crates/feldera-macros/src/lib.rs | 5 + crates/feldera-macros/src/tuples.rs | 34 +- crates/feldera-macros/tests/compile.rs | 1639 -------------- .../tests/declare_tuple_rkyv.rs | 106 - crates/feldera-macros/tests/tuple_formats.rs | 271 +++ crates/feldera-macros/tests/tuple_proptest.rs | 1902 +++++++++++++++++ crates/ir/Cargo.toml | 2 +- crates/storage-test-compat/README.md | 26 + ....feldera => golden-batch-v3-large.feldera} | Bin .../golden-batch-v3-small.feldera | Bin 0 -> 25600 bytes ...a => golden-batch-v3-snappy-large.feldera} | Bin .../golden-batch-v3-snappy-small.feldera | Bin 0 -> 10752 bytes ....feldera => golden-batch-v4-large.feldera} | Bin .../golden-batch-v4-small.feldera | Bin 0 -> 25600 bytes ...a => golden-batch-v4-snappy-large.feldera} | Bin .../golden-batch-v4-snappy-small.feldera | Bin 0 -> 10752 bytes .../src/bin/golden-writer.rs | 142 +- crates/storage-test-compat/src/lib.rs | 116 +- 27 files changed, 2516 insertions(+), 1873 deletions(-) delete mode 100644 crates/feldera-macros/tests/compile.rs delete mode 100644 crates/feldera-macros/tests/declare_tuple_rkyv.rs create mode 100644 crates/feldera-macros/tests/tuple_formats.rs create mode 100644 crates/feldera-macros/tests/tuple_proptest.rs create mode 100644 crates/storage-test-compat/README.md rename crates/storage-test-compat/golden-files/{golden-batch-v3.feldera => golden-batch-v3-large.feldera} (100%) create mode 100644 crates/storage-test-compat/golden-files/golden-batch-v3-small.feldera rename crates/storage-test-compat/golden-files/{golden-batch-v3-snappy.feldera => golden-batch-v3-snappy-large.feldera} (100%) create mode 100644 crates/storage-test-compat/golden-files/golden-batch-v3-snappy-small.feldera rename crates/storage-test-compat/golden-files/{golden-batch-v4.feldera => golden-batch-v4-large.feldera} (100%) create mode 100644 crates/storage-test-compat/golden-files/golden-batch-v4-small.feldera rename crates/storage-test-compat/golden-files/{golden-batch-v4-snappy.feldera => golden-batch-v4-snappy-large.feldera} (100%) create mode 100644 crates/storage-test-compat/golden-files/golden-batch-v4-snappy-small.feldera diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index 5a91d84a0f..ae8aaf33db 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -72,6 +72,18 @@ jobs: if: ${{ vars.CI_DRY_RUN != 'true' }} run: ./build/feldera_sqllib-* + - name: feldera-macros + if: ${{ vars.CI_DRY_RUN != 'true' }} + run: | + ./build/feldera_macros-* + ./build/tuple_formats-* + ./build/tuple_proptest-* + + - name: storage-test-compat + if: ${{ vars.CI_DRY_RUN != 'true' }} + run: ./build/storage_test_compat-* + working-directory: crates/storage-test-compat + - name: feldera-ir if: ${{ vars.CI_DRY_RUN != 'true' }} run: ./build/feldera_ir-* diff --git a/crates/dbsp/src/dynamic/pair.rs b/crates/dbsp/src/dynamic/pair.rs index a36d081dae..277a5edf62 100644 --- a/crates/dbsp/src/dynamic/pair.rs +++ b/crates/dbsp/src/dynamic/pair.rs @@ -1,10 +1,6 @@ use std::mem::take; -use crate::{ - DBData, declare_trait_object, - dynamic::erase::Erase, - utils::Tup2, -}; +use crate::{DBData, declare_trait_object, dynamic::erase::Erase, utils::Tup2}; use super::{Data, DataTrait}; diff --git a/crates/dbsp/src/dynamic/rkyv.rs b/crates/dbsp/src/dynamic/rkyv.rs index aa6fe75a87..8283e5fe25 100644 --- a/crates/dbsp/src/dynamic/rkyv.rs +++ b/crates/dbsp/src/dynamic/rkyv.rs @@ -166,10 +166,7 @@ where Trait: DowncastTrait + ?Sized + 'static, { fn deserialize_with(&self, target: &mut Trait, deserializer: &mut Deserializer) { - *unsafe { target.downcast_mut::() } = self - .archived - .deserialize(deserializer) - .unwrap() + *unsafe { target.downcast_mut::() } = self.archived.deserialize(deserializer).unwrap() } fn eq_target(&self, other: &Trait) -> bool { diff --git a/crates/dbsp/src/operator/group/custom_ord.rs b/crates/dbsp/src/operator/group/custom_ord.rs index 285f264ea7..db02991e49 100644 --- a/crates/dbsp/src/operator/group/custom_ord.rs +++ b/crates/dbsp/src/operator/group/custom_ord.rs @@ -160,14 +160,8 @@ where // TODO(deserialization): Not ideal -- we're deserializing the values just to // compare them. Better would be to have `F: CmpFunc` for // the Archived (we already know that T::Archived implements Ord). - let real_self: T = self - .val - .deserialize(&mut Deserializer::default()) - .unwrap(); - let real_other: T = other - .val - .deserialize(&mut Deserializer::default()) - .unwrap(); + let real_self: T = self.val.deserialize(&mut Deserializer::default()).unwrap(); + let real_other: T = other.val.deserialize(&mut Deserializer::default()).unwrap(); F::cmp(&real_self, &real_other) } } diff --git a/crates/dbsp/src/storage/file/test.rs b/crates/dbsp/src/storage/file/test.rs index b966f65c55..d7bdc8a138 100644 --- a/crates/dbsp/src/storage/file/test.rs +++ b/crates/dbsp/src/storage/file/test.rs @@ -43,15 +43,71 @@ feldera_macros::declare_tuple! { type OptString = Option; type Tup65OptString = Tup65< - OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, - OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, - OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, - OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, - OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, - OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, - OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, - OptString, OptString, OptString, OptString, OptString, OptString, OptString, OptString, - OptString + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, + OptString, >; // Map bits to fields in MSB->LSB order so row indices remain lexicographically sorted. @@ -61,11 +117,7 @@ fn bit_set(bits: u128, idx: usize) -> bool { } fn opt_str(bit: bool) -> Option { - if bit { - Some("abc".to_string()) - } else { - None - } + if bit { Some("abc".to_string()) } else { None } } fn tup65_from_bits(bits: u128) -> Tup65OptString { @@ -1039,13 +1091,17 @@ fn test_tuple() { fn test_tup65_option_string() { init_test_logger(); for_each_compression_type(Parameters::default(), |parameters| { - test_one_column(1_000usize, |row| { - let bits = row as u128 * 2 + 1; - let before = tup65_from_bits(bits - 1); - let key = tup65_from_bits(bits); - let after = tup65_from_bits(bits + 1); - (before, key, after, ()) - }, parameters); + test_one_column( + 1_000usize, + |row| { + let bits = row as u128 * 2 + 1; + let before = tup65_from_bits(bits - 1); + let key = tup65_from_bits(bits); + let after = tup65_from_bits(bits + 1); + (before, key, after, ()) + }, + parameters, + ); }); } diff --git a/crates/dbsp/src/trace.rs b/crates/dbsp/src/trace.rs index 8dd01de85a..c7780d73cb 100644 --- a/crates/dbsp/src/trace.rs +++ b/crates/dbsp/src/trace.rs @@ -117,7 +117,7 @@ impl DBData for T where + Debug + ArchivedDBData + IsNone - + 'static, + + 'static { } diff --git a/crates/dbsp/src/trace/spine_async.rs b/crates/dbsp/src/trace/spine_async.rs index e0548f66dc..f2a1cb8cc8 100644 --- a/crates/dbsp/src/trace/spine_async.rs +++ b/crates/dbsp/src/trace/spine_async.rs @@ -1504,9 +1504,7 @@ where let content = Runtime::storage_backend().unwrap().read(&pspine_path)?; let archived = unsafe { rkyv::archived_root::(&content) }; - let committed: CommittedSpine = archived - .deserialize(&mut Deserializer::default()) - .unwrap(); + let committed: CommittedSpine = archived.deserialize(&mut Deserializer::default()).unwrap(); self.dirty = committed.dirty; self.key_filter = None; self.value_filter = None; diff --git a/crates/dbsp/src/utils/is_none.rs b/crates/dbsp/src/utils/is_none.rs index ba3db072ba..5acc8aa559 100644 --- a/crates/dbsp/src/utils/is_none.rs +++ b/crates/dbsp/src/utils/is_none.rs @@ -149,9 +149,13 @@ impl IsNone for BTreeMap { false } - fn unwrap_or_self(&self) -> &Self::Inner { self } + fn unwrap_or_self(&self) -> &Self::Inner { + self + } - fn from_inner(inner: Self::Inner) -> Self { inner } + fn from_inner(inner: Self::Inner) -> Self { + inner + } } #[cfg(test)] diff --git a/crates/feldera-macros/Cargo.toml b/crates/feldera-macros/Cargo.toml index d6acb3a795..609ecb6785 100644 --- a/crates/feldera-macros/Cargo.toml +++ b/crates/feldera-macros/Cargo.toml @@ -21,6 +21,7 @@ prettyplease = "0.2.29" [dev-dependencies] derive_more = { version = "1.0", features = ["not"] } +proptest = { workspace = true } rkyv = { workspace = true, features = ["std", "size_64", "validation"] } serde = { workspace = true, features = ["derive"] } size-of = { workspace = true } diff --git a/crates/feldera-macros/src/lib.rs b/crates/feldera-macros/src/lib.rs index 2c716e2f39..0461482f40 100644 --- a/crates/feldera-macros/src/lib.rs +++ b/crates/feldera-macros/src/lib.rs @@ -1,3 +1,8 @@ +//! Procedural macros for Feldera tuple types and `IsNone`. +//! +//! The `declare_tuple!` macro decides which layout to use based on tuple size +//! and the active storage format rules. + use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, DeriveInput}; diff --git a/crates/feldera-macros/src/tuples.rs b/crates/feldera-macros/src/tuples.rs index 8f2f981996..eb1687ffb4 100644 --- a/crates/feldera-macros/src/tuples.rs +++ b/crates/feldera-macros/src/tuples.rs @@ -1,3 +1,13 @@ +//! Tuple code generation for Feldera storage formats. +//! +//! We support three tuple layouts: +//! - Legacy/default rkyv layout used in storage v3. +//! - Storage v4 dense layout (bitmap + inner values). +//! - Storage v4 sparse layout (bitmap + offsets to present fields). +//! +//! For small tuples we keep the legacy layout. Larger tuples use the v4 +//! optimized dense/sparse format chosen at serialize time. + use proc_macro2::{Literal, TokenStream as TokenStream2}; use quote::{format_ident, quote}; use syn::{punctuated::Punctuated, Ident, Index, Token}; @@ -24,7 +34,13 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { .map(|(idx, _e)| Index::from(idx)) .collect::>(); let num_elements = elements.len(); - let use_legacy = num_elements < 8; + // Use the default rkyv format for Tup's that are small. + // + // The v4 format adds some overhead (to distinguish sparse/dense plus bitmaps) + // which get amortized with larger tuples. For smaller tuples it seems often + // better to just use the regular format. + // (note that changing this is requires a new storage format version) + let use_legacy = num_elements <= 8; let bitmap_bytes = num_elements.div_ceil(8); let field_ptr_name = format_ident!("{}FieldPtr", name); let bitmap_ty = quote!(::dbsp::utils::tuple::TupleBitmap<#bitmap_bytes>); @@ -561,7 +577,8 @@ pub(super) fn declare_tuple_impl(tuple: TupleDef) -> TokenStream2 { #(#choose_format_fields)* let none_bits = bitmap.count_none(Self::NUM_ELEMENTS); - if none_bits * 3 > Self::NUM_ELEMENTS { + // Choose sparse format if 40% is None + if none_bits * 10 >= Self::NUM_ELEMENTS * 4 { (bitmap, #format_ty::Sparse) } else { (bitmap, #format_ty::Dense) @@ -1039,20 +1056,21 @@ mod tests { #[test] /// A simple test to verify the code of Tup<> types, for manual invocation run this: /// - /// `cargo test -p feldera-macros -- --nocapture` - fn dump_tup1_expansion() { - let tuple: TupleDef = syn::parse2(quote!(Tup1)).expect("Failed to parse TupleDef"); + /// `cargo test -p feldera-macros -- dump_tup_expansions --nocapture` + fn dump_tup_expansions() { + let tuple: TupleDef = syn::parse2(quote!(Tup2)).expect("Failed to parse TupleDef"); let expanded = declare_tuple_impl(tuple); let parsed_file: syn::File = syn::parse2(expanded).expect("Failed to parse output"); let formatted = prettyplease::unparse(&parsed_file); println!("{formatted}"); - assert!(formatted.contains("pub struct Tup1")); + assert!(formatted.contains("pub struct Tup2")); - let tuple: TupleDef = syn::parse2(quote!(Tup2)).expect("Failed to parse TupleDef"); + let tuple: TupleDef = syn::parse2(quote!(Tup8)) + .expect("Failed to parse TupleDef"); let expanded = declare_tuple_impl(tuple); let parsed_file: syn::File = syn::parse2(expanded).expect("Failed to parse output"); let formatted = prettyplease::unparse(&parsed_file); println!("{formatted}"); - assert!(formatted.contains("pub struct Tup2")); + assert!(formatted.contains("pub struct Tup8")); } } diff --git a/crates/feldera-macros/tests/compile.rs b/crates/feldera-macros/tests/compile.rs deleted file mode 100644 index b23cbdbb6c..0000000000 --- a/crates/feldera-macros/tests/compile.rs +++ /dev/null @@ -1,1639 +0,0 @@ -#![allow(unused)] - -use dbsp::utils::IsNone; -use feldera_macros::IsNone; -use rkyv::{out_field, Archived}; -use std::sync::OnceLock; - -#[derive( - Default, - Eq, - Ord, - Clone, - Hash, - PartialEq, - PartialOrd, - derive_more::Neg, - serde::Serialize, - serde::Deserialize, - size_of::SizeOf, -)] -pub struct Tup1(pub T0); -impl Tup1 { - #[allow(clippy::too_many_arguments)] - pub fn new(t0: T0) -> Self { - Self(t0) - } -} -impl Tup1 { - pub const NUM_ELEMENTS: usize = 1; - - #[inline] - pub fn get_0(&self) -> &T0 { - &self.0 - } - #[inline] - pub fn get_0_mut(&mut self) -> &mut T0 { - &mut self.0 - } -} - -type TupBitmap = ::dbsp::utils::tuple::TupleBitmap; -type TupFormat = ::dbsp::utils::tuple::TupleFormat; -impl Tup1 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - #[inline] - fn choose_format(&self) -> (TupBitmap<1>, TupFormat) { - let mut bitmap = TupBitmap::<1>::new(); - if ::dbsp::utils::IsNone::is_none(&self.0) { - bitmap.set_none(0); - } - - let none_bits = bitmap.count_none(Self::NUM_ELEMENTS); - if none_bits * 3 > Self::NUM_ELEMENTS { - (bitmap, TupFormat::Sparse) - } else { - (bitmap, TupFormat::Dense) - } - } -} -pub struct ArchivedTup1V3 -where - T0: ::rkyv::Archive, -{ - pub t0: ::rkyv::Archived, -} -impl ::rkyv::Deserialize, D> for ArchivedTup1V3 -where - D: ::rkyv::Fallible + ?Sized, - T0: ::rkyv::Archive, - ::rkyv::Archived: ::rkyv::Deserialize, -{ - #[inline] - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Tup1(self.t0.deserialize(deserializer)?)) - } -} -#[derive(Copy, Clone)] -struct Tup1FieldPtr { - pos: usize, -} -impl ::rkyv::Archive for Tup1FieldPtr { - type Archived = ::rkyv::rel_ptr::RawRelPtrI32; - type Resolver = usize; - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos, resolver, out); - } -} -impl ::rkyv::Serialize for Tup1FieldPtr -where - S: ::rkyv::ser::Serializer + ?Sized, -{ - #[inline] - fn serialize(&self, _serializer: &mut S) -> Result { - Ok(self.pos) - } -} -#[repr(C)] -pub struct ArchivedTup1Sparse -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - bitmap: TupBitmap<1>, - ptrs: ::rkyv::vec::ArchivedVec<::rkyv::rel_ptr::RawRelPtrI32>, - _phantom: core::marker::PhantomData (T0)>, -} - -#[repr(C)] -pub struct ArchivedTup1Dense -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - bitmap: TupBitmap<1>, - t0: core::mem::MaybeUninit<::rkyv::Archived<::Inner>>, - _phantom: core::marker::PhantomData (T0)>, -} - -#[repr(C)] -pub struct ArchivedTup1 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - format: TupFormat, - data: ::rkyv::rel_ptr::RawRelPtrI32, - _phantom: core::marker::PhantomData (T0)>, -} - -impl ArchivedTup1Sparse -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - #[inline] - fn none_bit_set(&self, idx: usize) -> bool { - debug_assert!(idx < Tup1::::NUM_ELEMENTS); - self.bitmap.is_none(idx) - } - - #[inline] - fn idx_for_field(&self, field_idx: usize) -> usize { - debug_assert!(field_idx < Tup1::::NUM_ELEMENTS); - field_idx - self.bitmap.count_none_before(field_idx) - } - - #[inline] - pub fn get_t0(&self) -> Option<&::rkyv::Archived<::Inner>> { - if self.none_bit_set(0) { - None - } else { - let ptr_idx = self.idx_for_field(0); - debug_assert!(ptr_idx < self.ptrs.len()); - Some(unsafe { - &*self - .ptrs - .as_slice() - .get_unchecked(ptr_idx) - .as_ptr() - .cast::<::rkyv::Archived<::Inner>>() - }) - } - } -} - -impl ArchivedTup1Dense -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - #[inline] - fn none_bit_set(&self, idx: usize) -> bool { - debug_assert!(idx < Tup1::::NUM_ELEMENTS); - self.bitmap.is_none(idx) - } - - #[inline] - pub fn get_t0(&self) -> Option<&::rkyv::Archived<::Inner>> { - if self.none_bit_set(0) { - None - } else { - Some(unsafe { &*self.t0.as_ptr() }) - } - } -} - -impl ArchivedTup1 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - #[inline] - fn sparse(&self) -> &ArchivedTup1Sparse { - unsafe { &*self.data.as_ptr().cast::>() } - } - - #[inline] - fn dense(&self) -> &ArchivedTup1Dense { - unsafe { &*self.data.as_ptr().cast::>() } - } - - #[inline] - pub fn get_t0(&self) -> Option<&::rkyv::Archived<::Inner>> { - match self.format { - TupFormat::Sparse => self.sparse().get_t0(), - TupFormat::Dense => self.dense().get_t0(), - } - } -} -impl core::cmp::PartialEq for ArchivedTup1 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived<::Inner>: core::cmp::PartialEq, -{ - #[inline] - fn eq(&self, other: &Self) -> bool { - true && self.get_t0() == other.get_t0() - } -} -impl core::cmp::Eq for ArchivedTup1 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived<::Inner>: core::cmp::Eq, -{ -} -impl core::cmp::PartialOrd for ArchivedTup1 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived<::Inner>: core::cmp::Ord, -{ - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl core::cmp::Ord for ArchivedTup1 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived<::Inner>: core::cmp::Ord, -{ - #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let cmp = self.get_t0().cmp(&other.get_t0()); - if cmp != core::cmp::Ordering::Equal { - return cmp; - } - core::cmp::Ordering::Equal - } -} -struct Tup1SparseData<'a, T0> { - bitmap: TupBitmap<1>, - value: &'a Tup1, -} - -struct Tup1SparseResolver { - bitmap: TupBitmap<1>, - ptrs_resolver: ::rkyv::vec::VecResolver, - ptrs_len: usize, -} - -impl<'a, T0> ::rkyv::Archive for Tup1SparseData<'a, T0> -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - type Archived = ArchivedTup1Sparse; - type Resolver = Tup1SparseResolver; - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let (_fp, fo) = ::rkyv::out_field!(out.bitmap); - fo.write(resolver.bitmap); - let (fp, fo) = ::rkyv::out_field!(out.ptrs); - let vec_pos = pos + fp; - ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::resolve_from_len( - resolver.ptrs_len, - vec_pos, - resolver.ptrs_resolver, - fo, - ); - let (_fp, fo) = ::rkyv::out_field!(out._phantom); - fo.write(core::marker::PhantomData); - } -} - -impl<'a, S, T0> ::rkyv::Serialize for Tup1SparseData<'a, T0> -where - S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, -{ - #[inline] - fn serialize(&self, serializer: &mut S) -> Result { - let t0_is_none = self.bitmap.is_none(0); - let mut ptrs: [Tup1FieldPtr; 1usize] = [Tup1FieldPtr { pos: 0 }; 1usize]; - let mut ptrs_len = 0usize; - if !t0_is_none { - let pos = - serializer.serialize_value(::dbsp::utils::IsNone::unwrap_or_self(&self.value.0))?; - ptrs[ptrs_len] = Tup1FieldPtr { pos }; - ptrs_len += 1; - } - let ptrs_resolver = - ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::serialize_from_slice( - &ptrs[..ptrs_len], - serializer, - )?; - Ok(Tup1SparseResolver { - bitmap: self.bitmap, - ptrs_resolver, - ptrs_len, - }) - } -} - -struct Tup1DenseData<'a, T0> { - bitmap: TupBitmap<1>, - value: &'a Tup1, -} - -struct Tup1DenseResolver -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - bitmap: TupBitmap<1>, - t0: Option<<::Inner as ::rkyv::Archive>::Resolver>, -} - -impl<'a, T0> ::rkyv::Archive for Tup1DenseData<'a, T0> -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - type Archived = ArchivedTup1Dense; - type Resolver = Tup1DenseResolver; - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let (_fp, fo) = ::rkyv::out_field!(out.bitmap); - fo.write(resolver.bitmap); - let (fp, fo) = ::rkyv::out_field!(out.t0); - let t0_out = fo - .cast::::Inner>>>( - ); - if let Some(resolver) = resolver.t0 { - let inner = ::dbsp::utils::IsNone::unwrap_or_self(&self.value.0); - <::Inner as ::rkyv::Archive>::resolve( - inner, - pos + fp, - resolver, - t0_out.cast::<::rkyv::Archived<::Inner>>(), - ); - } else { - core::ptr::write(t0_out, core::mem::MaybeUninit::zeroed()); - } - let (_fp, fo) = ::rkyv::out_field!(out._phantom); - fo.write(core::marker::PhantomData); - } -} - -impl<'a, S, T0> ::rkyv::Serialize for Tup1DenseData<'a, T0> -where - S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, -{ - #[inline] - fn serialize(&self, serializer: &mut S) -> Result { - let t0_is_none = self.bitmap.is_none(0); - let t0 = if t0_is_none { - None - } else { - Some(::rkyv::Serialize::serialize( - ::dbsp::utils::IsNone::unwrap_or_self(&self.value.0), - serializer, - )?) - }; - Ok(Tup1DenseResolver { - bitmap: self.bitmap, - t0, - }) - } -} - -pub enum Tup1Resolver { - Sparse { data_pos: usize }, - Dense { data_pos: usize }, - _Phantom(core::marker::PhantomData), -} - -impl ::rkyv::Archive for Tup1 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, -{ - type Archived = ArchivedTup1; - type Resolver = Tup1Resolver; - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let (_fp, format_out) = ::rkyv::out_field!(out.format); - let (fp, data_out) = ::rkyv::out_field!(out.data); - let data_out = data_out.cast::<::rkyv::rel_ptr::RawRelPtrI32>(); - - match resolver { - Tup1Resolver::Sparse { data_pos } => { - format_out.write(TupFormat::Sparse); - ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos + fp, data_pos, data_out); - } - Tup1Resolver::Dense { data_pos } => { - format_out.write(TupFormat::Dense); - ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos + fp, data_pos, data_out); - } - Tup1Resolver::_Phantom(_) => unreachable!(), - } - let (_fp, fo) = ::rkyv::out_field!(out._phantom); - fo.write(core::marker::PhantomData); - } -} - -impl ::rkyv::Serialize for Tup1 -where - S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, -{ - #[inline] - fn serialize(&self, serializer: &mut S) -> Result { - let (bitmap, format) = self.choose_format(); - match format { - TupFormat::Dense => { - let data = Tup1DenseData { - bitmap, - value: self, - }; - let data_pos = serializer.serialize_value(&data)?; - Ok(Tup1Resolver::Dense { data_pos }) - } - TupFormat::Sparse => { - let data = Tup1SparseData { - bitmap, - value: self, - }; - let data_pos = serializer.serialize_value(&data)?; - Ok(Tup1Resolver::Sparse { data_pos }) - } - } - } -} -impl ::rkyv::Deserialize, D> for ArchivedTup1 -where - D: ::rkyv::Fallible + ::core::any::Any, - T0: ::rkyv::Archive + Default + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived: ::rkyv::Deserialize, - ::rkyv::Archived<::Inner>: - ::rkyv::Deserialize<::Inner, D>, -{ - #[inline] - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - let version = (deserializer as &mut dyn ::core::any::Any) - .downcast_mut::<::dbsp::storage::file::Deserializer>() - .map(|deserializer| deserializer.version()) - .expect("passed wrong deserializer"); - if version <= 3 { - let legacy = unsafe { &*(self as *const _ as *const ArchivedTup1V3) }; - return as ::rkyv::Deserialize, D>>::deserialize( - legacy, - deserializer, - ); - } - match self.format { - TupFormat::Sparse => { - let sparse = self.sparse(); - let mut ptr_idx = 0usize; - let t0 = if sparse.none_bit_set(0) { - T0::default() - } else { - let archived: &::rkyv::Archived<::Inner> = unsafe { - &*sparse - .ptrs - .as_slice() - .get_unchecked(ptr_idx) - .as_ptr() - .cast::<::rkyv::Archived<::Inner>>() - }; - ptr_idx += 1; - let inner = archived.deserialize(deserializer)?; - ::from_inner(inner) - }; - Ok(Tup1(t0)) - } - TupFormat::Dense => { - let dense = self.dense(); - let t0 = if dense.none_bit_set(0) { - T0::default() - } else { - let archived = dense.get_t0().expect("ArchivedTup1Dense: missing field 0"); - let inner = archived.deserialize(deserializer)?; - ::from_inner(inner) - }; - Ok(Tup1(t0)) - } - } - } -} -impl ::dbsp::algebra::MulByRef for Tup1 -where - T0: ::dbsp::algebra::MulByRef, - W: ::dbsp::algebra::ZRingValue, -{ - type Output = Self; - fn mul_by_ref(&self, other: &W) -> Self::Output { - let Tup1(t0) = self; - Tup1(t0.mul_by_ref(other)) - } -} -impl ::dbsp::algebra::HasZero for Tup1 -where - T0: ::dbsp::algebra::HasZero, -{ - fn zero() -> Self { - Tup1(T0::zero()) - } - fn is_zero(&self) -> bool { - let mut result = true; - let Tup1(t0) = self; - result = result && t0.is_zero(); - result - } -} -impl ::dbsp::algebra::AddByRef for Tup1 -where - T0: ::dbsp::algebra::AddByRef, -{ - fn add_by_ref(&self, other: &Self) -> Self { - let Tup1(t0) = self; - let Tup1(other_t0) = other; - Tup1(t0.add_by_ref(other_t0)) - } -} -impl ::dbsp::algebra::AddAssignByRef for Tup1 -where - T0: ::dbsp::algebra::AddAssignByRef, -{ - fn add_assign_by_ref(&mut self, other: &Self) { - let Tup1(ref mut t0) = self; - let Tup1(ref other_t0) = other; - t0.add_assign_by_ref(other_t0); - } -} -impl ::dbsp::algebra::NegByRef for Tup1 -where - T0: ::dbsp::algebra::NegByRef, -{ - fn neg_by_ref(&self) -> Self { - let Tup1(t0) = self; - Tup1(t0.neg_by_ref()) - } -} -impl From<(T0)> for Tup1 { - fn from((t0): (T0)) -> Self { - Self(t0) - } -} -impl<'a, T0> Into<(&'a T0,)> for &'a Tup1 { - #[allow(clippy::from_over_into)] - fn into(self) -> (&'a T0,) { - let Tup1(t0) = &self; - (t0,) - } -} -impl Into<(T0,)> for Tup1 { - #[allow(clippy::from_over_into)] - fn into(self) -> (T0,) { - let Tup1(t0) = self; - (t0,) - } -} -impl ::dbsp::NumEntries for Tup1 -where - T0: ::dbsp::NumEntries, -{ - const CONST_NUM_ENTRIES: Option = None; - fn num_entries_shallow(&self) -> usize { - Self::NUM_ELEMENTS - } - fn num_entries_deep(&self) -> usize { - let Tup1(t0) = self; - 0 + (t0).num_entries_deep() - } -} -impl core::fmt::Debug for Tup1 { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { - let Tup1(t0) = self; - f.debug_tuple("").field(&t0).finish() - } -} -impl Copy for Tup1 {} -impl ::dbsp::circuit::checkpointer::Checkpoint for Tup1 -where - Tup1: ::rkyv::Serialize<::dbsp::storage::file::Serializer> - + ::dbsp::storage::file::Deserializable, -{ - fn checkpoint(&self) -> Result, ::dbsp::Error> { - let mut s = ::dbsp::storage::file::Serializer::default(); - let _offset = ::rkyv::ser::Serializer::serialize_value(&mut s, self).unwrap(); - let data = s.into_serializer().into_inner().into_vec(); - Ok(data) - } - fn restore(&mut self, data: &[u8]) -> Result<(), ::dbsp::Error> { - *self = ::dbsp::trace::unaligned_deserialize(data); - Ok(()) - } -} -impl ::dbsp::utils::IsNone for Tup1 { - type Inner = Self; - fn is_none(&self) -> bool { - false - } - fn unwrap_or_self(&self) -> &Self::Inner { - self - } - fn from_inner(inner: Self::Inner) -> Self { - inner - } -} - -#[derive( - Default, - Eq, - Ord, - Clone, - Hash, - PartialEq, - PartialOrd, - derive_more::Neg, - serde::Serialize, - serde::Deserialize, - size_of::SizeOf, -)] -pub struct Tup2(pub T0, pub T1); -impl Tup2 { - #[allow(clippy::too_many_arguments)] - pub fn new(t0: T0, t1: T1) -> Self { - Self(t0, t1) - } -} -impl Tup2 { - pub const NUM_ELEMENTS: usize = 2; - - #[inline] - pub fn get_0(&self) -> &T0 { - &self.0 - } - #[inline] - pub fn get_0_mut(&mut self) -> &mut T0 { - &mut self.0 - } -} -impl Tup2 { - #[inline] - pub fn get_1(&self) -> &T1 { - &self.1 - } - #[inline] - pub fn get_1_mut(&mut self) -> &mut T1 { - &mut self.1 - } -} -impl Tup2 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - #[inline] - fn choose_format(&self) -> (TupBitmap<1>, TupFormat) { - let mut bitmap = TupBitmap::<1>::new(); - if ::dbsp::utils::IsNone::is_none(&self.0) { - bitmap.set_none(0); - } - if ::dbsp::utils::IsNone::is_none(&self.1) { - bitmap.set_none(1); - } - - let none_bits = bitmap.count_none(Self::NUM_ELEMENTS); - if none_bits * 3 > Self::NUM_ELEMENTS { - eprintln!("choosing TupFormat::Sparse..."); - (bitmap, TupFormat::Sparse) - } else { - eprintln!("choosing TupFormat::Dense"); - (bitmap, TupFormat::Dense) - } - } -} -pub struct ArchivedTup2V3 -where - T0: ::rkyv::Archive, - T1: ::rkyv::Archive, -{ - pub t0: ::rkyv::Archived, - pub t1: ::rkyv::Archived, -} -impl ::rkyv::Deserialize, D> for ArchivedTup2V3 -where - D: ::rkyv::Fallible + ?Sized, - T0: ::rkyv::Archive, - T1: ::rkyv::Archive, - ::rkyv::Archived: ::rkyv::Deserialize, - ::rkyv::Archived: ::rkyv::Deserialize, -{ - #[inline] - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Tup2( - self.t0.deserialize(deserializer)?, - self.t1.deserialize(deserializer)?, - )) - } -} -#[derive(Copy, Clone)] -struct Tup2FieldPtr { - pos: usize, -} -impl ::rkyv::Archive for Tup2FieldPtr { - type Archived = ::rkyv::rel_ptr::RawRelPtrI32; - type Resolver = usize; - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos, resolver, out); - } -} -impl ::rkyv::Serialize for Tup2FieldPtr -where - S: ::rkyv::ser::Serializer + ?Sized, -{ - #[inline] - fn serialize(&self, _serializer: &mut S) -> Result { - Ok(self.pos) - } -} -#[repr(C)] -pub struct ArchivedTup2Sparse -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - bitmap: TupBitmap<1>, - ptrs: ::rkyv::vec::ArchivedVec<::rkyv::rel_ptr::RawRelPtrI32>, - _phantom: core::marker::PhantomData (T0, T1)>, -} - -#[repr(C)] -pub struct ArchivedTup2Dense -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - bitmap: TupBitmap<1>, - t0: core::mem::MaybeUninit<::rkyv::Archived<::Inner>>, - t1: core::mem::MaybeUninit<::rkyv::Archived<::Inner>>, - _phantom: core::marker::PhantomData (T0, T1)>, -} - -#[repr(C)] -pub struct ArchivedTup2 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - format: TupFormat, - data: ::rkyv::rel_ptr::RawRelPtrI32, - _phantom: core::marker::PhantomData (T0, T1)>, -} - -impl ArchivedTup2Sparse -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - #[inline] - fn none_bit_set(&self, idx: usize) -> bool { - debug_assert!(idx < Tup2::::NUM_ELEMENTS); - self.bitmap.is_none(idx) - } - - #[inline] - fn idx_for_field(&self, field_idx: usize) -> usize { - debug_assert!(field_idx < Tup2::::NUM_ELEMENTS); - field_idx - self.bitmap.count_none_before(field_idx) - } - - #[inline] - pub fn get_t0(&self) -> Option<&::rkyv::Archived<::Inner>> { - if self.none_bit_set(0) { - None - } else { - let ptr_idx = self.idx_for_field(0); - debug_assert!(ptr_idx < self.ptrs.len()); - Some(unsafe { - &*self - .ptrs - .as_slice() - .get_unchecked(ptr_idx) - .as_ptr() - .cast::<::rkyv::Archived<::Inner>>() - }) - } - } - - #[inline] - pub fn get_t1(&self) -> Option<&::rkyv::Archived<::Inner>> { - if self.none_bit_set(1) { - None - } else { - let ptr_idx = self.idx_for_field(1); - debug_assert!(ptr_idx < self.ptrs.len()); - Some(unsafe { - &*self - .ptrs - .as_slice() - .get_unchecked(ptr_idx) - .as_ptr() - .cast::<::rkyv::Archived<::Inner>>() - }) - } - } -} - -impl ArchivedTup2Dense -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - #[inline] - fn none_bit_set(&self, idx: usize) -> bool { - debug_assert!(idx < Tup2::::NUM_ELEMENTS); - self.bitmap.is_none(idx) - } - - #[inline] - pub fn get_t0(&self) -> Option<&::rkyv::Archived<::Inner>> { - if self.none_bit_set(0) { - None - } else { - Some(unsafe { &*self.t0.as_ptr() }) - } - } - - #[inline] - pub fn get_t1(&self) -> Option<&::rkyv::Archived<::Inner>> { - if self.none_bit_set(1) { - None - } else { - Some(unsafe { &*self.t1.as_ptr() }) - } - } -} - -impl ArchivedTup2 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - #[inline] - fn sparse(&self) -> &ArchivedTup2Sparse { - unsafe { &*self.data.as_ptr().cast::>() } - } - - #[inline] - fn dense(&self) -> &ArchivedTup2Dense { - unsafe { &*self.data.as_ptr().cast::>() } - } - - #[inline] - pub fn get_t0(&self) -> Option<&::rkyv::Archived<::Inner>> { - match self.format { - TupFormat::Sparse => self.sparse().get_t0(), - TupFormat::Dense => self.dense().get_t0(), - } - } - - #[inline] - pub fn get_t1(&self) -> Option<&::rkyv::Archived<::Inner>> { - match self.format { - TupFormat::Sparse => self.sparse().get_t1(), - TupFormat::Dense => self.dense().get_t1(), - } - } -} -impl core::cmp::PartialEq for ArchivedTup2 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived<::Inner>: core::cmp::PartialEq, - ::rkyv::Archived<::Inner>: core::cmp::PartialEq, -{ - #[inline] - fn eq(&self, other: &Self) -> bool { - true && self.get_t0() == other.get_t0() && self.get_t1() == other.get_t1() - } -} -impl core::cmp::Eq for ArchivedTup2 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived<::Inner>: core::cmp::Eq, - ::rkyv::Archived<::Inner>: core::cmp::Eq, -{ -} -impl core::cmp::PartialOrd for ArchivedTup2 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived<::Inner>: core::cmp::Ord, - ::rkyv::Archived<::Inner>: core::cmp::Ord, -{ - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl core::cmp::Ord for ArchivedTup2 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived<::Inner>: core::cmp::Ord, - ::rkyv::Archived<::Inner>: core::cmp::Ord, -{ - #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let cmp = self.get_t0().cmp(&other.get_t0()); - if cmp != core::cmp::Ordering::Equal { - return cmp; - } - let cmp = self.get_t1().cmp(&other.get_t1()); - if cmp != core::cmp::Ordering::Equal { - return cmp; - } - core::cmp::Ordering::Equal - } -} -struct Tup2SparseData<'a, T0, T1> { - bitmap: TupBitmap<1>, - value: &'a Tup2, -} - -struct Tup2SparseResolver { - bitmap: TupBitmap<1>, - ptrs_resolver: ::rkyv::vec::VecResolver, - ptrs_len: usize, -} - -impl<'a, T0, T1> ::rkyv::Archive for Tup2SparseData<'a, T0, T1> -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - type Archived = ArchivedTup2Sparse; - type Resolver = Tup2SparseResolver; - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let (_fp, fo) = ::rkyv::out_field!(out.bitmap); - fo.write(resolver.bitmap); - let (fp, fo) = ::rkyv::out_field!(out.ptrs); - let vec_pos = pos + fp; - ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::resolve_from_len( - resolver.ptrs_len, - vec_pos, - resolver.ptrs_resolver, - fo, - ); - let (_fp, fo) = ::rkyv::out_field!(out._phantom); - fo.write(core::marker::PhantomData); - } -} - -impl<'a, S, T0, T1> ::rkyv::Serialize for Tup2SparseData<'a, T0, T1> -where - S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, -{ - #[inline] - fn serialize(&self, serializer: &mut S) -> Result { - let t0_is_none = self.bitmap.is_none(0); - let t1_is_none = self.bitmap.is_none(1); - let mut ptrs: [Tup2FieldPtr; 2usize] = [Tup2FieldPtr { pos: 0 }; 2usize]; - let mut ptrs_len = 0usize; - if !t0_is_none { - let pos = - serializer.serialize_value(::dbsp::utils::IsNone::unwrap_or_self(&self.value.0))?; - ptrs[ptrs_len] = Tup2FieldPtr { pos }; - ptrs_len += 1; - } - if !t1_is_none { - let pos = - serializer.serialize_value(::dbsp::utils::IsNone::unwrap_or_self(&self.value.1))?; - ptrs[ptrs_len] = Tup2FieldPtr { pos }; - ptrs_len += 1; - } - let ptrs_resolver = - ::rkyv::vec::ArchivedVec::<::rkyv::rel_ptr::RawRelPtrI32>::serialize_from_slice( - &ptrs[..ptrs_len], - serializer, - )?; - Ok(Tup2SparseResolver { - bitmap: self.bitmap, - ptrs_resolver, - ptrs_len, - }) - } -} - -struct Tup2DenseData<'a, T0, T1> { - bitmap: TupBitmap<1>, - value: &'a Tup2, -} - -struct Tup2DenseResolver -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - bitmap: TupBitmap<1>, - t0: Option<<::Inner as ::rkyv::Archive>::Resolver>, - t1: Option<<::Inner as ::rkyv::Archive>::Resolver>, -} - -impl<'a, T0, T1> ::rkyv::Archive for Tup2DenseData<'a, T0, T1> -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - type Archived = ArchivedTup2Dense; - type Resolver = Tup2DenseResolver; - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let (_fp, fo) = ::rkyv::out_field!(out.bitmap); - fo.write(resolver.bitmap); - let (fp, fo) = ::rkyv::out_field!(out.t0); - let t0_out = fo - .cast::::Inner>>>( - ); - if let Some(resolver) = resolver.t0 { - let inner = ::dbsp::utils::IsNone::unwrap_or_self(&self.value.0); - <::Inner as ::rkyv::Archive>::resolve( - inner, - pos + fp, - resolver, - t0_out.cast::<::rkyv::Archived<::Inner>>(), - ); - } else { - core::ptr::write(t0_out, core::mem::MaybeUninit::zeroed()); - } - let (fp, fo) = ::rkyv::out_field!(out.t1); - let t1_out = fo - .cast::::Inner>>>( - ); - if let Some(resolver) = resolver.t1 { - let inner = ::dbsp::utils::IsNone::unwrap_or_self(&self.value.1); - <::Inner as ::rkyv::Archive>::resolve( - inner, - pos + fp, - resolver, - t1_out.cast::<::rkyv::Archived<::Inner>>(), - ); - } else { - core::ptr::write(t1_out, core::mem::MaybeUninit::zeroed()); - } - let (_fp, fo) = ::rkyv::out_field!(out._phantom); - fo.write(core::marker::PhantomData); - } -} - -impl<'a, S, T0, T1> ::rkyv::Serialize for Tup2DenseData<'a, T0, T1> -where - S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, -{ - #[inline] - fn serialize(&self, serializer: &mut S) -> Result { - let t0_is_none = self.bitmap.is_none(0); - let t1_is_none = self.bitmap.is_none(1); - let t0 = if t0_is_none { - None - } else { - Some(::rkyv::Serialize::serialize( - ::dbsp::utils::IsNone::unwrap_or_self(&self.value.0), - serializer, - )?) - }; - let t1 = if t1_is_none { - None - } else { - Some(::rkyv::Serialize::serialize( - ::dbsp::utils::IsNone::unwrap_or_self(&self.value.1), - serializer, - )?) - }; - Ok(Tup2DenseResolver { - bitmap: self.bitmap, - t0, - t1, - }) - } -} - -pub enum Tup2Resolver { - Sparse { data_pos: usize }, - Dense { data_pos: usize }, - _Phantom(core::marker::PhantomData<(T0, T1)>), -} - -impl ::rkyv::Archive for Tup2 -where - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, -{ - type Archived = ArchivedTup2; - type Resolver = Tup2Resolver; - #[inline] - unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let (_fp, format_out) = ::rkyv::out_field!(out.format); - let (fp, data_out) = ::rkyv::out_field!(out.data); - let data_out = data_out.cast::<::rkyv::rel_ptr::RawRelPtrI32>(); - - match resolver { - Tup2Resolver::Sparse { data_pos } => { - format_out.write(TupFormat::Sparse); - ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos + fp, data_pos, data_out); - } - Tup2Resolver::Dense { data_pos } => { - format_out.write(TupFormat::Dense); - ::rkyv::rel_ptr::RawRelPtrI32::emplace(pos + fp, data_pos, data_out); - } - Tup2Resolver::_Phantom(_) => unreachable!(), - } - let (_fp, fo) = ::rkyv::out_field!(out._phantom); - fo.write(core::marker::PhantomData); - } -} - -impl ::rkyv::Serialize for Tup2 -where - S: ::rkyv::ser::Serializer + ::rkyv::ser::ScratchSpace + ?Sized, - T0: ::rkyv::Archive + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, - ::Inner: ::rkyv::Archive + ::rkyv::Serialize, -{ - #[inline] - fn serialize(&self, serializer: &mut S) -> Result { - let (bitmap, format) = self.choose_format(); - match format { - TupFormat::Dense => { - let data = Tup2DenseData { - bitmap, - value: self, - }; - let data_pos = serializer.serialize_value(&data)?; - Ok(Tup2Resolver::Dense { data_pos }) - } - TupFormat::Sparse => { - let data = Tup2SparseData { - bitmap, - value: self, - }; - let data_pos = serializer.serialize_value(&data)?; - Ok(Tup2Resolver::Sparse { data_pos }) - } - } - } -} -impl ::rkyv::Deserialize, D> for ArchivedTup2 -where - D: ::rkyv::Fallible + ::core::any::Any, - T0: ::rkyv::Archive + Default + ::dbsp::utils::IsNone, - T1: ::rkyv::Archive + Default + ::dbsp::utils::IsNone, - ::Inner: ::rkyv::Archive, - ::Inner: ::rkyv::Archive, - ::rkyv::Archived: ::rkyv::Deserialize, - ::rkyv::Archived: ::rkyv::Deserialize, - ::rkyv::Archived<::Inner>: - ::rkyv::Deserialize<::Inner, D>, - ::rkyv::Archived<::Inner>: - ::rkyv::Deserialize<::Inner, D>, -{ - #[inline] - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - let version = (deserializer as &mut dyn ::core::any::Any) - .downcast_mut::<::dbsp::storage::file::Deserializer>() - .map(|deserializer| deserializer.version()) - .expect("passed wrong deserializer"); - if version <= 3 { - let legacy = unsafe { &*(self as *const _ as *const ArchivedTup2V3) }; - return as ::rkyv::Deserialize, D>>::deserialize( - legacy, - deserializer, - ); - } - match self.format { - TupFormat::Sparse => { - let sparse = self.sparse(); - let mut ptr_idx = 0usize; - let t0 = if sparse.none_bit_set(0) { - T0::default() - } else { - let archived: &::rkyv::Archived<::Inner> = unsafe { - &*sparse - .ptrs - .as_slice() - .get_unchecked(ptr_idx) - .as_ptr() - .cast::<::rkyv::Archived<::Inner>>() - }; - ptr_idx += 1; - let inner = archived.deserialize(deserializer)?; - ::from_inner(inner) - }; - let t1 = if sparse.none_bit_set(1) { - T1::default() - } else { - let archived: &::rkyv::Archived<::Inner> = unsafe { - &*sparse - .ptrs - .as_slice() - .get_unchecked(ptr_idx) - .as_ptr() - .cast::<::rkyv::Archived<::Inner>>() - }; - ptr_idx += 1; - let inner = archived.deserialize(deserializer)?; - ::from_inner(inner) - }; - Ok(Tup2(t0, t1)) - } - TupFormat::Dense => { - let dense = self.dense(); - let t0 = if dense.none_bit_set(0) { - T0::default() - } else { - let archived = dense.get_t0().expect("ArchivedTup2Dense: missing field 0"); - let inner = archived.deserialize(deserializer)?; - ::from_inner(inner) - }; - let t1 = if dense.none_bit_set(1) { - T1::default() - } else { - let archived = dense.get_t1().expect("ArchivedTup2Dense: missing field 1"); - let inner = archived.deserialize(deserializer)?; - ::from_inner(inner) - }; - Ok(Tup2(t0, t1)) - } - } - } -} -impl ::dbsp::algebra::MulByRef for Tup2 -where - T0: ::dbsp::algebra::MulByRef, - T1: ::dbsp::algebra::MulByRef, - W: ::dbsp::algebra::ZRingValue, -{ - type Output = Self; - fn mul_by_ref(&self, other: &W) -> Self::Output { - let Tup2(t0, t1) = self; - Tup2(t0.mul_by_ref(other), t1.mul_by_ref(other)) - } -} -impl ::dbsp::algebra::HasZero for Tup2 -where - T0: ::dbsp::algebra::HasZero, - T1: ::dbsp::algebra::HasZero, -{ - fn zero() -> Self { - Tup2(T0::zero(), T1::zero()) - } - fn is_zero(&self) -> bool { - let mut result = true; - let Tup2(t0, t1) = self; - result = result && t0.is_zero(); - result = result && t1.is_zero(); - result - } -} -impl ::dbsp::algebra::AddByRef for Tup2 -where - T0: ::dbsp::algebra::AddByRef, - T1: ::dbsp::algebra::AddByRef, -{ - fn add_by_ref(&self, other: &Self) -> Self { - let Tup2(t0, t1) = self; - let Tup2(other_t0, other_t1) = other; - Tup2(t0.add_by_ref(other_t0), t1.add_by_ref(other_t1)) - } -} -impl ::dbsp::algebra::AddAssignByRef for Tup2 -where - T0: ::dbsp::algebra::AddAssignByRef, - T1: ::dbsp::algebra::AddAssignByRef, -{ - fn add_assign_by_ref(&mut self, other: &Self) { - let Tup2(ref mut t0, ref mut t1) = self; - let Tup2(ref other_t0, ref other_t1) = other; - t0.add_assign_by_ref(other_t0); - t1.add_assign_by_ref(other_t1); - } -} -impl ::dbsp::algebra::NegByRef for Tup2 -where - T0: ::dbsp::algebra::NegByRef, - T1: ::dbsp::algebra::NegByRef, -{ - fn neg_by_ref(&self) -> Self { - let Tup2(t0, t1) = self; - Tup2(t0.neg_by_ref(), t1.neg_by_ref()) - } -} -impl From<(T0, T1)> for Tup2 { - fn from((t0, t1): (T0, T1)) -> Self { - Self(t0, t1) - } -} -impl<'a, T0, T1> Into<(&'a T0, &'a T1)> for &'a Tup2 { - #[allow(clippy::from_over_into)] - fn into(self) -> (&'a T0, &'a T1) { - let Tup2(t0, t1) = &self; - (t0, t1) - } -} -impl Into<(T0, T1)> for Tup2 { - #[allow(clippy::from_over_into)] - fn into(self) -> (T0, T1) { - let Tup2(t0, t1) = self; - (t0, t1) - } -} -impl ::dbsp::NumEntries for Tup2 -where - T0: ::dbsp::NumEntries, - T1: ::dbsp::NumEntries, -{ - const CONST_NUM_ENTRIES: Option = None; - fn num_entries_shallow(&self) -> usize { - Self::NUM_ELEMENTS - } - fn num_entries_deep(&self) -> usize { - let Tup2(t0, t1) = self; - 0 + (t0).num_entries_deep() + (t1).num_entries_deep() - } -} -impl core::fmt::Debug for Tup2 { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> { - let Tup2(t0, t1) = self; - f.debug_tuple("").field(&t0).field(&t1).finish() - } -} -impl Copy for Tup2 {} -impl ::dbsp::circuit::checkpointer::Checkpoint for Tup2 -where - Tup2: ::rkyv::Serialize<::dbsp::storage::file::Serializer> - + ::dbsp::storage::file::Deserializable, -{ - fn checkpoint(&self) -> Result, ::dbsp::Error> { - let mut s = ::dbsp::storage::file::Serializer::default(); - let _offset = ::rkyv::ser::Serializer::serialize_value(&mut s, self).unwrap(); - let data = s.into_serializer().into_inner().into_vec(); - Ok(data) - } - fn restore(&mut self, data: &[u8]) -> Result<(), ::dbsp::Error> { - *self = ::dbsp::trace::unaligned_deserialize(data); - Ok(()) - } -} -impl ::dbsp::utils::IsNone for Tup2 { - type Inner = Self; - fn is_none(&self) -> bool { - false - } - fn unwrap_or_self(&self) -> &Self::Inner { - self - } - fn from_inner(inner: Self::Inner) -> Self { - inner - } -} - -#[test] -fn compile_tup1() { - let t1 = Tup1::new(Some(32i32)); -} - -#[test] -fn compile_tup2() { - let t2 = Tup2::new(Some(32i32), Some(64i32)); -} - -#[test] -fn rkyv_compact_tup1_option_roundtrip_bool() { - let tup_some = Tup1::new(Some(true)); - let bytes_some = dbsp::storage::file::to_bytes(&tup_some).unwrap(); - let restored_some: Tup1> = dbsp::trace::unaligned_deserialize(&bytes_some[..]); - assert_eq!(restored_some, tup_some); - - let tup_none: Tup1> = Tup1::new(None); - let bytes_none = dbsp::storage::file::to_bytes(&tup_none).unwrap(); - let restored_none: Tup1> = dbsp::trace::unaligned_deserialize(&bytes_none[..]); - assert_eq!(restored_none, tup_none); - assert!( - bytes_none.len() >= core::mem::size_of::>>(), - "expected serialized bytes to include archived data, got bytes={} archived={}", - bytes_none.len(), - core::mem::size_of::>>() - ); - - eprintln!( - "Tup1>: None={} Some={}", - bytes_none.len(), - bytes_some.len() - ); - - let _ = (bytes_none, bytes_some); -} - -#[test] -fn rkyv_compact_tup1_option_roundtrip() { - use feldera_sqllib::SqlString; - - let tup_some = Tup1::new(()); - let bytes_some = dbsp::storage::file::to_bytes(&tup_some).unwrap(); - let restored_some: Tup1<()> = dbsp::trace::unaligned_deserialize(&bytes_some[..]); - assert_eq!(restored_some, tup_some); - - eprintln!("Tup1<()>: {}", bytes_some.len()); - - let tup_some = Tup1::new(0u8); - let bytes_some = dbsp::storage::file::to_bytes(&tup_some).unwrap(); - let restored_some: Tup1 = dbsp::trace::unaligned_deserialize(&bytes_some[..]); - assert_eq!(restored_some, tup_some); - - eprintln!("Tup1: {}", bytes_some.len()); - - let tup_some = Tup1::new(Some(0u8)); - let bytes_some = dbsp::storage::file::to_bytes(&tup_some).unwrap(); - let restored_some: Tup1> = dbsp::trace::unaligned_deserialize(&bytes_some[..]); - assert_eq!(restored_some, tup_some); - - eprintln!("Tup1>: {}", bytes_some.len()); -} - -#[test] -fn rkyv_compact_tup2_option_sizes() { - use feldera_sqllib::SqlString; - - let tup_some = Tup2::new( - Some(SqlString::from_ref("hello")), - Some(SqlString::from_ref("hello")), - ); - let bytes_some = dbsp::storage::file::to_bytes(&tup_some).unwrap(); - let restored_some: Tup2, Option> = - dbsp::trace::unaligned_deserialize(&bytes_some[..]); - assert_eq!(restored_some, tup_some); - - let tup_none: Tup2, Option> = Tup2::new(None, None); - let bytes_none = dbsp::storage::file::to_bytes(&tup_none).unwrap(); - let restored_none: Tup2, Option> = - dbsp::trace::unaligned_deserialize(&bytes_none[..]); - assert_eq!(restored_none, tup_none); - - eprintln!( - "Tup2, Option>: None={} Some={}", - bytes_none.len(), - bytes_some.len() - ); -} - -#[test] -fn rkyv_compact_tup1_archived_get_t0() { - use feldera_sqllib::SqlString; - - let tup_none: Tup1> = Tup1::new(None); - let bytes_none = dbsp::storage::file::to_bytes(&tup_none).unwrap(); - let archived_none = unsafe { rkyv::archived_root::>>(&bytes_none[..]) }; - let archived_t0_none = archived_none.get_t0(); - assert!(archived_t0_none.is_none()); - - let tup_some = Tup1::new(Some(SqlString::from_ref("hello"))); - let bytes_some = dbsp::storage::file::to_bytes(&tup_some).unwrap(); - let archived_some = unsafe { rkyv::archived_root::>>(&bytes_some[..]) }; - let archived_t0_some = archived_some.get_t0(); - assert!(archived_t0_some.is_some()); - assert_eq!(archived_t0_some.unwrap().as_str(), "hello"); -} - -#[test] -fn rkyv_compact_tup1_option_checkpoint_roundtrip() { - use dbsp::circuit::checkpointer::Checkpoint; - use feldera_sqllib::SqlString; - - let tup_some = Tup1::new(Some(SqlString::from_ref("hello"))); - let bytes_some = tup_some.checkpoint().unwrap(); - let mut restored_some: Tup1> = Tup1::new(None); - restored_some.restore(&bytes_some).unwrap(); - assert_eq!(restored_some, tup_some); - - let tup_none: Tup1> = Tup1::new(None); - let bytes_none = tup_none.checkpoint().unwrap(); - let mut restored_none: Tup1> = Tup1::new(Some(SqlString::from_ref("x"))); - restored_none.restore(&bytes_none).unwrap(); - assert_eq!(restored_none, tup_none); - - assert!( - bytes_none.len() >= core::mem::size_of::>>(), - "expected serialized bytes to include archived data, got bytes={} archived={}", - bytes_none.len(), - core::mem::size_of::>>() - ); -} - -#[test] -fn rkyv_compact_tup2_roundtrip() { - use feldera_sqllib::SqlString; - - let tup_vals: Tup2 = Tup2::new(SqlString::from_ref("hi"), 8i32); - let bytes_vals = dbsp::storage::file::to_bytes(&tup_vals).unwrap(); - let restored_vals: Tup2 = dbsp::trace::unaligned_deserialize(&bytes_vals[..]); - assert_eq!(restored_vals, tup_vals); - assert!( - bytes_vals.len() >= core::mem::size_of::>(), - "expected serialized bytes to include archived data, got bytes={} archived={}", - bytes_vals.len(), - core::mem::size_of::>() - ); -} - -#[test] -fn rkyv_compact_tup2_option_roundtrip() { - use feldera_sqllib::SqlString; - - let tup_none: Tup2, Option> = Tup2::new(None, None); - let bytes_none = dbsp::storage::file::to_bytes(&tup_none).unwrap(); - let restored_none: Tup2, Option> = - dbsp::trace::unaligned_deserialize(&bytes_none[..]); - assert_eq!(restored_none, tup_none); - eprintln!("bytes_none.len() = {}", bytes_none.len()); - assert!( - bytes_none.len() >= core::mem::size_of::, Option>>(), - "expected serialized bytes to include archived data, got bytes={} archived={}", - bytes_none.len(), - core::mem::size_of::, Option>>() - ); - - let tup_10: Tup2, Option> = - Tup2::new(Some(SqlString::from_ref("hi")), None); - let bytes_10 = dbsp::storage::file::to_bytes(&tup_10).unwrap(); - let restored_10: Tup2, Option> = - dbsp::trace::unaligned_deserialize(&bytes_10[..]); - assert_eq!(restored_10, tup_10); - - let tup_01: Tup2, Option> = Tup2::new(None, Some(42)); - let bytes_01 = dbsp::storage::file::to_bytes(&tup_01).unwrap(); - let restored_01: Tup2, Option> = - dbsp::trace::unaligned_deserialize(&bytes_01[..]); - assert_eq!(restored_01, tup_01); - - let tup_11: Tup2, Option> = - Tup2::new(Some(SqlString::from_ref("hello")), Some(42)); - let bytes_11 = dbsp::storage::file::to_bytes(&tup_11).unwrap(); - let restored_11: Tup2, Option> = - dbsp::trace::unaligned_deserialize(&bytes_11[..]); - assert_eq!(restored_11, tup_11); -} - -#[test] -fn rkyv_compact_tup2_archived_get_t0_t1() { - use feldera_sqllib::SqlString; - - let tup_10: Tup2, Option> = - Tup2::new(Some(SqlString::from_ref("hi")), None); - let bytes_10 = dbsp::storage::file::to_bytes(&tup_10).unwrap(); - let archived_10 = - unsafe { rkyv::archived_root::, Option>>(&bytes_10[..]) }; - let t0_10 = archived_10.get_t0(); - let t1_10 = archived_10.get_t1(); - assert!(t0_10.is_some()); - assert!(t1_10.is_none()); - assert_eq!(t0_10.unwrap().as_str(), "hi"); - - let tup_01: Tup2, Option> = Tup2::new(None, Some(42)); - let bytes_01 = dbsp::storage::file::to_bytes(&tup_01).unwrap(); - let archived_01 = - unsafe { rkyv::archived_root::, Option>>(&bytes_01[..]) }; - let t0_01 = archived_01.get_t0(); - let t1_01 = archived_01.get_t1(); - assert!(t0_01.is_none()); - assert!(t1_01.is_some()); - assert_eq!(*t1_01.unwrap(), 42); -} diff --git a/crates/feldera-macros/tests/declare_tuple_rkyv.rs b/crates/feldera-macros/tests/declare_tuple_rkyv.rs deleted file mode 100644 index ba8ec3288b..0000000000 --- a/crates/feldera-macros/tests/declare_tuple_rkyv.rs +++ /dev/null @@ -1,106 +0,0 @@ -use feldera_sqllib::SqlString; - -feldera_macros::declare_tuple! { Tup1 } -feldera_macros::declare_tuple! { Tup2 } -feldera_macros::declare_tuple! { Tup12 } - -type OptStr = Option; -type Tup12Opt = Tup12< - OptStr, - OptStr, - OptStr, - OptStr, - OptStr, - OptStr, - OptStr, - OptStr, - OptStr, - OptStr, - OptStr, - OptStr, ->; - -#[test] -fn rkyv_roundtrip_with_option_sqlstring() { - let tup1_some = Tup1::new(Some(SqlString::from_ref("hello"))); - assert_eq!(tup1_some.get_0().as_ref().cloned().unwrap().str(), "hello"); - - let bytes1_some = dbsp::storage::file::to_bytes(&tup1_some).unwrap(); - let restored1_some: Tup1> = - dbsp::trace::unaligned_deserialize(&bytes1_some[..]); - assert_eq!(restored1_some, tup1_some); - - let tup1_none: Tup1> = Tup1::new(None); - let bytes1_none = dbsp::storage::file::to_bytes(&tup1_none).unwrap(); - let restored1_none: Tup1> = - dbsp::trace::unaligned_deserialize(&bytes1_none[..]); - assert_eq!(restored1_none, tup1_none); - assert!( - bytes1_none.len() >= core::mem::size_of::>>(), - "expected archived root to fit, got {} bytes", - bytes1_none.len() - ); - - let tup2_some = Tup2::new( - Some(SqlString::from_ref("hello")), - Some(SqlString::from_ref("world")), - ); - assert_eq!(tup2_some.get_0().as_ref().cloned().unwrap().str(), "hello"); - assert_eq!(tup2_some.get_1().as_ref().cloned().unwrap().str(), "world"); - - let bytes2_some = dbsp::storage::file::to_bytes(&tup2_some).unwrap(); - let restored2_some: Tup2, Option> = - dbsp::trace::unaligned_deserialize(&bytes2_some[..]); - assert_eq!(restored2_some, tup2_some); - - let tup2_none: Tup2, Option> = Tup2::new(None, None); - let bytes2_none = dbsp::storage::file::to_bytes(&tup2_none).unwrap(); - let restored2_none: Tup2, Option> = - dbsp::trace::unaligned_deserialize(&bytes2_none[..]); - assert_eq!(restored2_none, tup2_none); - assert!( - bytes2_none.len() >= core::mem::size_of::, Option>>(), - "expected archived root to fit, got {} bytes", - bytes2_none.len() - ); -} - -#[test] -fn rkyv_archived_getters() { - let tup1_none: Tup1> = Tup1::new(None); - let bytes1_none = dbsp::storage::file::to_bytes(&tup1_none).unwrap(); - let archived1_none = - unsafe { rkyv::archived_root::>>(&bytes1_none[..]) }; - let t0_none = archived1_none.0.as_ref(); - assert!(t0_none.is_none()); - - let tup2_10: Tup2, Option> = - Tup2::new(Some(SqlString::from_ref("hi")), None); - let bytes2_10 = dbsp::storage::file::to_bytes(&tup2_10).unwrap(); - let archived2_10 = - unsafe { rkyv::archived_root::, Option>>(&bytes2_10[..]) }; - let t0_10 = archived2_10.0.as_ref(); - let t1_10 = archived2_10.1.as_ref(); - assert!(t0_10.is_some()); - assert!(t1_10.is_none()); - assert_eq!(t0_10.unwrap().as_str(), "hi"); -} - -#[test] -fn rkyv_tup12_all_none_size() { - let tup: Tup12Opt = Tup12Opt { - 11: Some(SqlString::from("12345678")), - ..Default::default() - }; - let bytes = dbsp::storage::file::to_bytes(&tup).unwrap(); - assert!( - bytes.len() >= core::mem::size_of::>(), - "expected archived root to fit, got {} bytes", - bytes.len() - ); - let tup_archived = unsafe { rkyv::archived_root::(&bytes[..]) }; - assert_eq!( - tup_archived.get_t11().as_ref().unwrap().as_str(), - "12345678" - ); -} diff --git a/crates/feldera-macros/tests/tuple_formats.rs b/crates/feldera-macros/tests/tuple_formats.rs new file mode 100644 index 0000000000..d318b11f75 --- /dev/null +++ b/crates/feldera-macros/tests/tuple_formats.rs @@ -0,0 +1,271 @@ +use dbsp::utils::tuple::TupleFormat; +use feldera_sqllib::SqlString; + +feldera_macros::declare_tuple! { Tup1 } +feldera_macros::declare_tuple! { Tup2 } +feldera_macros::declare_tuple! { Tup7 } +feldera_macros::declare_tuple! { Tup8 } +feldera_macros::declare_tuple! { Tup12 } + +type Tup1OptStr = Tup1>; +type Tup2Sql = Tup2>; +type Tup2OptInt = Tup2, Option>; +type Tup8Base = Tup8; +type Tup7Opt = + Tup7, Option, Option, Option, Option, Option, Option>; +type Tup8Opt = Tup8< + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, +>; +type Tup12Opt = Tup12< + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, +>; + +#[repr(C)] +struct ArchivedFormatHeader { + format: TupleFormat, +} + +fn serialize_bytes(value: &T) -> dbsp::storage::buffer_cache::FBuf +where + T: rkyv::Archive + rkyv::Serialize, +{ + dbsp::storage::file::to_bytes(value).expect("serialize tuple") +} + +fn roundtrip(value: &T) +where + T: rkyv::Archive + + rkyv::Serialize + + PartialEq + + core::fmt::Debug, + rkyv::Archived: rkyv::Deserialize, +{ + let bytes = serialize_bytes(value); + let restored: T = dbsp::trace::unaligned_deserialize(&bytes[..]); + assert_eq!(&restored, value); +} + +fn archived_format(bytes: &[u8]) -> TupleFormat +where + T: rkyv::Archive, +{ + let archived = unsafe { rkyv::archived_root::(bytes) }; + unsafe { (*(archived as *const _ as *const ArchivedFormatHeader)).format } +} + +/// Makes sure we can serialize and deserialize the Tup's and +/// we have the same content before and after +#[test] +fn roundtrip_various_sizes() { + let tup1 = Tup1OptStr::new(Some(SqlString::from_ref("hello"))); + let tup2 = Tup2Sql::new(SqlString::from_ref("world"), Some(42u16)); + let tup8 = Tup8Base::new(-1, -2, -3, -4, 1, 2, 3, 4); + let tup12 = Tup12Opt::new( + Some(-8), + Some(-16), + Some(-32), + Some(-64), + Some(8), + Some(16), + Some(32), + Some(64), + Some(true), + Some(1.25), + Some(2.5), + Some(SqlString::from_ref("tuple")), + ); + + roundtrip(&tup1); + roundtrip(&tup2); + roundtrip(&tup8); + roundtrip(&tup12); +} + +#[test] +fn legacy_small_tuple_sizes() { + // We use the regular rkyv Archive impl for TupN where N < 8: + // (because our optimized Tuples have some overhead that only + // gets amortized when Tuples are large) + + // This means the Tup2 + let tup2_none: Tup2OptInt = Tup2OptInt::new(None, None); + let bytes2 = serialize_bytes(&tup2_none); + assert_eq!(bytes2.len(), 4); + + // This is 24 bytes mostly because a None in the archived version of + // SqlString doesnt get optimized away since it's first member is a [u8; X] + let tup1_none: Tup1OptStr = Tup1OptStr::new(None); + let bytes1 = serialize_bytes(&tup1_none); + assert_eq!(bytes1.len(), 24); + + // A Tup7 with all None is serialized in the regular rkyv derived version + // therefor it's size is the size of all the option types (44) aligned + // to a multiple of 8: 48 bytes + let tup7_none: Tup7Opt = Tup7Opt::new(None, None, None, None, None, None, None); + let bytes7 = serialize_bytes(&tup7_none); + let option_sizes = std::mem::size_of::>() + + std::mem::size_of::>() + + std::mem::size_of::>() + + std::mem::size_of::>() + + std::mem::size_of::>() + + std::mem::size_of::>() + + std::mem::size_of::>(); + let archived_alignment = std::mem::align_of::< + ArchivedTup7< + Option, + Option, + Option, + Option, + Option, + Option, + Option, + >, + >(); + assert_eq!( + bytes7.len(), + option_sizes.next_multiple_of(archived_alignment) + ); + + // In comparison here is a Tup12 we have optimized: + // the size is the header plus the sparse payload and doesn't include any fields. + let tup12_none: Tup12Opt = + Tup12Opt::new(None, None, None, None, None, None, None, None, None, None, None, None); + let bytes12 = serialize_bytes(&tup12_none); + let archived_sparse_size = core::mem::size_of::< + ArchivedTup12Sparse< + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + >, + >(); + let archived_size = core::mem::size_of::< + ArchivedTup12< + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + >, + >(); + assert_eq!(bytes12.len(), archived_size + archived_sparse_size); +} + +/// Tests that we pick the "right" storage format based on the data +#[test] +fn choose_appropriate_format() { + let tup8_dense: Tup8Opt = Tup8Opt::new( + Some(-1), + Some(-2), + Some(-3), + Some(-4), + Some(1), + Some(2), + None, + None, + ); + // A Tuple with just a few None's should be stored in the + // Dense format + let bytes_dense = serialize_bytes(&tup8_dense); + assert_eq!( + archived_format::(&bytes_dense[..]), + TupleFormat::Dense + ); + + // A Tup with many (>1/3) None's should be stored + // as Sparse + let tup8_sparse: Tup8Opt = + Tup8Opt::new(Some(-1), Some(-2), None, None, None, None, Some(3), Some(4)); + let bytes_sparse = serialize_bytes(&tup8_sparse); + assert_eq!( + archived_format::(&bytes_sparse[..]), + TupleFormat::Sparse + ); +} + +#[test] +fn choose_format_tup12() { + let tup12_all_none = Tup12Opt::new( + None, None, None, None, None, None, None, None, None, None, None, None, + ); + let bytes_none = serialize_bytes(&tup12_all_none); + assert_eq!( + archived_format::(&bytes_none[..]), + TupleFormat::Sparse + ); + + let tup12_dense = Tup12Opt::new( + Some(-1), + Some(-2), + Some(-3), + Some(-4), + Some(1), + Some(2), + Some(3), + Some(4), + None, + None, + Some(2.5), + Some(SqlString::from_ref("dense")), + ); + let bytes_dense = serialize_bytes(&tup12_dense); + assert_eq!( + archived_format::(&bytes_dense[..]), + TupleFormat::Dense + ); + + let tup12_sparse = Tup12Opt::new( + Some(-1), + None, + Some(-3), + None, + Some(1), + None, + Some(3), + None, + None, + None, + None, + None, + ); + let bytes_sparse = serialize_bytes(&tup12_sparse); + assert_eq!( + archived_format::(&bytes_sparse[..]), + TupleFormat::Sparse + ); + assert!(bytes_none.len() < bytes_dense.len()); + assert!(bytes_sparse.len() < bytes_dense.len()); +} diff --git a/crates/feldera-macros/tests/tuple_proptest.rs b/crates/feldera-macros/tests/tuple_proptest.rs new file mode 100644 index 0000000000..4fae9a0463 --- /dev/null +++ b/crates/feldera-macros/tests/tuple_proptest.rs @@ -0,0 +1,1902 @@ +use std::collections::BTreeMap; +use std::sync::Arc; + +use dbsp::algebra::{F32, F64}; +use dbsp::dynamic::{DynData, Erase}; +use dbsp::storage::backend::memory_impl::MemoryBackend; +use dbsp::storage::buffer_cache::BufferCache; +use dbsp::storage::file::writer::{Parameters, Writer1}; +use dbsp::storage::file::Factories; +use dbsp::DBData; +use feldera_sqllib::{ + to_array, to_map, Array, ByteArray, Date, GeoPoint, LongInterval, Map, ShortInterval, + SqlDecimal, SqlString, Time, Timestamp, Uuid, Variant, +}; +use proptest::prelude::*; + +use dbsp::utils::{Tup0, Tup1, Tup10, Tup2, Tup3, Tup4, Tup5, Tup6, Tup7, Tup8, Tup9}; +feldera_macros::declare_tuple! { Tup11 } +feldera_macros::declare_tuple! { Tup12 } +feldera_macros::declare_tuple! { Tup13 } +feldera_macros::declare_tuple! { Tup14 } +feldera_macros::declare_tuple! { Tup15 } +feldera_macros::declare_tuple! { Tup16 } +feldera_macros::declare_tuple! { Tup17 } +feldera_macros::declare_tuple! { Tup65< + T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, + T41, T42, T43, T44, T45, T46, T47, T48, T49, T50, + T51, T52, T53, T54, T55, T56, T57, T58, T59, T60, + T61, T62, T63, T64, T65 +> } + +type Dec12_2 = SqlDecimal<12, 2>; +type Dec10_0 = SqlDecimal<10, 0>; +type Dec18_4 = SqlDecimal<18, 4>; + +type Tup0Ty = Tup0; +type Tup1Ty = Tup1; +type Tup2Ty = Tup2>; +type Tup3Ty = Tup3; +type Tup4Ty = Tup4; +type Tup5Ty = Tup5>; +type Tup6Ty = Tup6< + Option, + Option, + Option, + Option, + Option, + Option, +>; +type Tup7Ty = Tup7< + Option