diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.lock | 23 | ||||
-rw-r--r-- | Cargo.toml | 20 | ||||
-rw-r--r-- | src/lib.rs | 115 |
4 files changed, 159 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5837ea0 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" + +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +dependencies = [ + "build_const", +] + +[[package]] +name = "growth-ring" +version = "0.1.0" +dependencies = [ + "crc", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0899509 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "growth-ring" +version = "0.1.0" +authors = ["Determinant <[email protected]>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +crc = "1.8.1" + +[lib] +name = "growthring" +path = "src/lib.rs" +crate-type = ["dylib", "rlib", "staticlib"] + + +[profile.release] +lto = true +debug = true diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d6a1e12 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,115 @@ +#[repr(u8)] +enum WALRingType { + Full, + First, + Middle, + Last +} + +struct WALRingBlob { + crc32: u32, + rsize: u32, + rtype: WALRingType, + // payload follows +} + +type WALFileId = u32; +type WALPos = u64; +type WALWrite = (WALPos, Box<[u8]>); + +pub struct WALState { + pub base: WALPos, + pub last: WALPos, + pub block_nbit: u8, + pub file_nbit: u8, +} + +pub struct WALWriter { + state: WALState, + block_buffer: Box<[u8]>, + block_size: u32, + file_size: u64, +} + +impl WALWriter { + pub fn new(state: WALState) -> Self { + let mut b = Vec::new(); + let block_size = 1 << (state.block_nbit as u32); + let file_size = 1 << (state.file_nbit as u64); + b.resize(block_size as usize, 0); + WALWriter{ + state, + block_buffer: b.into_boxed_slice(), + block_size, + file_size, + } + } + + pub fn grow(&mut self, records: &[Box<[u8]>]) -> Vec<WALWrite> { + let mut res = Vec::new(); + let msize = std::mem::size_of::<WALRingBlob>() as u32; + // the global offest of the begining of the block + // the start of the unwritten data + let mut bbuff_start = self.state.last as u32 & (self.block_size - 1); + // the end of the unwritten data + let mut bbuff_cur = bbuff_start; + + for _rec in records { + let mut rec = &_rec[..]; + let mut rsize = rec.len() as u32; + let mut started = false; + while rsize > 0 { + let remain = self.block_size - bbuff_cur; + if remain > msize { + let d = remain - msize; + let blob = unsafe {std::mem::transmute::<*mut u8, &mut WALRingBlob>( + &mut self.block_buffer[bbuff_cur as usize] as *mut u8)}; + if d >= rsize { + // the remaining rec fits in the block + let payload = rec; + blob.crc32 = crc::crc32::checksum_ieee(payload); + blob.rsize = rsize; + blob.rtype = if started {WALRingType::Last} else {WALRingType::Full}; + rsize = 0; + &mut self.block_buffer[bbuff_cur as usize..].copy_from_slice(payload); + bbuff_cur += rsize; + } else { + // the remaining block can only accommodate partial rec + let payload = &rec[..d as usize]; + blob.crc32 = crc::crc32::checksum_ieee(payload); + blob.rsize = d; + blob.rtype = if started {WALRingType::Middle} else { + started = true; + WALRingType::First + }; + rsize -= d; + &mut self.block_buffer[bbuff_cur as usize..].copy_from_slice(payload); + bbuff_cur += d; + rec = &rec[d as usize..]; + } + } else { + // add padding space by moving the point to the end of the block + bbuff_cur = self.block_size; + } + if bbuff_cur == self.block_size { + res.push((self.state.last, + self.block_buffer[bbuff_start as usize..] + .to_vec().into_boxed_slice())); + self.state.last += (self.block_size - bbuff_start) as u64; + bbuff_start = 0; + bbuff_cur = 0; + } + } + } + if bbuff_cur > bbuff_start { + res.push((self.state.last, + self.block_buffer[bbuff_start as usize..bbuff_cur as usize] + .to_vec().into_boxed_slice())); + self.state.last += (bbuff_cur - bbuff_start) as u64; + } + res + } +} + +struct WALReader { +} |