From 381c9e58be2e3e527caa01b45f0672e039d6a42c Mon Sep 17 00:00:00 2001 From: Al Liu Date: Sun, 15 Sep 2024 03:46:12 +0800 Subject: [PATCH] Add an example --- examples/foo.rs | 1 - examples/zero_cost.rs | 174 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 1 deletion(-) delete mode 100644 examples/foo.rs create mode 100644 examples/zero_cost.rs diff --git a/examples/foo.rs b/examples/foo.rs deleted file mode 100644 index f328e4d9..00000000 --- a/examples/foo.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() {} diff --git a/examples/zero_cost.rs b/examples/zero_cost.rs new file mode 100644 index 00000000..7ffd06a1 --- /dev/null +++ b/examples/zero_cost.rs @@ -0,0 +1,174 @@ +use std::{cmp, sync::Arc, thread::spawn}; + +use orderwal::{swmr::generic::*, utils::*, OpenOptions, Options}; + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct Person { + id: u64, + name: String, +} + +impl Person { + fn random() -> Self { + Self { + id: rand::random(), + name: names::Generator::default().next().unwrap(), + } + } +} + +#[derive(Debug)] +struct PersonRef<'a> { + id: u64, + name: &'a str, +} + +impl<'a> PartialEq for PersonRef<'a> { + fn eq(&self, other: &Self) -> bool { + self.id == other.id && self.name == other.name + } +} + +impl<'a> Eq for PersonRef<'a> {} + +impl<'a> PartialOrd for PersonRef<'a> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl<'a> Ord for PersonRef<'a> { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self + .id + .cmp(&other.id) + .then_with(|| self.name.cmp(other.name)) + } +} + +impl Equivalent for PersonRef<'_> { + fn equivalent(&self, key: &Person) -> bool { + self.id == key.id && self.name == key.name + } +} + +impl Comparable for PersonRef<'_> { + fn compare(&self, key: &Person) -> std::cmp::Ordering { + self.id.cmp(&key.id).then_with(|| self.name.cmp(&key.name)) + } +} + +impl Equivalent> for Person { + fn equivalent(&self, key: &PersonRef<'_>) -> bool { + self.id == key.id && self.name == key.name + } +} + +impl Comparable> for Person { + fn compare(&self, key: &PersonRef<'_>) -> std::cmp::Ordering { + self + .id + .cmp(&key.id) + .then_with(|| self.name.as_str().cmp(key.name)) + } +} + +impl<'a> KeyRef<'a, Person> for PersonRef<'a> { + fn compare(&self, a: &Q) -> cmp::Ordering + where + Q: ?Sized + Ord + Comparable, + { + Comparable::compare(a, self).reverse() + } + + fn compare_binary(this: &[u8], other: &[u8]) -> cmp::Ordering { + let (this_id_size, this_id) = decode_u64_varint(this).unwrap(); + let (other_id_size, other_id) = decode_u64_varint(other).unwrap(); + + PersonRef { + id: this_id, + name: std::str::from_utf8(&this[this_id_size..]).unwrap(), + } + .cmp(&PersonRef { + id: other_id, + name: std::str::from_utf8(&other[other_id_size..]).unwrap(), + }) + } +} + +impl Type for Person { + type Ref<'a> = PersonRef<'a>; + type Error = dbutils::leb128::EncodeVarintError; + + fn encoded_len(&self) -> usize { + encoded_u64_varint_len(self.id) + self.name.len() + } + + fn encode(&self, buf: &mut [u8]) -> Result<(), Self::Error> { + let id_size = encode_u64_varint(self.id, buf)?; + buf[id_size..].copy_from_slice(self.name.as_bytes()); + Ok(()) + } +} + +impl<'a> TypeRef<'a> for PersonRef<'a> { + fn from_slice(src: &'a [u8]) -> Self { + let (id_size, id) = decode_u64_varint(src).unwrap(); + let name = std::str::from_utf8(&src[id_size..]).unwrap(); + PersonRef { id, name } + } +} + +fn main() { + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("zero_copy.wal"); + + let people = (0..100) + .map(|_| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + (p, v) + }) + .collect::>(); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(1024 * 1024)) + .write(true) + .read(true), + ) + .unwrap() + }; + + // Create 100 readers + let readers = (0..100).map(|_| wal.reader()).collect::>(); + + let people = Arc::new(people); + + // Spawn 100 threads to read from the wal + let handles = readers.into_iter().enumerate().map(|(i, reader)| { + let people = people.clone(); + spawn(move || loop { + let (person, hello) = &people[i]; + if let Some(p) = reader.get(&people[i].0) { + assert_eq!(p.key().id, person.id); + assert_eq!(p.key().name, person.name); + assert_eq!(p.value(), hello); + break; + } + }) + }); + + // Insert 100 people into the wal + for (p, h) in people.iter() { + wal.insert(p, h).unwrap(); + } + + // Wait for all threads to finish + for handle in handles { + handle.join().unwrap(); + } +}