summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2020-06-08 22:32:53 -0400
committerDeterminant <[email protected]>2020-06-08 22:32:53 -0400
commit62956a6b138c3824389274cee87a9f781ff4077c (patch)
tree1a925debfe49b3cd3426963eb3ab1a00604af9a6
init
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock23
-rw-r--r--Cargo.toml20
-rw-r--r--src/lib.rs115
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 {
+}