diff --git a/.codecov.yml b/.codecov.yml index daec5b14..750acffe 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -9,8 +9,11 @@ ignore: - "src/swmr/generic/traits/impls.rs" - "src/tests.rs" - "src/swmr/generic/tests.rs" + - "src/swmr/generic/tests/" - "src/swmr/wal/tests.rs" + - "src/swmr/wal/tests/" - "src/unsync/tests.rs" + - "src/unsync/tests/" coverage: status: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ea0c80d..603a3fd2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -217,68 +217,58 @@ jobs: run: ci/sanitizer_generic.sh if: matrix.os != 'ubuntu-latest' - miri-tb-unsync: - name: miri-tb-unsync - strategy: - matrix: - os: - - ubuntu-latest - # - macos-latest - # - windows-latest - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - name: Cache cargo build and registry - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-miri-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-miri- - - name: Install cargo-hack - run: cargo install cargo-hack - - name: Miri (Linux) - run: ci/miri_tb_unsync.sh - if: matrix.os == 'ubuntu-latest' + # miri-tb-unsync: + # name: miri-tb-unsync + # strategy: + # matrix: + # os: + # - ubuntu-latest + # # - macos-latest + # # - windows-latest + # runs-on: ${{ matrix.os }} + # steps: + # - uses: actions/checkout@v3 + # - name: Cache cargo build and registry + # uses: actions/cache@v3 + # with: + # path: | + # ~/.cargo/registry + # ~/.cargo/git + # target + # key: ${{ runner.os }}-miri-${{ hashFiles('**/Cargo.lock') }} + # restore-keys: | + # ${{ runner.os }}-miri- + # - name: Install cargo-hack + # run: cargo install cargo-hack + # - name: Miri (Linux) + # run: ci/miri_tb_unsync.sh + # if: matrix.os == 'ubuntu-latest' - miri-tb-swmr: - name: miri-tb-swmr - strategy: - matrix: - os: - - ubuntu-latest - # - macos-latest - # - windows-latest - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - name: Cache cargo build and registry - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-miri-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-miri- - - name: Install cargo-hack - run: cargo install cargo-hack - - name: Miri (Linux) - run: ci/miri_tb_swmr.sh - if: matrix.os == 'ubuntu-latest' - - miri-tb-swmr-generic: - name: miri-tb-swmr-generic + miri-tb: + name: miri-tb-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.features }} strategy: matrix: os: - ubuntu-latest # - macos-latest # - windows-latest + target: + - x86_64-unknown-linux-gnu + - i686-unknown-linux-gnu + - powerpc64-unknown-linux-gnu + features: + - test-unsync-insert + - test-unsync-iters + - test-unsync-get + - test-unsync-constructor + - test-swmr-insert + - test-swmr-iters + - test-swmr-get + - test-swmr-constructor + - test-swmr-generic-insert + - test-swmr-generic-iters + - test-swmr-generic-get + - test-swmr-generic-constructor runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 @@ -295,7 +285,8 @@ jobs: - name: Install cargo-hack run: cargo install cargo-hack - name: Miri (Linux) - run: ci/miri_tb_swmr_generic.sh + run: | + bash ci/miri_tb.sh ${{ matrix.target }} ${{ matrix.features }} if: matrix.os == 'ubuntu-latest' # miri-sb: diff --git a/Cargo.toml b/Cargo.toml index 3dab90e9..ab8a3ecc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "orderwal" -version = "0.1.0" +version = "0.1.1" edition = "2021" repository = "https://github.com/al8n/orderwal" homepage = "https://github.com/al8n/orderwal" @@ -24,9 +24,21 @@ xxhash3 = ["dbutils/xxhash3", "std"] xxhash64 = ["dbutils/xxhash64", "std"] ## only for miri testing -test-unsync = ["std"] -test-swmr = ["std"] -test-swmr-generic = ["std"] +test-unsync-insert = ["std"] +test-unsync-iters = ["std"] +test-unsync-get = ["std"] +test-unsync-constructor = ["std"] + +test-swmr-insert = ["std"] +test-swmr-iters = ["std"] +test-swmr-get = ["std"] +test-swmr-constructor = ["std"] + +test-swmr-generic-insert = ["std"] +test-swmr-generic-iters = ["std"] +test-swmr-generic-get = ["std"] +test-swmr-generic-constructor = ["std"] + [dependencies] among = { version = "0.1", default-features = false, features = ["either"] } diff --git a/ci/miri_tb.sh b/ci/miri_tb.sh index 5a6c4c22..85cc5984 100755 --- a/ci/miri_tb.sh +++ b/ci/miri_tb.sh @@ -1,13 +1,25 @@ #!/bin/bash set -e +# Check if TARGET and FEATURES are provided, otherwise panic +if [ -z "$1" ]; then + echo "Error: TARGET is not provided" + exit 1 +fi + +if [ -z "$2" ]; then + echo "Error: FEATURES are not provided" + exit 1 +fi + +TARGET=$1 +FEATURES=$2 + rustup toolchain install nightly --component miri rustup override set nightly cargo miri setup -export MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-tree-borrows" +export MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-tree-borrows -Zmiri-ignore-leaks" + +cargo miri test --tests --target $TARGET --features $FEATURES --lib -cargo miri test --tests --target x86_64-unknown-linux-gnu --all-features -# cargo miri test --tests --target aarch64-unknown-linux-gnu #crossbeam_utils has problem on this platform -cargo miri test --tests --target i686-unknown-linux-gnu --all-features -cargo miri test --tests --target powerpc64-unknown-linux-gnu --all-features diff --git a/ci/miri_tb_generic.sh b/ci/miri_tb_generic.sh deleted file mode 100755 index 6e6c9013..00000000 --- a/ci/miri_tb_generic.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -set -e - -rustup toolchain install nightly --component miri -rustup override set nightly -cargo miri setup - -export MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-tree-borrows" - -cargo miri test --tests --all-features diff --git a/ci/miri_tb_swmr.sh b/ci/miri_tb_swmr.sh deleted file mode 100755 index 4196fbbd..00000000 --- a/ci/miri_tb_swmr.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -set -e - -rustup toolchain install nightly --component miri -rustup override set nightly -cargo miri setup - -export MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-tree-borrows -Zmiri-ignore-leaks" - -cargo miri test --tests --target x86_64-unknown-linux-gnu --features test-swmr --lib -# cargo miri test --tests --target aarch64-unknown-linux-gnu #crossbeam_utils has problem on this platform -cargo miri test --tests --target i686-unknown-linux-gnu --features test-swmr --lib -cargo miri test --tests --target powerpc64-unknown-linux-gnu --features test-swmr --lib diff --git a/ci/miri_tb_swmr_generic.sh b/ci/miri_tb_swmr_generic.sh deleted file mode 100755 index 770c91d6..00000000 --- a/ci/miri_tb_swmr_generic.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -set -e - -rustup toolchain install nightly --component miri -rustup override set nightly -cargo miri setup - -export MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-tree-borrows -Zmiri-ignore-leaks" - -cargo miri test --tests --target x86_64-unknown-linux-gnu --features test-swmr-generic --lib -# cargo miri test --tests --target aarch64-unknown-linux-gnu #crossbeam_utils has problem on this platform -cargo miri test --tests --target i686-unknown-linux-gnu --features test-swmr-generic --lib -cargo miri test --tests --target powerpc64-unknown-linux-gnu --features test-swmr-generic --lib diff --git a/ci/miri_tb_unsync.sh b/ci/miri_tb_unsync.sh deleted file mode 100755 index 8a485ad1..00000000 --- a/ci/miri_tb_unsync.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -set -e - -rustup toolchain install nightly --component miri -rustup override set nightly -cargo miri setup - -export MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation -Zmiri-tree-borrows" - -cargo miri test --tests --target x86_64-unknown-linux-gnu --features test-unsync --lib -# cargo miri test --tests --target aarch64-unknown-linux-gnu #crossbeam_utils has problem on this platform -cargo miri test --tests --target i686-unknown-linux-gnu --features test-unsync --lib -cargo miri test --tests --target powerpc64-unknown-linux-gnu --features test-unsync --lib diff --git a/src/lib.rs b/src/lib.rs index a6a5ae2f..e04cbba2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,7 +39,7 @@ const MAGIC_TEXT_SIZE: usize = MAGIC_TEXT.len(); const MAGIC_VERSION_SIZE: usize = mem::size_of::(); const HEADER_SIZE: usize = MAGIC_TEXT_SIZE + MAGIC_VERSION_SIZE; -#[cfg(all(test, any(feature = "test-swmr", feature = "test-unsync")))] +#[cfg(test)] #[macro_use] mod tests; diff --git a/src/swmr/generic.rs b/src/swmr/generic.rs index b5891220..4d97a137 100644 --- a/src/swmr/generic.rs +++ b/src/swmr/generic.rs @@ -32,7 +32,7 @@ pub use reader::*; mod iter; pub use iter::*; -#[cfg(all(test, feature = "test-swmr-generic"))] +#[cfg(test)] mod tests; #[doc(hidden)] diff --git a/src/swmr/generic/tests.rs b/src/swmr/generic/tests.rs index 8cf51b03..4836cb4d 100644 --- a/src/swmr/generic/tests.rs +++ b/src/swmr/generic/tests.rs @@ -8,6 +8,15 @@ use super::*; const MB: u32 = 1024 * 1024; +#[cfg(all(test, feature = "test-swmr-generic-constructor"))] +mod constructor; +#[cfg(all(test, feature = "test-swmr-generic-get"))] +mod get; +#[cfg(all(test, feature = "test-swmr-generic-insert"))] +mod insert; +#[cfg(all(test, feature = "test-swmr-generic-iters"))] +mod iters; + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Arbitrary)] struct Person { id: u64, @@ -155,1584 +164,3 @@ impl<'a> TypeRef<'a> for PersonRef<'a> { PersonRef { id, name } } } - -#[test] -fn owned_comparable() { - let p1 = Person { - id: 3127022870678870148, - name: "enthusiastic-magic".into(), - }; - let p2 = Person { - id: 9872687799307360216, - name: "damaged-friend".into(), - }; - - let p1bytes = p1.to_vec(); - let p2bytes = p2.to_vec(); - - let ptr1 = Pointer::::new(p1bytes.len(), 0, p1bytes.as_ptr()); - let ptr2 = Pointer::::new(p2bytes.len(), 0, p2bytes.as_ptr()); - - let map = SkipSet::new(); - map.insert(ptr1); - map.insert(ptr2); - - assert!(map.contains(&Owned::new(&p1))); - assert!(map.get(&Owned::new(&p1)).is_some()); - - assert!(map.contains(&Owned::new(&p2))); - assert!(map.get(&Owned::new(&p2)).is_some()); - - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - wal.insert(&p1, &"My name is Alice!".to_string()).unwrap(); - wal.insert(&p2, &"My name is Bob!".to_string()).unwrap(); - - assert!(wal.contains_key(&p1)); - assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); - - assert!(wal.contains_key(&p2)); - assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); -} - -#[test] -fn ref_comparable() { - let p1 = PersonRef { - id: 3127022870678870148, - name: "enthusiastic-magic", - }; - let p2 = PersonRef { - id: 9872687799307360216, - name: "damaged-friend", - }; - - let p1bytes = p1.to_vec(); - let p2bytes = p2.to_vec(); - - let ptr1 = Pointer::::new(p1bytes.len(), 0, p1bytes.as_ptr()); - let ptr2 = Pointer::::new(p2bytes.len(), 0, p2bytes.as_ptr()); - - let map = SkipSet::new(); - map.insert(ptr1); - map.insert(ptr2); - - assert!(map.contains(&Owned::new(&p1))); - assert!(map.get(&Owned::new(&p1)).is_some()); - - assert!(map.contains(&Owned::new(&p2))); - assert!(map.get(&Owned::new(&p2)).is_some()); - - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - - unsafe { - wal - .insert_key_bytes_with_value(&p1bytes, &"My name is Alice!".to_string()) - .unwrap(); - wal - .insert_key_bytes_with_value(&p2bytes, &"My name is Bob!".to_string()) - .unwrap(); - } - - assert!(wal.contains_key(&p1)); - assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); - - assert!(wal.contains_key(&p2)); - assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); - - assert!(wal.contains_key_by_ref(&p1)); - assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); - - assert!(wal.contains_key_by_ref(&p2)); - assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); - - unsafe { - assert!(wal.contains_key_by_bytes(&p1bytes)); - assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); - - assert!(wal.contains_key_by_bytes(&p2bytes)); - assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); - } -} - -#[test] -fn construct_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - - let person = Person { - id: 1, - name: "Alice".to_string(), - }; - - assert!(wal.is_empty()); - - wal - .insert(&person, &"My name is Alice!".to_string()) - .unwrap(); - - let wal = wal.reader(); - - assert_eq!(wal.len(), 1); - assert!(!wal.is_empty()); -} - -#[test] -fn construct_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - - let person = Person { - id: 1, - name: "Alice".to_string(), - }; - - wal - .insert(&person, &"My name is Alice!".to_string()) - .unwrap(); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn construct_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_construct_map_file"); - - unsafe { - let mut wal = GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap(); - let person = Person { - id: 1, - name: "Alice".to_string(), - }; - - wal - .insert(&person, &"My name is Alice!".to_string()) - .unwrap(); - assert_eq!(wal.get(&person).unwrap().value(), "My name is Alice!"); - - assert_eq!(*wal.path().unwrap().as_ref(), path); - } - - let pr = PersonRef { - id: 1, - name: "Alice", - }; - - unsafe { - let wal = GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new().create(Some(MB)).write(true).read(true), - ) - .unwrap(); - assert_eq!(wal.get(&pr).unwrap().value(), "My name is Alice!"); - } - - let wal = unsafe { GenericOrderWal::::map(&path, Options::new()).unwrap() }; - assert_eq!(wal.get(&pr).unwrap().value(), "My name is Alice!"); -} - -#[test] -fn construct_with_small_capacity_inmemory() { - let wal = GenericOrderWal::::new(Options::new().with_capacity(1)); - - assert!(wal.is_err()); - match wal { - Err(e) => println!("error: {:?}", e), - _ => panic!("unexpected error"), - } -} - -#[test] -fn construct_with_small_capacity_map_anon() { - let wal = GenericOrderWal::::map_anon(Options::new().with_capacity(1)); - - assert!(wal.is_err()); - match wal { - Err(e) => println!("error: {:?}", e), - _ => panic!("unexpected error"), - } -} - -#[test] -fn construct_with_small_capacity_map_file() { - let dir = tempdir().unwrap(); - let path = dir - .path() - .join("generic_wal_construct_with_small_capacity_map_file"); - - let wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(1)) - .write(true) - .read(true), - ) - }; - - assert!(wal.is_err()); - match wal { - Err(e) => println!("{:?}", e), - _ => panic!("unexpected error"), - } -} - -fn insert_to_full(wal: &mut GenericOrderWal) { - let mut full = false; - for _ in 0u32.. { - let p = Person::random(); - match wal.insert(&p, &format!("My name is {}", p.name)) { - Ok(_) => {} - Err(e) => match e { - Among::Right(Error::InsufficientSpace { .. }) => { - full = true; - break; - } - _ => panic!("unexpected error"), - }, - } - } - assert!(full); -} - -#[test] -fn insert_to_full_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - insert_to_full(&mut wal); -} - -#[test] -fn insert_to_full_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - insert_to_full(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn insert_to_full_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_insert_to_full_map_file"); - - unsafe { - let mut wal = GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap(); - insert_to_full(&mut wal); - } -} - -fn insert(wal: &mut GenericOrderWal) -> Vec { - let people = (0..100) - .map(|_| { - let p = Person::random(); - wal.insert(&p, &format!("My name is {}", p.name)).unwrap(); - p - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for p in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - assert_eq!( - wal.get(p).unwrap().value(), - format!("My name is {}", p.name) - ); - } - - people -} - -#[test] -fn insert_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - insert(&mut wal); -} - -#[test] -fn insert_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - insert(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn insert_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_insert_map_file"); - - let people = unsafe { - let mut wal = GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap(); - insert(&mut wal) - }; - - let wal = unsafe { GenericOrderWal::::map(&path, Options::new()).unwrap() }; - - for p in people { - assert!(wal.contains_key(&p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - assert_eq!( - wal.get(&p).unwrap().value(), - format!("My name is {}", p.name) - ); - } -} - -fn insert_key_bytes_with_value( - wal: &mut GenericOrderWal, -) -> Vec<(Vec, Person)> { - let people = (0..100) - .map(|_| { - let p = Person::random(); - let pbytes = p.to_vec(); - unsafe { - wal - .insert_key_bytes_with_value(&pbytes, &format!("My name is {}", p.name)) - .unwrap(); - } - (pbytes, p) - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for (pbytes, p) in &people { - assert!(wal.contains_key(p)); - unsafe { - assert!(wal.contains_key_by_bytes(pbytes)); - } - assert_eq!( - wal.get(p).unwrap().value(), - format!("My name is {}", p.name) - ); - - assert_eq!( - unsafe { wal.get_by_bytes(pbytes).unwrap().value() }, - format!("My name is {}", p.name) - ); - } - - people -} - -#[test] -fn insert_key_bytes_with_value_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - insert_key_bytes_with_value(&mut wal); -} - -#[test] -fn insert_key_bytes_with_value_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - insert_key_bytes_with_value(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn insert_key_bytes_with_value_map_file() { - let dir = tempdir().unwrap(); - let path = dir - .path() - .join("generic_wal_insert_key_bytes_with_value_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - let people = insert_key_bytes_with_value(&mut wal); - - let wal = wal.reader(); - - for (pbytes, p) in &people { - assert!(wal.contains_key(p)); - unsafe { - assert!(wal.contains_key_by_bytes(pbytes)); - } - assert_eq!( - wal.get(p).unwrap().value(), - format!("My name is {}", p.name) - ); - assert_eq!( - unsafe { wal.get_by_bytes(pbytes).unwrap().value() }, - format!("My name is {}", p.name) - ); - } - - let wal = unsafe { GenericOrderWal::::map(&path, Options::new()).unwrap() }; - - for (pbytes, p) in people { - assert!(wal.contains_key(&p)); - unsafe { - assert!(wal.contains_key_by_bytes(&pbytes)); - } - assert_eq!( - wal.get(&p).unwrap().value(), - format!("My name is {}", p.name) - ); - assert_eq!( - unsafe { wal.get_by_bytes(&pbytes).unwrap().value() }, - format!("My name is {}", p.name) - ); - } -} - -fn insert_key_with_value_bytes(wal: &mut GenericOrderWal) -> Vec { - let people = (0..100) - .map(|_| { - let p = Person::random(); - unsafe { - wal - .insert_key_with_value_bytes(&p, format!("My name is {}", p.name).as_bytes()) - .unwrap(); - } - p - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for p in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - assert_eq!( - wal.get_by_ref(p).unwrap().value(), - format!("My name is {}", p.name) - ); - } - - people -} - -#[test] -fn insert_key_with_value_bytes_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - insert_key_with_value_bytes(&mut wal); -} - -#[test] -fn insert_key_with_value_bytes_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - insert_key_with_value_bytes(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn insert_key_with_value_bytes_map_file() { - let dir = tempdir().unwrap(); - let path = dir - .path() - .join("generic_wal_insert_key_with_value_bytes_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - let people = insert_key_with_value_bytes(&mut wal); - let wal = wal.reader(); - - for p in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - assert_eq!( - wal.get_by_ref(p).unwrap().value(), - format!("My name is {}", p.name) - ); - } -} - -fn insert_bytes(wal: &mut GenericOrderWal) -> Vec { - let people = (0..100) - .map(|_| { - let p = Person::random(); - let pbytes = p.to_vec(); - unsafe { - wal - .insert_bytes(&pbytes, format!("My name is {}", p.name).as_bytes()) - .unwrap(); - } - p - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for p in &people { - assert!(wal.contains_key(p)); - unsafe { - assert!(wal.contains_key_by_bytes(&p.to_vec())); - } - assert_eq!( - wal.get(p).unwrap().value(), - format!("My name is {}", p.name) - ); - } - - people -} - -#[test] -fn insert_bytes_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - insert_bytes(&mut wal); -} - -#[test] -fn insert_bytes_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - insert_bytes(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn insert_bytes_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_insert_bytes_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - let people = insert_bytes(&mut wal); - - let wal = wal.reader(); - - for p in &people { - assert!(wal.contains_key(p)); - unsafe { - assert!(wal.contains_key_by_bytes(&p.to_vec())); - } - assert_eq!( - wal.get(p).unwrap().value(), - format!("My name is {}", p.name) - ); - } -} - -fn iter(wal: &mut GenericOrderWal) -> Vec<(Person, String)> { - let mut people = (0..100) - .map(|_| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - wal.insert(&p, &v).unwrap(); - (p, v) - }) - .collect::>(); - - people.sort_by(|a, b| a.0.cmp(&b.0)); - - let mut iter = wal.iter(); - - for (pwal, pvec) in people.iter().zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } - - let mut rev_iter = wal.iter().rev(); - - for (pwal, pvec) in people.iter().rev().zip(rev_iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } - - people -} - -#[test] -fn iter_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - iter(&mut wal); -} - -#[test] -fn iter_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - iter(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn iter_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_iter_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - let people = iter(&mut wal); - - let wal = wal.reader(); - let mut iter = wal.iter(); - - for (pwal, pvec) in people.iter().zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } -} - -fn range(wal: &mut GenericOrderWal) { - let mut mid = Person::random(); - let people = (0..100) - .map(|idx| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - wal.insert(&p, &v).unwrap(); - - if idx == 500 { - mid = p.clone(); - } - (p, v) - }) - .collect::>(); - - let mut iter = wal.range(Bound::Included(&mid), Bound::Unbounded); - - for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } - - assert!(iter.next().is_none()); - - let wal = wal.reader(); - let mut iter = wal.range(Bound::Included(&mid), Bound::Unbounded); - - for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } - - let mut rev_iter = wal.range(Bound::Included(&mid), Bound::Unbounded).rev(); - - for (pwal, pvec) in people.range(&mid..).rev().zip(rev_iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } -} - -#[test] -fn range_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - range(&mut wal); -} - -#[test] -fn range_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - range(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn range_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_range_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - range(&mut wal); -} - -fn range_ref(wal: &mut GenericOrderWal) { - let mut mid = Person::random(); - let people = (0..100) - .map(|idx| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - wal.insert(&p, &v).unwrap(); - - if idx == 500 { - mid = p.clone(); - } - (p, v) - }) - .collect::>(); - - let mid_ref = mid.as_ref(); - let mut iter = wal.range_by_ref(Bound::Included(&mid_ref), Bound::Unbounded); - - for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } - - assert!(iter.next().is_none()); - - let wal = wal.reader(); - let mut iter = wal.range_by_ref(Bound::Included(&mid), Bound::Unbounded); - - for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } - - let mut rev_iter = wal - .range_by_ref(Bound::Included(&mid), Bound::Unbounded) - .rev(); - - for (pwal, pvec) in people.range(&mid..).rev().zip(rev_iter.by_ref()) { - assert!(pwal.0.equivalent(&pvec.key())); - assert_eq!(pwal.1, pvec.value()); - } -} - -#[test] -fn range_ref_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - range(&mut wal); -} - -#[test] -fn range_ref_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - range_ref(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn range_ref_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_range_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - range_ref(&mut wal); -} - -fn first(wal: &mut GenericOrderWal) { - let people = (0..10) - .map(|_| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - wal.insert(&p, &v).unwrap(); - - (p, v) - }) - .collect::>(); - - let ent = wal.first().unwrap(); - let (p, v) = people.first_key_value().unwrap(); - assert!(ent.key().equivalent(p)); - assert_eq!(ent.value(), v); - - let wal = wal.reader().clone(); - let ent = wal.first().unwrap(); - let (p, v) = people.first_key_value().unwrap(); - assert!(ent.key().equivalent(p)); - assert_eq!(ent.value(), v); -} - -#[test] -fn first_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - first(&mut wal); -} - -#[test] -fn first_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - first(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn first_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_first_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - first(&mut wal); -} - -fn last(wal: &mut GenericOrderWal) { - let people = (0..10) - .map(|_| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - wal.insert(&p, &v).unwrap(); - - (p, v) - }) - .collect::>(); - - let ent = wal.last().unwrap(); - let (p, v) = people.last_key_value().unwrap(); - assert!(ent.key().equivalent(p)); - assert_eq!(ent.value(), v); - - let wal = wal.reader(); - let ent = wal.last().unwrap(); - assert!(ent.key().equivalent(p)); - assert_eq!(ent.value(), v); -} - -#[test] -fn last_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - last(&mut wal); -} - -#[test] -fn last_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - last(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn last_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_last_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - last(&mut wal); -} - -fn get_or_insert(wal: &mut GenericOrderWal) { - let people = (0..100) - .map(|_| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - wal.get_or_insert(&p, &v).unwrap_right().unwrap(); - (p, v) - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for (p, pv) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - assert_eq!( - wal - .get_or_insert(p, &format!("Hello! {}!", p.name)) - .unwrap_left() - .value(), - pv - ); - } - - for (p, _) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - } -} - -#[test] -fn get_or_insert_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - get_or_insert(&mut wal); -} - -#[test] -fn get_or_insert_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - get_or_insert(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn get_or_insert_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_get_or_insert_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - get_or_insert(&mut wal); -} - -fn get_or_insert_with(wal: &mut GenericOrderWal) { - let people = (0..100) - .map(|_| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - wal - .get_or_insert_with(&p, || v.clone()) - .unwrap_right() - .unwrap(); - (p, v) - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for (p, pv) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - assert_eq!( - wal - .get_or_insert_with(p, || format!("Hello! {}!", p.name)) - .unwrap_left() - .value(), - pv - ); - } - - for (p, _) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - } -} - -#[test] -fn get_or_insert_with_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - get_or_insert_with(&mut wal); -} - -#[test] -fn get_or_insert_with_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - get_or_insert_with(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn get_or_insert_with_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_get_or_insert_with_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - get_or_insert_with(&mut wal); -} - -fn get_or_insert_key_with_value_bytes(wal: &mut GenericOrderWal) { - let people = (0..100) - .map(|_| { - let p = Person::random(); - let pvec = p.to_vec(); - let v = format!("My name is {}", p.name); - unsafe { - wal - .get_by_bytes_or_insert(pvec.as_ref(), &v) - .unwrap_right() - .unwrap(); - } - (p, v) - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for (p, pv) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - assert_eq!( - wal - .get_or_insert(p, &format!("Hello! {}!", p.name)) - .unwrap_left() - .value(), - pv - ); - } - - for (p, _) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - } -} - -#[test] -fn get_or_insert_key_with_value_bytes_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - get_or_insert_key_with_value_bytes(&mut wal); -} - -#[test] -fn get_or_insert_key_with_value_bytes_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - get_or_insert_key_with_value_bytes(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn get_or_insert_key_with_value_bytes_map_file() { - let dir = tempdir().unwrap(); - let path = dir - .path() - .join("generic_wal_get_or_insert_key_with_value_bytes_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - get_or_insert_key_with_value_bytes(&mut wal); -} - -fn get_or_insert_value_bytes(wal: &mut GenericOrderWal) { - let people = (0..100) - .map(|_| { - let p = Person::random(); - let v = format!("My name is {}", p.name); - unsafe { - wal - .get_or_insert_bytes(&p, v.as_bytes()) - .unwrap_right() - .unwrap(); - } - (p, v) - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for (p, pv) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - unsafe { - assert_eq!( - wal - .get_or_insert_bytes(p, pv.as_bytes()) - .unwrap_left() - .value(), - pv - ); - } - } - - for (p, _) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - } -} - -#[test] -fn get_or_insert_value_bytes_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - get_or_insert_value_bytes(&mut wal); -} - -#[test] -fn get_or_insert_value_bytes_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - get_or_insert_value_bytes(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn get_or_insert_value_bytes_map_file() { - let dir = tempdir().unwrap(); - let path = dir - .path() - .join("generic_wal_get_or_insert_value_bytes_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - get_or_insert_value_bytes(&mut wal); -} - -fn get_by_bytes_or_insert_with(wal: &mut GenericOrderWal) { - let people = (0..100) - .map(|_| { - let p = Person::random(); - let pvec = p.to_vec(); - let v = format!("My name is {}", p.name); - unsafe { - wal - .get_by_bytes_or_insert_with(pvec.as_ref(), || v.clone()) - .unwrap_right() - .unwrap(); - } - (p, pvec, v) - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for (p, pvec, pv) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - unsafe { - assert_eq!( - wal - .get_by_bytes_or_insert_with(pvec, || format!("Hello! {}!", p.name)) - .unwrap_left() - .value(), - pv - ); - } - } - - for (p, _, _) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - } -} - -#[test] -fn get_by_bytes_or_insert_with_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - get_by_bytes_or_insert_with(&mut wal); -} - -#[test] -fn get_by_bytes_or_insert_with_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - get_by_bytes_or_insert_with(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn get_by_bytes_or_insert_with_map_file() { - let dir = tempdir().unwrap(); - let path = dir - .path() - .join("generic_wal_get_by_bytes_or_insert_with_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - get_by_bytes_or_insert_with(&mut wal); -} - -fn get_by_bytes_or_insert_bytes(wal: &mut GenericOrderWal) { - let people = (0..100) - .map(|_| { - let p = Person::random(); - let pvec = p.to_vec(); - let v = format!("My name is {}", p.name); - unsafe { - wal - .get_by_bytes_or_insert_bytes(pvec.as_ref(), v.as_bytes()) - .unwrap_right() - .unwrap(); - } - (p, pvec, v) - }) - .collect::>(); - - assert_eq!(wal.len(), 100); - - for (p, pvec, pv) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - unsafe { - assert_eq!( - wal - .get_by_bytes_or_insert_bytes(pvec, pv.as_bytes()) - .unwrap_left() - .value(), - pv - ); - } - } - - for (p, _, _) in &people { - assert!(wal.contains_key(p)); - assert!(wal.contains_key_by_ref(&p.as_ref())); - } -} - -#[test] -fn get_by_bytes_or_insert_bytes_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - get_by_bytes_or_insert_bytes(&mut wal); -} - -#[test] -fn get_by_bytes_or_insert_bytes_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - get_by_bytes_or_insert_bytes(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn get_by_bytes_or_insert_bytes_map_file() { - let dir = tempdir().unwrap(); - let path = dir - .path() - .join("generic_wal_get_by_bytes_or_insert_bytes_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - get_by_bytes_or_insert_bytes(&mut wal); -} - -fn zero_reserved(wal: &mut GenericOrderWal) { - unsafe { - assert_eq!(wal.reserved_slice(), &[]); - assert_eq!(wal.reserved_slice_mut(), &mut []); - - let wal = wal.reader(); - assert_eq!(wal.reserved_slice(), &[]); - } -} - -#[test] -fn zero_reserved_inmemory() { - let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); - zero_reserved(&mut wal); -} - -#[test] -fn zero_reserved_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); - zero_reserved(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn zero_reserved_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_zero_reserved_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new(), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - zero_reserved(&mut wal); -} - -fn reserved(wal: &mut GenericOrderWal) { - unsafe { - let buf = wal.reserved_slice_mut(); - buf.copy_from_slice(b"al8n"); - assert_eq!(wal.reserved_slice(), b"al8n"); - assert_eq!(wal.reserved_slice_mut(), b"al8n"); - - let wal = wal.reader(); - assert_eq!(wal.reserved_slice(), b"al8n"); - } -} - -#[test] -fn reserved_inmemory() { - let mut wal = - GenericOrderWal::::new(Options::new().with_capacity(MB).with_reserved(4)) - .unwrap(); - reserved(&mut wal); -} - -#[test] -fn reserved_map_anon() { - let mut wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB).with_reserved(4)) - .unwrap(); - reserved(&mut wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn reserved_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_reserved_map_file"); - - let mut wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new().with_reserved(4), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - reserved(&mut wal); -} - -fn concurrent_basic(mut w: GenericOrderWal) { - let readers = (0..100u32).map(|i| (i, w.reader())).collect::>(); - - let handles = readers.into_iter().map(|(i, reader)| { - spawn(move || loop { - if let Some(p) = reader.get(&i) { - assert_eq!(p.key(), i); - assert_eq!(p.value(), i.to_le_bytes()); - break; - } - }) - }); - - spawn(move || { - for i in 0..100u32 { - w.insert(&i, &i.to_le_bytes()).unwrap(); - } - }); - - for handle in handles { - handle.join().unwrap(); - } -} - -#[test] -fn concurrent_basic_inmemory() { - let wal = GenericOrderWal::::new(Options::new().with_capacity(MB).with_reserved(4)) - .unwrap(); - concurrent_basic(wal); -} - -#[test] -fn concurrent_basic_map_anon() { - let wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB).with_reserved(4)) - .unwrap(); - concurrent_basic(wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn concurrent_basic_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_concurrent_basic_map_file"); - - let wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new().with_reserved(4), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - concurrent_basic(wal); - - let wal = - unsafe { GenericOrderWal::::map(path, Options::new().with_reserved(4)).unwrap() }; - - for i in 0..100u32 { - assert!(wal.contains_key(&i)); - } -} - -fn concurrent_one_key(mut w: GenericOrderWal) { - let readers = (0..100u32).map(|i| (i, w.reader())).collect::>(); - let handles = readers.into_iter().map(|(_, reader)| { - spawn(move || loop { - if let Some(p) = reader.get(&1) { - assert_eq!(p.key(), 1); - assert_eq!(p.value(), 1u32.to_le_bytes()); - break; - } - }) - }); - - w.insert(&1, &1u32.to_le_bytes()).unwrap(); - - for handle in handles { - handle.join().unwrap(); - } -} - -#[test] -fn concurrent_one_key_inmemory() { - let wal = GenericOrderWal::::new(Options::new().with_capacity(MB).with_reserved(4)) - .unwrap(); - concurrent_one_key(wal); -} - -#[test] -fn concurrent_one_key_map_anon() { - let wal = - GenericOrderWal::::map_anon(Options::new().with_capacity(MB).with_reserved(4)) - .unwrap(); - concurrent_one_key(wal); -} - -#[test] -#[cfg_attr(miri, ignore)] -fn concurrent_one_key_map_file() { - let dir = tempdir().unwrap(); - let path = dir.path().join("generic_wal_concurrent_basic_map_file"); - - let wal = unsafe { - GenericOrderWal::::map_mut( - &path, - Options::new().with_reserved(4), - OpenOptions::new() - .create_new(Some(MB)) - .write(true) - .read(true), - ) - .unwrap() - }; - - concurrent_one_key(wal); - - let wal = - unsafe { GenericOrderWal::::map(path, Options::new().with_reserved(4)).unwrap() }; - - assert!(wal.contains_key(&1)); -} diff --git a/src/swmr/generic/tests/constructor.rs b/src/swmr/generic/tests/constructor.rs new file mode 100644 index 00000000..6ddd1b1c --- /dev/null +++ b/src/swmr/generic/tests/constructor.rs @@ -0,0 +1,322 @@ +use super::*; + +#[test] +fn owned_comparable() { + let p1 = Person { + id: 3127022870678870148, + name: "enthusiastic-magic".into(), + }; + let p2 = Person { + id: 9872687799307360216, + name: "damaged-friend".into(), + }; + + let p1bytes = p1.to_vec(); + let p2bytes = p2.to_vec(); + + let ptr1 = Pointer::::new(p1bytes.len(), 0, p1bytes.as_ptr()); + let ptr2 = Pointer::::new(p2bytes.len(), 0, p2bytes.as_ptr()); + + let map = SkipSet::new(); + map.insert(ptr1); + map.insert(ptr2); + + assert!(map.contains(&Owned::new(&p1))); + assert!(map.get(&Owned::new(&p1)).is_some()); + + assert!(map.contains(&Owned::new(&p2))); + assert!(map.get(&Owned::new(&p2)).is_some()); + + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + wal.insert(&p1, &"My name is Alice!".to_string()).unwrap(); + wal.insert(&p2, &"My name is Bob!".to_string()).unwrap(); + + assert!(wal.contains_key(&p1)); + assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); + + assert!(wal.contains_key(&p2)); + assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); +} + +#[test] +fn ref_comparable() { + let p1 = PersonRef { + id: 3127022870678870148, + name: "enthusiastic-magic", + }; + let p2 = PersonRef { + id: 9872687799307360216, + name: "damaged-friend", + }; + + let p1bytes = p1.to_vec(); + let p2bytes = p2.to_vec(); + + let ptr1 = Pointer::::new(p1bytes.len(), 0, p1bytes.as_ptr()); + let ptr2 = Pointer::::new(p2bytes.len(), 0, p2bytes.as_ptr()); + + let map = SkipSet::new(); + map.insert(ptr1); + map.insert(ptr2); + + assert!(map.contains(&Owned::new(&p1))); + assert!(map.get(&Owned::new(&p1)).is_some()); + + assert!(map.contains(&Owned::new(&p2))); + assert!(map.get(&Owned::new(&p2)).is_some()); + + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + + unsafe { + wal + .insert_key_bytes_with_value(&p1bytes, &"My name is Alice!".to_string()) + .unwrap(); + wal + .insert_key_bytes_with_value(&p2bytes, &"My name is Bob!".to_string()) + .unwrap(); + } + + assert!(wal.contains_key(&p1)); + assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); + + assert!(wal.contains_key(&p2)); + assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); + + assert!(wal.contains_key_by_ref(&p1)); + assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); + + assert!(wal.contains_key_by_ref(&p2)); + assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); + + unsafe { + assert!(wal.contains_key_by_bytes(&p1bytes)); + assert_eq!(wal.get(&p1).unwrap().value(), "My name is Alice!"); + + assert!(wal.contains_key_by_bytes(&p2bytes)); + assert_eq!(wal.get(&p2).unwrap().value(), "My name is Bob!"); + } +} + +#[test] +fn construct_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + + let person = Person { + id: 1, + name: "Alice".to_string(), + }; + + assert!(wal.is_empty()); + + wal + .insert(&person, &"My name is Alice!".to_string()) + .unwrap(); + + let wal = wal.reader(); + + assert_eq!(wal.len(), 1); + assert!(!wal.is_empty()); +} + +#[test] +fn construct_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + + let person = Person { + id: 1, + name: "Alice".to_string(), + }; + + wal + .insert(&person, &"My name is Alice!".to_string()) + .unwrap(); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn construct_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_construct_map_file"); + + unsafe { + let mut wal = GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap(); + let person = Person { + id: 1, + name: "Alice".to_string(), + }; + + wal + .insert(&person, &"My name is Alice!".to_string()) + .unwrap(); + assert_eq!(wal.get(&person).unwrap().value(), "My name is Alice!"); + + assert_eq!(*wal.path().unwrap().as_ref(), path); + } + + let pr = PersonRef { + id: 1, + name: "Alice", + }; + + unsafe { + let wal = GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new().create(Some(MB)).write(true).read(true), + ) + .unwrap(); + assert_eq!(wal.get(&pr).unwrap().value(), "My name is Alice!"); + } + + let wal = unsafe { GenericOrderWal::::map(&path, Options::new()).unwrap() }; + assert_eq!(wal.get(&pr).unwrap().value(), "My name is Alice!"); +} + +#[test] +fn construct_with_small_capacity_inmemory() { + let wal = GenericOrderWal::::new(Options::new().with_capacity(1)); + + assert!(wal.is_err()); + match wal { + Err(e) => println!("error: {:?}", e), + _ => panic!("unexpected error"), + } +} + +#[test] +fn construct_with_small_capacity_map_anon() { + let wal = GenericOrderWal::::map_anon(Options::new().with_capacity(1)); + + assert!(wal.is_err()); + match wal { + Err(e) => println!("error: {:?}", e), + _ => panic!("unexpected error"), + } +} + +#[test] +fn construct_with_small_capacity_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_construct_with_small_capacity_map_file"); + + let wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(1)) + .write(true) + .read(true), + ) + }; + + assert!(wal.is_err()); + match wal { + Err(e) => println!("{:?}", e), + _ => panic!("unexpected error"), + } +} + +fn zero_reserved(wal: &mut GenericOrderWal) { + unsafe { + assert_eq!(wal.reserved_slice(), &[]); + assert_eq!(wal.reserved_slice_mut(), &mut []); + + let wal = wal.reader(); + assert_eq!(wal.reserved_slice(), &[]); + } +} + +#[test] +fn zero_reserved_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + zero_reserved(&mut wal); +} + +#[test] +fn zero_reserved_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + zero_reserved(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn zero_reserved_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_zero_reserved_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + zero_reserved(&mut wal); +} + +fn reserved(wal: &mut GenericOrderWal) { + unsafe { + let buf = wal.reserved_slice_mut(); + buf.copy_from_slice(b"al8n"); + assert_eq!(wal.reserved_slice(), b"al8n"); + assert_eq!(wal.reserved_slice_mut(), b"al8n"); + + let wal = wal.reader(); + assert_eq!(wal.reserved_slice(), b"al8n"); + } +} + +#[test] +fn reserved_inmemory() { + let mut wal = + GenericOrderWal::::new(Options::new().with_capacity(MB).with_reserved(4)) + .unwrap(); + reserved(&mut wal); +} + +#[test] +fn reserved_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB).with_reserved(4)) + .unwrap(); + reserved(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn reserved_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_reserved_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new().with_reserved(4), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + reserved(&mut wal); +} diff --git a/src/swmr/generic/tests/get.rs b/src/swmr/generic/tests/get.rs new file mode 100644 index 00000000..c6df9581 --- /dev/null +++ b/src/swmr/generic/tests/get.rs @@ -0,0 +1,538 @@ +use super::*; + +fn first(wal: &mut GenericOrderWal) { + let people = (0..10) + .map(|_| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + wal.insert(&p, &v).unwrap(); + + (p, v) + }) + .collect::>(); + + let ent = wal.first().unwrap(); + let (p, v) = people.first_key_value().unwrap(); + assert!(ent.key().equivalent(p)); + assert_eq!(ent.value(), v); + + let wal = wal.reader().clone(); + let ent = wal.first().unwrap(); + let (p, v) = people.first_key_value().unwrap(); + assert!(ent.key().equivalent(p)); + assert_eq!(ent.value(), v); +} + +#[test] +fn first_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + first(&mut wal); +} + +#[test] +fn first_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + first(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn first_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_first_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + first(&mut wal); +} + +fn last(wal: &mut GenericOrderWal) { + let people = (0..10) + .map(|_| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + wal.insert(&p, &v).unwrap(); + + (p, v) + }) + .collect::>(); + + let ent = wal.last().unwrap(); + let (p, v) = people.last_key_value().unwrap(); + assert!(ent.key().equivalent(p)); + assert_eq!(ent.value(), v); + + let wal = wal.reader(); + let ent = wal.last().unwrap(); + assert!(ent.key().equivalent(p)); + assert_eq!(ent.value(), v); +} + +#[test] +fn last_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + last(&mut wal); +} + +#[test] +fn last_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + last(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn last_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_last_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + last(&mut wal); +} + +fn get_or_insert(wal: &mut GenericOrderWal) { + let people = (0..100) + .map(|_| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + wal.get_or_insert(&p, &v).unwrap_right().unwrap(); + (p, v) + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for (p, pv) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + assert_eq!( + wal + .get_or_insert(p, &format!("Hello! {}!", p.name)) + .unwrap_left() + .value(), + pv + ); + } + + for (p, _) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + } +} + +#[test] +fn get_or_insert_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + get_or_insert(&mut wal); +} + +#[test] +fn get_or_insert_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + get_or_insert(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn get_or_insert_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_get_or_insert_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + get_or_insert(&mut wal); +} + +fn get_or_insert_with(wal: &mut GenericOrderWal) { + let people = (0..100) + .map(|_| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + wal + .get_or_insert_with(&p, || v.clone()) + .unwrap_right() + .unwrap(); + (p, v) + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for (p, pv) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + assert_eq!( + wal + .get_or_insert_with(p, || format!("Hello! {}!", p.name)) + .unwrap_left() + .value(), + pv + ); + } + + for (p, _) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + } +} + +#[test] +fn get_or_insert_with_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + get_or_insert_with(&mut wal); +} + +#[test] +fn get_or_insert_with_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + get_or_insert_with(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn get_or_insert_with_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_get_or_insert_with_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + get_or_insert_with(&mut wal); +} + +fn get_or_insert_key_with_value_bytes(wal: &mut GenericOrderWal) { + let people = (0..100) + .map(|_| { + let p = Person::random(); + let pvec = p.to_vec(); + let v = format!("My name is {}", p.name); + unsafe { + wal + .get_by_bytes_or_insert(pvec.as_ref(), &v) + .unwrap_right() + .unwrap(); + } + (p, v) + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for (p, pv) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + assert_eq!( + wal + .get_or_insert(p, &format!("Hello! {}!", p.name)) + .unwrap_left() + .value(), + pv + ); + } + + for (p, _) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + } +} + +#[test] +fn get_or_insert_key_with_value_bytes_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + get_or_insert_key_with_value_bytes(&mut wal); +} + +#[test] +fn get_or_insert_key_with_value_bytes_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + get_or_insert_key_with_value_bytes(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn get_or_insert_key_with_value_bytes_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_get_or_insert_key_with_value_bytes_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + get_or_insert_key_with_value_bytes(&mut wal); +} + +fn get_or_insert_value_bytes(wal: &mut GenericOrderWal) { + let people = (0..100) + .map(|_| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + unsafe { + wal + .get_or_insert_bytes(&p, v.as_bytes()) + .unwrap_right() + .unwrap(); + } + (p, v) + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for (p, pv) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + unsafe { + assert_eq!( + wal + .get_or_insert_bytes(p, pv.as_bytes()) + .unwrap_left() + .value(), + pv + ); + } + } + + for (p, _) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + } +} + +#[test] +fn get_or_insert_value_bytes_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + get_or_insert_value_bytes(&mut wal); +} + +#[test] +fn get_or_insert_value_bytes_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + get_or_insert_value_bytes(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn get_or_insert_value_bytes_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_get_or_insert_value_bytes_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + get_or_insert_value_bytes(&mut wal); +} + +fn get_by_bytes_or_insert_with(wal: &mut GenericOrderWal) { + let people = (0..100) + .map(|_| { + let p = Person::random(); + let pvec = p.to_vec(); + let v = format!("My name is {}", p.name); + unsafe { + wal + .get_by_bytes_or_insert_with(pvec.as_ref(), || v.clone()) + .unwrap_right() + .unwrap(); + } + (p, pvec, v) + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for (p, pvec, pv) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + unsafe { + assert_eq!( + wal + .get_by_bytes_or_insert_with(pvec, || format!("Hello! {}!", p.name)) + .unwrap_left() + .value(), + pv + ); + } + } + + for (p, _, _) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + } +} + +#[test] +fn get_by_bytes_or_insert_with_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + get_by_bytes_or_insert_with(&mut wal); +} + +#[test] +fn get_by_bytes_or_insert_with_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + get_by_bytes_or_insert_with(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn get_by_bytes_or_insert_with_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_get_by_bytes_or_insert_with_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + get_by_bytes_or_insert_with(&mut wal); +} + +fn get_by_bytes_or_insert_bytes(wal: &mut GenericOrderWal) { + let people = (0..100) + .map(|_| { + let p = Person::random(); + let pvec = p.to_vec(); + let v = format!("My name is {}", p.name); + unsafe { + wal + .get_by_bytes_or_insert_bytes(pvec.as_ref(), v.as_bytes()) + .unwrap_right() + .unwrap(); + } + (p, pvec, v) + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for (p, pvec, pv) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + unsafe { + assert_eq!( + wal + .get_by_bytes_or_insert_bytes(pvec, pv.as_bytes()) + .unwrap_left() + .value(), + pv + ); + } + } + + for (p, _, _) in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + } +} + +#[test] +fn get_by_bytes_or_insert_bytes_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + get_by_bytes_or_insert_bytes(&mut wal); +} + +#[test] +fn get_by_bytes_or_insert_bytes_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + get_by_bytes_or_insert_bytes(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn get_by_bytes_or_insert_bytes_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_get_by_bytes_or_insert_bytes_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + get_by_bytes_or_insert_bytes(&mut wal); +} diff --git a/src/swmr/generic/tests/insert.rs b/src/swmr/generic/tests/insert.rs new file mode 100644 index 00000000..ced2c1d6 --- /dev/null +++ b/src/swmr/generic/tests/insert.rs @@ -0,0 +1,502 @@ +use super::*; + +fn insert_to_full(wal: &mut GenericOrderWal) { + let mut full = false; + for _ in 0u32.. { + let p = Person::random(); + match wal.insert(&p, &format!("My name is {}", p.name)) { + Ok(_) => {} + Err(e) => match e { + Among::Right(Error::InsufficientSpace { .. }) => { + full = true; + break; + } + _ => panic!("unexpected error"), + }, + } + } + assert!(full); +} + +#[test] +fn insert_to_full_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + insert_to_full(&mut wal); +} + +#[test] +fn insert_to_full_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + insert_to_full(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn insert_to_full_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_insert_to_full_map_file"); + + unsafe { + let mut wal = GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap(); + insert_to_full(&mut wal); + } +} + +fn insert(wal: &mut GenericOrderWal) -> Vec { + let people = (0..100) + .map(|_| { + let p = Person::random(); + wal.insert(&p, &format!("My name is {}", p.name)).unwrap(); + p + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for p in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + assert_eq!( + wal.get(p).unwrap().value(), + format!("My name is {}", p.name) + ); + } + + people +} + +#[test] +fn insert_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + insert(&mut wal); +} + +#[test] +fn insert_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + insert(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn insert_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_insert_map_file"); + + let people = unsafe { + let mut wal = GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap(); + insert(&mut wal) + }; + + let wal = unsafe { GenericOrderWal::::map(&path, Options::new()).unwrap() }; + + for p in people { + assert!(wal.contains_key(&p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + assert_eq!( + wal.get(&p).unwrap().value(), + format!("My name is {}", p.name) + ); + } +} + +fn insert_key_bytes_with_value( + wal: &mut GenericOrderWal, +) -> Vec<(Vec, Person)> { + let people = (0..100) + .map(|_| { + let p = Person::random(); + let pbytes = p.to_vec(); + unsafe { + wal + .insert_key_bytes_with_value(&pbytes, &format!("My name is {}", p.name)) + .unwrap(); + } + (pbytes, p) + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for (pbytes, p) in &people { + assert!(wal.contains_key(p)); + unsafe { + assert!(wal.contains_key_by_bytes(pbytes)); + } + assert_eq!( + wal.get(p).unwrap().value(), + format!("My name is {}", p.name) + ); + + assert_eq!( + unsafe { wal.get_by_bytes(pbytes).unwrap().value() }, + format!("My name is {}", p.name) + ); + } + + people +} + +#[test] +fn insert_key_bytes_with_value_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + insert_key_bytes_with_value(&mut wal); +} + +#[test] +fn insert_key_bytes_with_value_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + insert_key_bytes_with_value(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn insert_key_bytes_with_value_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_insert_key_bytes_with_value_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + let people = insert_key_bytes_with_value(&mut wal); + + let wal = wal.reader(); + + for (pbytes, p) in &people { + assert!(wal.contains_key(p)); + unsafe { + assert!(wal.contains_key_by_bytes(pbytes)); + } + assert_eq!( + wal.get(p).unwrap().value(), + format!("My name is {}", p.name) + ); + assert_eq!( + unsafe { wal.get_by_bytes(pbytes).unwrap().value() }, + format!("My name is {}", p.name) + ); + } + + let wal = unsafe { GenericOrderWal::::map(&path, Options::new()).unwrap() }; + + for (pbytes, p) in people { + assert!(wal.contains_key(&p)); + unsafe { + assert!(wal.contains_key_by_bytes(&pbytes)); + } + assert_eq!( + wal.get(&p).unwrap().value(), + format!("My name is {}", p.name) + ); + assert_eq!( + unsafe { wal.get_by_bytes(&pbytes).unwrap().value() }, + format!("My name is {}", p.name) + ); + } +} + +fn insert_key_with_value_bytes(wal: &mut GenericOrderWal) -> Vec { + let people = (0..100) + .map(|_| { + let p = Person::random(); + unsafe { + wal + .insert_key_with_value_bytes(&p, format!("My name is {}", p.name).as_bytes()) + .unwrap(); + } + p + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for p in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + assert_eq!( + wal.get_by_ref(p).unwrap().value(), + format!("My name is {}", p.name) + ); + } + + people +} + +#[test] +fn insert_key_with_value_bytes_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + insert_key_with_value_bytes(&mut wal); +} + +#[test] +fn insert_key_with_value_bytes_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + insert_key_with_value_bytes(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn insert_key_with_value_bytes_map_file() { + let dir = tempdir().unwrap(); + let path = dir + .path() + .join("generic_wal_insert_key_with_value_bytes_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + let people = insert_key_with_value_bytes(&mut wal); + let wal = wal.reader(); + + for p in &people { + assert!(wal.contains_key(p)); + assert!(wal.contains_key_by_ref(&p.as_ref())); + assert_eq!( + wal.get_by_ref(p).unwrap().value(), + format!("My name is {}", p.name) + ); + } +} + +fn insert_bytes(wal: &mut GenericOrderWal) -> Vec { + let people = (0..100) + .map(|_| { + let p = Person::random(); + let pbytes = p.to_vec(); + unsafe { + wal + .insert_bytes(&pbytes, format!("My name is {}", p.name).as_bytes()) + .unwrap(); + } + p + }) + .collect::>(); + + assert_eq!(wal.len(), 100); + + for p in &people { + assert!(wal.contains_key(p)); + unsafe { + assert!(wal.contains_key_by_bytes(&p.to_vec())); + } + assert_eq!( + wal.get(p).unwrap().value(), + format!("My name is {}", p.name) + ); + } + + people +} + +#[test] +fn insert_bytes_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + insert_bytes(&mut wal); +} + +#[test] +fn insert_bytes_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + insert_bytes(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn insert_bytes_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_insert_bytes_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + let people = insert_bytes(&mut wal); + + let wal = wal.reader(); + + for p in &people { + assert!(wal.contains_key(p)); + unsafe { + assert!(wal.contains_key_by_bytes(&p.to_vec())); + } + assert_eq!( + wal.get(p).unwrap().value(), + format!("My name is {}", p.name) + ); + } +} + +fn concurrent_basic(mut w: GenericOrderWal) { + let readers = (0..100u32).map(|i| (i, w.reader())).collect::>(); + + let handles = readers.into_iter().map(|(i, reader)| { + spawn(move || loop { + if let Some(p) = reader.get(&i) { + assert_eq!(p.key(), i); + assert_eq!(p.value(), i.to_le_bytes()); + break; + } + }) + }); + + spawn(move || { + for i in 0..100u32 { + w.insert(&i, &i.to_le_bytes()).unwrap(); + } + }); + + for handle in handles { + handle.join().unwrap(); + } +} + +#[test] +fn concurrent_basic_inmemory() { + let wal = GenericOrderWal::::new(Options::new().with_capacity(MB).with_reserved(4)) + .unwrap(); + concurrent_basic(wal); +} + +#[test] +fn concurrent_basic_map_anon() { + let wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB).with_reserved(4)) + .unwrap(); + concurrent_basic(wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn concurrent_basic_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_concurrent_basic_map_file"); + + let wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new().with_reserved(4), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + concurrent_basic(wal); + + let wal = + unsafe { GenericOrderWal::::map(path, Options::new().with_reserved(4)).unwrap() }; + + for i in 0..100u32 { + assert!(wal.contains_key(&i)); + } +} + +fn concurrent_one_key(mut w: GenericOrderWal) { + let readers = (0..100u32).map(|i| (i, w.reader())).collect::>(); + let handles = readers.into_iter().map(|(_, reader)| { + spawn(move || loop { + if let Some(p) = reader.get(&1) { + assert_eq!(p.key(), 1); + assert_eq!(p.value(), 1u32.to_le_bytes()); + break; + } + }) + }); + + w.insert(&1, &1u32.to_le_bytes()).unwrap(); + + for handle in handles { + handle.join().unwrap(); + } +} + +#[test] +fn concurrent_one_key_inmemory() { + let wal = GenericOrderWal::::new(Options::new().with_capacity(MB).with_reserved(4)) + .unwrap(); + concurrent_one_key(wal); +} + +#[test] +fn concurrent_one_key_map_anon() { + let wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB).with_reserved(4)) + .unwrap(); + concurrent_one_key(wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn concurrent_one_key_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_concurrent_basic_map_file"); + + let wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new().with_reserved(4), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + concurrent_one_key(wal); + + let wal = + unsafe { GenericOrderWal::::map(path, Options::new().with_reserved(4)).unwrap() }; + + assert!(wal.contains_key(&1)); +} diff --git a/src/swmr/generic/tests/iters.rs b/src/swmr/generic/tests/iters.rs new file mode 100644 index 00000000..33702369 --- /dev/null +++ b/src/swmr/generic/tests/iters.rs @@ -0,0 +1,223 @@ +use super::*; + +fn iter(wal: &mut GenericOrderWal) -> Vec<(Person, String)> { + let mut people = (0..100) + .map(|_| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + wal.insert(&p, &v).unwrap(); + (p, v) + }) + .collect::>(); + + people.sort_by(|a, b| a.0.cmp(&b.0)); + + let mut iter = wal.iter(); + + for (pwal, pvec) in people.iter().zip(iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } + + let mut rev_iter = wal.iter().rev(); + + for (pwal, pvec) in people.iter().rev().zip(rev_iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } + + people +} + +#[test] +fn iter_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + iter(&mut wal); +} + +#[test] +fn iter_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + iter(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn iter_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_iter_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + let people = iter(&mut wal); + + let wal = wal.reader(); + let mut iter = wal.iter(); + + for (pwal, pvec) in people.iter().zip(iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } +} + +fn range(wal: &mut GenericOrderWal) { + let mut mid = Person::random(); + let people = (0..100) + .map(|idx| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + wal.insert(&p, &v).unwrap(); + + if idx == 500 { + mid = p.clone(); + } + (p, v) + }) + .collect::>(); + + let mut iter = wal.range(Bound::Included(&mid), Bound::Unbounded); + + for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } + + assert!(iter.next().is_none()); + + let wal = wal.reader(); + let mut iter = wal.range(Bound::Included(&mid), Bound::Unbounded); + + for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } + + let mut rev_iter = wal.range(Bound::Included(&mid), Bound::Unbounded).rev(); + + for (pwal, pvec) in people.range(&mid..).rev().zip(rev_iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } +} + +#[test] +fn range_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + range(&mut wal); +} + +#[test] +fn range_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + range(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn range_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_range_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + range(&mut wal); +} + +fn range_ref(wal: &mut GenericOrderWal) { + let mut mid = Person::random(); + let people = (0..100) + .map(|idx| { + let p = Person::random(); + let v = format!("My name is {}", p.name); + wal.insert(&p, &v).unwrap(); + + if idx == 500 { + mid = p.clone(); + } + (p, v) + }) + .collect::>(); + + let mid_ref = mid.as_ref(); + let mut iter = wal.range_by_ref(Bound::Included(&mid_ref), Bound::Unbounded); + + for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } + + assert!(iter.next().is_none()); + + let wal = wal.reader(); + let mut iter = wal.range_by_ref(Bound::Included(&mid), Bound::Unbounded); + + for (pwal, pvec) in people.range(&mid..).zip(iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } + + let mut rev_iter = wal + .range_by_ref(Bound::Included(&mid), Bound::Unbounded) + .rev(); + + for (pwal, pvec) in people.range(&mid..).rev().zip(rev_iter.by_ref()) { + assert!(pwal.0.equivalent(&pvec.key())); + assert_eq!(pwal.1, pvec.value()); + } +} + +#[test] +fn range_ref_inmemory() { + let mut wal = GenericOrderWal::::new(Options::new().with_capacity(MB)).unwrap(); + range(&mut wal); +} + +#[test] +fn range_ref_map_anon() { + let mut wal = + GenericOrderWal::::map_anon(Options::new().with_capacity(MB)).unwrap(); + range_ref(&mut wal); +} + +#[test] +#[cfg_attr(miri, ignore)] +fn range_ref_map_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("generic_wal_range_map_file"); + + let mut wal = unsafe { + GenericOrderWal::::map_mut( + &path, + Options::new(), + OpenOptions::new() + .create_new(Some(MB)) + .write(true) + .read(true), + ) + .unwrap() + }; + + range_ref(&mut wal); +} diff --git a/src/swmr/wal.rs b/src/swmr/wal.rs index b0b10e06..ded2db45 100644 --- a/src/swmr/wal.rs +++ b/src/swmr/wal.rs @@ -18,7 +18,7 @@ pub use reader::*; mod iter; pub use iter::*; -#[cfg(all(test, feature = "test-swmr"))] +#[cfg(test)] mod tests; pub struct OrderWalCore { @@ -204,11 +204,11 @@ where } impl OrderWal { - /// Returns the read-only view for the WAL. - #[inline] - pub fn reader(&self) -> OrderWalReader { - OrderWalReader::new(self.core.clone()) - } + // /// Returns the read-only view for the WAL. + // #[inline] + // pub fn reader(&self) -> OrderWalReader { + // OrderWalReader::new(self.core.clone()) + // } /// Returns the path of the WAL if it is backed by a file. pub fn path_buf(&self) -> Option<&std::sync::Arc> { @@ -262,11 +262,6 @@ where self.core.arena.path().map(|p| p.as_ref().as_path()) } - #[inline] - fn read_only(&self) -> bool { - self.ro - } - #[inline] fn len(&self) -> usize { self.core.map.len() @@ -390,6 +385,16 @@ where { type Reader = OrderWalReader; + #[inline] + fn read_only(&self) -> bool { + self.ro + } + + #[inline] + fn reader(&self) -> Self::Reader { + OrderWalReader::new(self.core.clone()) + } + #[inline] fn flush(&self) -> Result<(), Error> { if self.ro { diff --git a/src/swmr/wal/iter.rs b/src/swmr/wal/iter.rs index ddc82447..b69a583a 100644 --- a/src/swmr/wal/iter.rs +++ b/src/swmr/wal/iter.rs @@ -27,11 +27,6 @@ impl<'a, C: Comparator> Iterator for Iter<'a, C> { .next() .map(|ptr| (ptr.as_key_slice(), ptr.as_value_slice())) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C: Comparator> DoubleEndedIterator for Iter<'a, C> { @@ -63,11 +58,6 @@ impl<'a, C: Comparator> Iterator for Keys<'a, C> { fn next(&mut self) -> Option { self.iter.next().map(|ptr| ptr.as_key_slice()) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C: Comparator> DoubleEndedIterator for Keys<'a, C> { @@ -96,11 +86,6 @@ impl<'a, C: Comparator> Iterator for Values<'a, C> { fn next(&mut self) -> Option { self.iter.next().map(|ptr| ptr.as_value_slice()) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C: Comparator> DoubleEndedIterator for Values<'a, C> { @@ -150,11 +135,6 @@ where .next() .map(|ptr| (ptr.as_key_slice(), ptr.as_value_slice())) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, Q, R, C> DoubleEndedIterator for Range<'a, Q, R, C> @@ -210,11 +190,6 @@ where fn next(&mut self) -> Option { self.iter.next().map(|ptr| ptr.as_key_slice()) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, Q, R, C> DoubleEndedIterator for RangeKeys<'a, Q, R, C> @@ -267,11 +242,6 @@ where fn next(&mut self) -> Option { self.iter.next().map(|ptr| ptr.as_value_slice()) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, Q, R, C> DoubleEndedIterator for RangeValues<'a, Q, R, C> diff --git a/src/swmr/wal/reader.rs b/src/swmr/wal/reader.rs index 4fb3ae2a..6164cbc7 100644 --- a/src/swmr/wal/reader.rs +++ b/src/swmr/wal/reader.rs @@ -68,11 +68,6 @@ impl ImmutableWal for OrderWalReader { self.0.path() } - #[inline] - fn read_only(&self) -> bool { - self.0.read_only() - } - #[inline] fn len(&self) -> usize { self.0.len() diff --git a/src/swmr/wal/tests.rs b/src/swmr/wal/tests.rs index ee8b5ca0..ac8c4f63 100644 --- a/src/swmr/wal/tests.rs +++ b/src/swmr/wal/tests.rs @@ -4,6 +4,16 @@ use crate::tests::*; use super::*; -const MB: u32 = 1024 * 1024; +#[cfg(all(test, feature = "test-swmr-constructor"))] +mod constructor; + +#[cfg(all(test, feature = "test-swmr-insert"))] +mod insert; + +#[cfg(all(test, feature = "test-swmr-iters"))] +mod iter; -common_unittests!(swmr::OrderWal); +#[cfg(all(test, feature = "test-swmr-get"))] +mod get; + +const MB: u32 = 1024 * 1024; diff --git a/src/swmr/wal/tests/constructor.rs b/src/swmr/wal/tests/constructor.rs new file mode 100644 index 00000000..03e864a3 --- /dev/null +++ b/src/swmr/wal/tests/constructor.rs @@ -0,0 +1,3 @@ +use super::*; + +common_unittests!(unsync::constructor::OrderWal); diff --git a/src/swmr/wal/tests/get.rs b/src/swmr/wal/tests/get.rs new file mode 100644 index 00000000..c9eefcf8 --- /dev/null +++ b/src/swmr/wal/tests/get.rs @@ -0,0 +1,3 @@ +use super::*; + +common_unittests!(unsync::get::OrderWal); diff --git a/src/swmr/wal/tests/insert.rs b/src/swmr/wal/tests/insert.rs new file mode 100644 index 00000000..6aacd454 --- /dev/null +++ b/src/swmr/wal/tests/insert.rs @@ -0,0 +1,3 @@ +use super::*; + +common_unittests!(unsync::insert::OrderWal); diff --git a/src/swmr/wal/tests/iter.rs b/src/swmr/wal/tests/iter.rs new file mode 100644 index 00000000..f20d78e8 --- /dev/null +++ b/src/swmr/wal/tests/iter.rs @@ -0,0 +1,3 @@ +use super::*; + +common_unittests!(unsync::iters::OrderWal); diff --git a/src/tests.rs b/src/tests.rs index 424dee32..aecb18de 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -7,40 +7,8 @@ use wal::ImmutableWal; const MB: usize = 1024 * 1024; macro_rules! common_unittests { - ($prefix:ident::$wal:ident) => { + ($prefix:ident::insert::$wal:ident) => { paste::paste! { - #[test] - fn test_construct_inmemory() { - construct_inmemory::>(); - } - - #[test] - fn test_construct_map_anon() { - construct_map_anon::>(); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_construct_map_file() { - construct_map_file::>(stringify!($prefix)); - } - - #[test] - fn test_construct_with_small_capacity_inmemory() { - construct_with_small_capacity_inmemory::>(); - } - - #[test] - fn test_construct_with_small_capacity_map_anon() { - construct_with_small_capacity_map_anon::>(); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_construct_with_small_capacity_map_file() { - construct_with_small_capacity_map_file::>(stringify!($prefix)); - } - #[test] fn test_insert_to_full_inmemory() { insert_to_full(&mut OrderWal::new(Builder::new().with_capacity(MB)).unwrap()); @@ -175,7 +143,10 @@ macro_rules! common_unittests { .unwrap() }, ); } - + } + }; + ($prefix:ident::iters::$wal:ident) => { + paste::paste! { #[test] fn test_iter_inmemory() { iter(&mut OrderWal::new(Builder::new().with_capacity(MB)).unwrap()); @@ -337,7 +308,10 @@ macro_rules! common_unittests { .unwrap() }, ); } - + } + }; + ($prefix:ident::get::$wal:ident) => { + paste::paste! { #[test] fn test_first_inmemory() { first(&mut OrderWal::new(Builder::new().with_capacity(MB)).unwrap()); @@ -456,6 +430,41 @@ macro_rules! common_unittests { assert_eq!(wal.path().unwrap(), path); } + } + }; + ($prefix:ident::constructor::$wal:ident) => { + paste::paste! { + #[test] + fn test_construct_inmemory() { + construct_inmemory::>(); + } + + #[test] + fn test_construct_map_anon() { + construct_map_anon::>(); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn test_construct_map_file() { + construct_map_file::>(stringify!($prefix)); + } + + #[test] + fn test_construct_with_small_capacity_inmemory() { + construct_with_small_capacity_inmemory::>(); + } + + #[test] + fn test_construct_with_small_capacity_map_anon() { + construct_with_small_capacity_map_anon::>(); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn test_construct_with_small_capacity_map_file() { + construct_with_small_capacity_map_file::>(stringify!($prefix)); + } #[test] fn test_zero_reserved_inmemory() { @@ -559,10 +568,17 @@ pub(crate) fn construct_map_file>(prefix: &str) { .unwrap(); assert_eq!(wal.get(b"key1").unwrap(), b"value1"); + assert!(!wal.read_only()); } let wal = unsafe { W::map(&path, Builder::new()).unwrap() }; assert_eq!(wal.get(b"key1").unwrap(), b"value1"); + assert_eq!(wal.path().unwrap(), path); + assert_eq!(wal.maximum_key_size(), Options::new().maximum_key_size()); + assert_eq!( + wal.maximum_value_size(), + Options::new().maximum_value_size() + ); } pub(crate) fn construct_with_small_capacity_inmemory>() { @@ -631,6 +647,16 @@ pub(crate) fn insert>(wal: &mut W) { wal.insert(&i.to_be_bytes(), &i.to_be_bytes()).unwrap(); } + assert!(!wal.is_empty()); + assert_eq!(wal.len(), 100); + + for i in 0..100u32 { + assert!(wal.contains_key(&i.to_be_bytes())); + assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); + } + + let wal = wal.reader(); + assert!(!wal.is_empty()); assert_eq!(wal.len(), 100); for i in 0..100u32 { @@ -655,6 +681,11 @@ pub(crate) fn insert_with_key_builder>(wal: &mut W) { for i in 0..100u32 { assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); } + + let wal = wal.reader(); + for i in 0..100u32 { + assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); + } } pub(crate) fn insert_with_value_builder>(wal: &mut W) { @@ -673,6 +704,11 @@ pub(crate) fn insert_with_value_builder>(wal: &mut W) { for i in 0..100u32 { assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); } + + let wal = wal.reader(); + for i in 0..100u32 { + assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); + } } pub(crate) fn insert_with_builders>(wal: &mut W) { @@ -694,6 +730,11 @@ pub(crate) fn insert_with_builders>(wal: &mut W) { for i in 0..100u32 { assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); } + + let wal = wal.reader(); + for i in 0..100u32 { + assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); + } } pub(crate) fn iter>(wal: &mut W) { @@ -702,11 +743,35 @@ pub(crate) fn iter>(wal: &mut W) { } let mut iter = wal.iter(); + + for i in 0..100u32 { + let (key, value) = iter.next().unwrap(); + assert_eq!(key, i.to_be_bytes()); + assert_eq!(value, i.to_be_bytes()); + } + + let mut iter = wal.iter(); + for i in (0..100u32).rev() { + let (key, value) = iter.next_back().unwrap(); + assert_eq!(key, i.to_be_bytes()); + assert_eq!(value, i.to_be_bytes()); + } + + let wal = wal.reader(); + let mut iter = wal.iter(); + for i in 0..100u32 { let (key, value) = iter.next().unwrap(); assert_eq!(key, i.to_be_bytes()); assert_eq!(value, i.to_be_bytes()); } + + let mut iter = wal.iter(); + for i in (0..100u32).rev() { + let (key, value) = iter.next_back().unwrap(); + assert_eq!(key, i.to_be_bytes()); + assert_eq!(value, i.to_be_bytes()); + } } pub(crate) fn range>(wal: &mut W) { @@ -724,6 +789,31 @@ pub(crate) fn range>(wal: &mut W) { } assert!(iter.next().is_none()); + + let mut iter = wal.range((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in (50..100u32).rev() { + let (key, value) = iter.next_back().unwrap(); + assert_eq!(key, i.to_be_bytes()); + assert_eq!(value, i.to_be_bytes()); + } + + let wal = wal.reader(); + + let mut iter = wal.range((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in 50..100u32 { + let (key, value) = iter.next().unwrap(); + assert_eq!(key, i.to_be_bytes()); + assert_eq!(value, i.to_be_bytes()); + } + + assert!(iter.next().is_none()); + + let mut iter = wal.range((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in (50..100u32).rev() { + let (key, value) = iter.next_back().unwrap(); + assert_eq!(key, i.to_be_bytes()); + assert_eq!(value, i.to_be_bytes()); + } } pub(crate) fn keys>(wal: &mut W) { @@ -732,10 +822,35 @@ pub(crate) fn keys>(wal: &mut W) { } let mut iter = wal.keys(); + + for i in 0..100u32 { + let key = iter.next().unwrap(); + assert_eq!(key, i.to_be_bytes()); + } + + assert!(iter.next().is_none()); + + let mut iter = wal.keys(); + for i in (0..100u32).rev() { + let key = iter.next_back().unwrap(); + assert_eq!(key, i.to_be_bytes()); + } + + let wal = wal.reader(); + let mut iter = wal.keys(); + for i in 0..100u32 { let key = iter.next().unwrap(); assert_eq!(key, i.to_be_bytes()); } + + assert!(iter.next().is_none()); + + let mut iter = wal.keys(); + for i in (0..100u32).rev() { + let key = iter.next_back().unwrap(); + assert_eq!(key, i.to_be_bytes()); + } } pub(crate) fn range_keys>(wal: &mut W) { @@ -752,6 +867,27 @@ pub(crate) fn range_keys>(wal: &mut W) { } assert!(iter.next().is_none()); + + let mut iter = wal.range_keys((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in (50..100u32).rev() { + let key = iter.next_back().unwrap(); + assert_eq!(key, i.to_be_bytes()); + } + + let wal = wal.reader(); + let mut iter = wal.range_keys((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in 50..100u32 { + let key = iter.next().unwrap(); + assert_eq!(key, i.to_be_bytes()); + } + + assert!(iter.next().is_none()); + + let mut iter = wal.range_keys((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in (50..100u32).rev() { + let key = iter.next_back().unwrap(); + assert_eq!(key, i.to_be_bytes()); + } } pub(crate) fn values>(wal: &mut W) { @@ -760,10 +896,35 @@ pub(crate) fn values>(wal: &mut W) { } let mut iter = wal.values(); + + for i in 0..100u32 { + let value = iter.next().unwrap(); + assert_eq!(value, i.to_be_bytes()); + } + + assert!(iter.next().is_none()); + + let mut iter = wal.values(); + for i in (0..100u32).rev() { + let value = iter.next_back().unwrap(); + assert_eq!(value, i.to_be_bytes()); + } + + let wal = wal.reader(); + let mut iter = wal.values(); + for i in 0..100u32 { let value = iter.next().unwrap(); assert_eq!(value, i.to_be_bytes()); } + + assert!(iter.next().is_none()); + + let mut iter = wal.values(); + for i in (0..100u32).rev() { + let value = iter.next_back().unwrap(); + assert_eq!(value, i.to_be_bytes()); + } } pub(crate) fn range_values>(wal: &mut W) { @@ -774,12 +935,34 @@ pub(crate) fn range_values>(wal: &mut W) { let x = 50u32.to_be_bytes(); let mut iter = wal.range_values((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in 50..100u32 { let value = iter.next().unwrap(); assert_eq!(value, i.to_be_bytes()); } assert!(iter.next().is_none()); + + let mut iter = wal.range_values((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in (50..100u32).rev() { + let value = iter.next_back().unwrap(); + assert_eq!(value, i.to_be_bytes()); + } + + let wal = wal.reader(); + let mut iter = wal.range_values((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in 50..100u32 { + let value = iter.next().unwrap(); + assert_eq!(value, i.to_be_bytes()); + } + + assert!(iter.next().is_none()); + + let mut iter = wal.range_values((Bound::Included(x.as_slice()), Bound::Unbounded)); + for i in (50..100u32).rev() { + let value = iter.next_back().unwrap(); + assert_eq!(value, i.to_be_bytes()); + } } pub(crate) fn first>(wal: &mut W) { @@ -790,6 +973,11 @@ pub(crate) fn first>(wal: &mut W) { let (key, value) = wal.first().unwrap(); assert_eq!(key, 0u32.to_be_bytes()); assert_eq!(value, 0u32.to_be_bytes()); + + let wal = wal.reader(); + let (key, value) = wal.first().unwrap(); + assert_eq!(key, 0u32.to_be_bytes()); + assert_eq!(value, 0u32.to_be_bytes()); } pub(crate) fn last>(wal: &mut W) { @@ -800,6 +988,11 @@ pub(crate) fn last>(wal: &mut W) { let (key, value) = wal.last().unwrap(); assert_eq!(key, 99u32.to_be_bytes()); assert_eq!(value, 99u32.to_be_bytes()); + + let wal = wal.reader(); + let (key, value) = wal.last().unwrap(); + assert_eq!(key, 99u32.to_be_bytes()); + assert_eq!(value, 99u32.to_be_bytes()); } pub(crate) fn get_or_insert>(wal: &mut W) { @@ -818,6 +1011,11 @@ pub(crate) fn get_or_insert>(wal: &mut W) { for i in 0..100u32 { assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); } + + let wal = wal.reader(); + for i in 0..100u32 { + assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); + } } pub(crate) fn get_or_insert_with_value_builder>(wal: &mut W) { @@ -848,12 +1046,20 @@ pub(crate) fn get_or_insert_with_value_builder>(wal: &mut for i in 0..100u32 { assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); } + + let wal = wal.reader(); + for i in 0..100u32 { + assert_eq!(wal.get(&i.to_be_bytes()).unwrap(), i.to_be_bytes()); + } } pub(crate) fn zero_reserved>(wal: &mut W) { unsafe { assert_eq!(wal.reserved_slice(), &[]); assert_eq!(wal.reserved_slice_mut(), &mut []); + + let reader = wal.reader(); + assert_eq!(reader.reserved_slice(), &[]); } } @@ -863,5 +1069,8 @@ pub(crate) fn reserved>(wal: &mut W) { buf.copy_from_slice(b"al8n"); assert_eq!(wal.reserved_slice(), b"al8n"); assert_eq!(wal.reserved_slice_mut(), b"al8n"); + + let reader = wal.reader(); + assert_eq!(reader.reserved_slice(), b"al8n"); } } diff --git a/src/unsync.rs b/src/unsync.rs index a05fa6b6..0a346c12 100644 --- a/src/unsync.rs +++ b/src/unsync.rs @@ -8,9 +8,9 @@ use wal::{ ImmutableWal, }; -use core::{ops::RangeBounds, ptr::NonNull}; +use core::{cell::UnsafeCell, ops::RangeBounds, ptr::NonNull}; use rarena_allocator::{unsync::Arena, Error as ArenaError}; -use std::collections::BTreeSet; +use std::{collections::BTreeSet, rc::Rc}; /// Iterators for the `OrderWal`. pub mod iter; @@ -19,7 +19,7 @@ use iter::*; mod c; use c::*; -#[cfg(all(test, feature = "test-unsync"))] +#[cfg(test)] mod tests; /// An ordered write-ahead log implementation for single thread environments. @@ -41,7 +41,7 @@ mod tests; // +----------------------+-------------------------+--------------------+---------------------+-----------------+--------------------+ // ``` pub struct OrderWal { - core: OrderWalCore, + core: Rc>>, ro: bool, _s: PhantomData, } @@ -56,7 +56,7 @@ where #[inline] fn from_core(core: Self::Core, ro: bool) -> Self { Self { - core, + core: Rc::new(UnsafeCell::new(core)), ro, _s: PhantomData, } @@ -66,7 +66,17 @@ where impl OrderWal { /// Returns the path of the WAL if it is backed by a file. pub fn path_buf(&self) -> Option<&std::rc::Rc> { - self.core.arena.path() + self.core().arena.path() + } + + #[inline] + fn core(&self) -> &OrderWalCore { + unsafe { &*self.core.get() } + } + + #[inline] + fn core_mut(&mut self) -> &mut OrderWalCore { + unsafe { &mut *self.core.get() } } } @@ -88,7 +98,8 @@ where let (len_size, kvlen, elen) = entry_size(klen, vlen); let klen = klen as usize; let vlen = vlen as usize; - let buf = self.core.arena.alloc_bytes(elen); + let core = self.core_mut(); + let buf = core.arena.alloc_bytes(elen); match buf { Err(e) => { @@ -107,8 +118,8 @@ where // We allocate the buffer with the exact size, so it's safe to write to the buffer. let flag = Flags::COMMITTED.bits(); - self.core.cks.reset(); - self.core.cks.update(&[flag]); + core.cks.reset(); + core.cks.update(&[flag]); buf.put_u8_unchecked(Flags::empty().bits()); let written = buf.put_u64_varint_unchecked(kvlen); @@ -134,27 +145,26 @@ where .map_err(Among::Middle)?; let cks = { - self.core.cks.update(&buf[1..]); - self.core.cks.digest() + core.cks.update(&buf[1..]); + core.cks.digest() }; buf.put_u64_le_unchecked(cks); // commit the entry buf[0] |= Flags::COMMITTED.bits(); - if self.core.opts.sync_on_write() && self.core.arena.is_ondisk() { - self - .core + if core.opts.sync_on_write() && core.arena.is_ondisk() { + core .arena .flush_range(buf.offset(), elen as usize) .map_err(|e| Among::Right(e.into()))?; } buf.detach(); - self.core.map.insert(Pointer::new( + core.map.insert(Pointer::new( klen, vlen, buf.as_ptr().add(ko), - self.core.cmp.cheap_clone(), + core.cmp.cheap_clone(), )); Ok(()) } @@ -197,43 +207,39 @@ where C: Comparator; unsafe fn reserved_slice(&self) -> &[u8] { - if self.core.opts.reserved() == 0 { + let core = self.core(); + if core.opts.reserved() == 0 { return &[]; } - &self.core.arena.reserved_slice()[HEADER_SIZE..] + &core.arena.reserved_slice()[HEADER_SIZE..] } #[inline] fn path(&self) -> Option<&std::path::Path> { - self.core.arena.path().map(|p| p.as_ref().as_path()) - } - - #[inline] - fn read_only(&self) -> bool { - self.ro + self.core().arena.path().map(|p| p.as_ref().as_path()) } /// Returns the number of entries in the WAL. #[inline] fn len(&self) -> usize { - self.core.map.len() + self.core().map.len() } /// Returns `true` if the WAL is empty. #[inline] fn is_empty(&self) -> bool { - self.core.map.is_empty() + self.core().map.is_empty() } #[inline] fn maximum_key_size(&self) -> u32 { - self.core.opts.maximum_key_size() + self.core().opts.maximum_key_size() } #[inline] fn maximum_value_size(&self) -> u32 { - self.core.opts.maximum_value_size() + self.core().opts.maximum_value_size() } #[inline] @@ -243,7 +249,7 @@ where Q: ?Sized + Ord, C: Comparator, { - self.core.map.contains(key) + self.core().map.contains(key) } #[inline] @@ -251,7 +257,7 @@ where where C: Comparator, { - Iter::new(self.core.map.iter()) + Iter::new(self.core().map.iter()) } #[inline] @@ -262,7 +268,7 @@ where Q: Ord + ?Sized, C: Comparator, { - Range::new(self.core.map.range(range)) + Range::new(self.core().map.range(range)) } #[inline] @@ -270,7 +276,7 @@ where where C: Comparator, { - Keys::new(self.core.map.iter()) + Keys::new(self.core().map.iter()) } #[inline] @@ -281,7 +287,7 @@ where Q: Ord + ?Sized, C: Comparator, { - RangeKeys::new(self.core.map.range(range)) + RangeKeys::new(self.core().map.range(range)) } #[inline] @@ -289,7 +295,7 @@ where where C: Comparator, { - Values::new(self.core.map.iter()) + Values::new(self.core().map.iter()) } #[inline] @@ -300,7 +306,7 @@ where Q: Ord + ?Sized, C: Comparator, { - RangeValues::new(self.core.map.range(range)) + RangeValues::new(self.core().map.range(range)) } #[inline] @@ -309,7 +315,7 @@ where C: Comparator, { self - .core + .core() .map .first() .map(|ent| (ent.as_key_slice(), ent.as_value_slice())) @@ -321,7 +327,7 @@ where C: Comparator, { self - .core + .core() .map .last() .map(|ent| (ent.as_key_slice(), ent.as_value_slice())) @@ -334,7 +340,7 @@ where Q: ?Sized + Ord, C: Comparator, { - self.core.map.get(key).map(|ent| ent.as_value_slice()) + self.core().map.get(key).map(|ent| ent.as_value_slice()) } } @@ -344,13 +350,28 @@ where { type Reader = Self; + #[inline] + fn read_only(&self) -> bool { + self.ro + } + + #[inline] + fn reader(&self) -> Self::Reader { + Self { + core: self.core.clone(), + ro: true, + _s: PhantomData, + } + } + #[inline] unsafe fn reserved_slice_mut(&mut self) -> &mut [u8] { - if self.core.opts.reserved() == 0 { + let core = self.core_mut(); + if core.opts.reserved() == 0 { return &mut []; } - &mut self.core.arena.reserved_slice_mut()[HEADER_SIZE..] + &mut core.arena.reserved_slice_mut()[HEADER_SIZE..] } #[inline] @@ -359,7 +380,7 @@ where return Err(error::Error::read_only()); } - self.core.arena.flush().map_err(Into::into) + self.core().arena.flush().map_err(Into::into) } #[inline] @@ -368,7 +389,7 @@ where return Err(error::Error::read_only()); } - self.core.arena.flush_async().map_err(Into::into) + self.core().arena.flush_async().map_err(Into::into) } fn get_or_insert_with_value_builder( @@ -393,7 +414,7 @@ where ) .map_err(Either::Right)?; - if let Some(ent) = self.core.map.get(key) { + if let Some(ent) = self.core().map.get(key) { return Ok(Some(ent.as_value_slice())); } diff --git a/src/unsync/iter.rs b/src/unsync/iter.rs index c0626da1..777f9b03 100644 --- a/src/unsync/iter.rs +++ b/src/unsync/iter.rs @@ -26,11 +26,6 @@ impl<'a, C> Iterator for Iter<'a, C> { (k, v) }) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C> DoubleEndedIterator for Iter<'a, C> { @@ -65,11 +60,6 @@ impl<'a, C> Iterator for Keys<'a, C> { fn next(&mut self) -> Option { self.iter.next().map(|ptr| ptr.as_key_slice()) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C> DoubleEndedIterator for Keys<'a, C> { @@ -100,11 +90,6 @@ impl<'a, C> Iterator for Values<'a, C> { fn next(&mut self) -> Option { self.iter.next().map(|ptr| ptr.as_value_slice()) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C> DoubleEndedIterator for Values<'a, C> { @@ -147,11 +132,6 @@ where .next() .map(|ptr| (ptr.as_key_slice(), ptr.as_value_slice())) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C> DoubleEndedIterator for Range<'a, C> @@ -197,11 +177,6 @@ where fn next(&mut self) -> Option { self.iter.next().map(|ptr| ptr.as_key_slice()) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C> DoubleEndedIterator for RangeKeys<'a, C> @@ -244,11 +219,6 @@ where fn next(&mut self) -> Option { self.iter.next().map(|ptr| ptr.as_value_slice()) } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } } impl<'a, C> DoubleEndedIterator for RangeValues<'a, C> diff --git a/src/unsync/tests.rs b/src/unsync/tests.rs index ee419731..96d3abab 100644 --- a/src/unsync/tests.rs +++ b/src/unsync/tests.rs @@ -4,6 +4,16 @@ use crate::tests::*; use super::*; -const MB: u32 = 1024 * 1024; +#[cfg(all(test, feature = "test-unsync-constructor"))] +mod constructor; + +#[cfg(all(test, feature = "test-unsync-insert"))] +mod insert; + +#[cfg(all(test, feature = "test-unsync-iters"))] +mod iter; -common_unittests!(unsync::OrderWal); +#[cfg(all(test, feature = "test-unsync-get"))] +mod get; + +const MB: u32 = 1024 * 1024; diff --git a/src/unsync/tests/constructor.rs b/src/unsync/tests/constructor.rs new file mode 100644 index 00000000..03e864a3 --- /dev/null +++ b/src/unsync/tests/constructor.rs @@ -0,0 +1,3 @@ +use super::*; + +common_unittests!(unsync::constructor::OrderWal); diff --git a/src/unsync/tests/get.rs b/src/unsync/tests/get.rs new file mode 100644 index 00000000..c9eefcf8 --- /dev/null +++ b/src/unsync/tests/get.rs @@ -0,0 +1,3 @@ +use super::*; + +common_unittests!(unsync::get::OrderWal); diff --git a/src/unsync/tests/insert.rs b/src/unsync/tests/insert.rs new file mode 100644 index 00000000..6aacd454 --- /dev/null +++ b/src/unsync/tests/insert.rs @@ -0,0 +1,3 @@ +use super::*; + +common_unittests!(unsync::insert::OrderWal); diff --git a/src/unsync/tests/iter.rs b/src/unsync/tests/iter.rs new file mode 100644 index 00000000..f20d78e8 --- /dev/null +++ b/src/unsync/tests/iter.rs @@ -0,0 +1,3 @@ +use super::*; + +common_unittests!(unsync::iters::OrderWal); diff --git a/src/wal.rs b/src/wal.rs index 907f54c2..b966529e 100644 --- a/src/wal.rs +++ b/src/wal.rs @@ -11,13 +11,13 @@ pub(crate) mod sealed; pub trait ImmutableWal: sealed::Constructor { /// The iterator type. - type Iter<'a>: Iterator + type Iter<'a>: Iterator + DoubleEndedIterator where Self: 'a, C: Comparator; /// The iterator type over a subset of entries in the WAL. - type Range<'a, Q, R>: Iterator + type Range<'a, Q, R>: Iterator + DoubleEndedIterator where R: RangeBounds, [u8]: Borrow, @@ -26,13 +26,13 @@ pub trait ImmutableWal: sealed::Constructor { C: Comparator; /// The keys iterator type. - type Keys<'a>: Iterator + type Keys<'a>: Iterator + DoubleEndedIterator where Self: 'a, C: Comparator; /// The iterator type over a subset of keys in the WAL. - type RangeKeys<'a, Q, R>: Iterator + type RangeKeys<'a, Q, R>: Iterator + DoubleEndedIterator where R: RangeBounds, [u8]: Borrow, @@ -41,13 +41,13 @@ pub trait ImmutableWal: sealed::Constructor { C: Comparator; /// The values iterator type. - type Values<'a>: Iterator + type Values<'a>: Iterator + DoubleEndedIterator where Self: 'a, C: Comparator; /// The iterator type over a subset of values in the WAL. - type RangeValues<'a, Q, R>: Iterator + type RangeValues<'a, Q, R>: Iterator + DoubleEndedIterator where R: RangeBounds, [u8]: Borrow, @@ -65,9 +65,6 @@ pub trait ImmutableWal: sealed::Constructor { /// Returns the path of the WAL if it is backed by a file. fn path(&self) -> Option<&std::path::Path>; - /// Returns `true` if this WAL instance is read-only. - fn read_only(&self) -> bool; - /// Returns the number of entries in the WAL. fn len(&self) -> usize; @@ -318,6 +315,9 @@ pub trait Wal: sealed::Sealed + ImmutableWal { .map_err(Either::Right) } + /// Returns `true` if this WAL instance is read-only. + fn read_only(&self) -> bool; + /// Returns the mutable reference to the reserved slice. /// /// # Safety @@ -331,6 +331,9 @@ pub trait Wal: sealed::Sealed + ImmutableWal { /// Flushes the to disk. fn flush_async(&self) -> Result<(), Error>; + /// Returns the read-only view for the WAL. + fn reader(&self) -> Self::Reader; + /// Get or insert a new entry into the WAL. fn get_or_insert(&mut self, key: &[u8], value: &[u8]) -> Result, Error> where @@ -392,11 +395,7 @@ pub trait Wal: sealed::Sealed + ImmutableWal { Ok(()) }), ) - .map_err(|e| match e { - Among::Left(e) => Either::Left(e), - Among::Middle(_) => unreachable!(), - Among::Right(e) => Either::Right(e), - }) + .map_err(Among::into_left_right) } /// Inserts a key-value pair into the WAL. This method @@ -433,11 +432,7 @@ pub trait Wal: sealed::Sealed + ImmutableWal { }), vb, ) - .map_err(|e| match e { - Among::Left(_) => unreachable!(), - Among::Middle(e) => Either::Left(e), - Among::Right(e) => Either::Right(e), - }) + .map_err(Among::into_middle_right) } /// Inserts a key-value pair into the WAL. This method