Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.14.0 #29

Merged
merged 91 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
21b0c81
Add `CompressionPolicy` as a configuration
al8n Jul 20, 2024
3e43cd6
Increase the discarded tracker when find new version
al8n Jul 20, 2024
e8729c3
Fix fmt
al8n Jul 20, 2024
d04c2ee
Split create new node and link new node
al8n Jul 20, 2024
bdb74bc
WIP: allocate unlinked node
al8n Jul 21, 2024
f0006b0
WIP: allocate unlinked node
al8n Jul 22, 2024
d46738c
WIP
al8n Jul 22, 2024
f10f667
Add documents
al8n Jul 24, 2024
dbc6427
Add unit test
al8n Jul 24, 2024
853facf
Modify CI
al8n Jul 24, 2024
841dbc3
Fix CI
al8n Jul 24, 2024
1a86f23
Update tests.rs
al8n Jul 25, 2024
d03f190
Add versioned API
al8n Jul 25, 2024
47a6108
Add `estimated_node_size` API
al8n Aug 3, 2024
07781dc
Fix fmt
al8n Aug 3, 2024
8aca79f
Check minimum height
al8n Aug 3, 2024
44b0a83
Update tests.rs
al8n Aug 3, 2024
3e472c6
Fix CI
al8n Aug 3, 2024
dd5fa6f
Update api.rs
al8n Aug 3, 2024
1790204
Add more APIs
al8n Aug 6, 2024
4608ccf
Add more API
al8n Aug 7, 2024
6195b3a
Fix fmt
al8n Aug 8, 2024
04a1a11
Support `rewind`
al8n Aug 8, 2024
f72fafd
Remove `&self`
al8n Aug 8, 2024
003277c
Add `*path_builder` constructor
al8n Aug 10, 2024
98fb381
WIP: crash-safety
al8n Aug 12, 2024
29dea7b
Update crash_safety.md
al8n Aug 13, 2024
05013bc
update doc
al8n Aug 13, 2024
3a4f4cf
update doc
al8n Aug 13, 2024
9b12554
Fix fmt
al8n Aug 13, 2024
5c5b32f
Make `Comparator` trait object safe
al8n Aug 14, 2024
9ee1c3a
WIP: embed version to Node
al8n Aug 15, 2024
b7af0b0
WIP: embed version to Node
al8n Aug 15, 2024
2d3c947
WIP: embed version to node
al8n Aug 15, 2024
46d6892
WIP: embed `version` to `Node`
al8n Aug 15, 2024
de4a42e
WIP
al8n Aug 15, 2024
c884f3e
WIP
al8n Aug 15, 2024
0c7a6fa
WIP: compile
al8n Aug 16, 2024
f0b0cac
WIP
al8n Aug 16, 2024
8c8ecb3
WIP
al8n Aug 17, 2024
0efc473
WIP
al8n Aug 17, 2024
7a07aae
WIP
al8n Aug 18, 2024
cdbc4d3
WIP: embed version to Node
al8n Aug 18, 2024
fcaa732
Fix trailer and value getter
al8n Aug 19, 2024
aef0076
WIP
al8n Aug 19, 2024
b61c22a
Add unsafe keyword
al8n Aug 19, 2024
5b11b4c
WIP: `msync`
al8n Aug 20, 2024
bcbb291
WIP: sync and commit
al8n Aug 20, 2024
b99846a
WIP
al8n Aug 21, 2024
8766af0
bk
al8n Aug 23, 2024
e75d95a
bk
al8n Aug 23, 2024
63db690
WIP: unsync version
al8n Aug 25, 2024
036b165
WIP: unsync version
al8n Aug 25, 2024
d4a298c
WIP
al8n Aug 26, 2024
0ef7989
WIP
al8n Aug 26, 2024
e262a10
Update map.rs
al8n Aug 26, 2024
e875441
Update map.rs
al8n Aug 26, 2024
0d6bb66
WIP
al8n Aug 26, 2024
b578450
Add test cases
al8n Aug 27, 2024
13daf00
unit tests
al8n Aug 27, 2024
c15b121
WIP
al8n Aug 27, 2024
e360a25
WIP
al8n Aug 27, 2024
2a822fd
Fix doc tests
al8n Aug 27, 2024
ff46784
Fix all test cases
al8n Aug 27, 2024
3307158
Add `path` API
al8n Aug 28, 2024
74d4c30
cleanup APIs
al8n Aug 28, 2024
1377fb9
remove unused sync
al8n Aug 28, 2024
949cac1
Fix doc tests
al8n Aug 29, 2024
1f961f7
remove `strong_count`
al8n Aug 29, 2024
1462fcb
Add more test cases
al8n Aug 29, 2024
a56cc6e
Merge branch 'main' into unsync
al8n Aug 29, 2024
50d9715
Add tb CI
al8n Aug 29, 2024
61ec616
Fix CI
al8n Aug 29, 2024
7cbcc50
Fix warnings
al8n Aug 29, 2024
6c3f42b
Fix CI warnings
al8n Aug 29, 2024
383744a
Fix CI on windows
al8n Aug 29, 2024
417806c
Fix miri
al8n Aug 29, 2024
9206ce2
Fix CI
al8n Aug 29, 2024
1befbe6
Update api.rs
al8n Aug 29, 2024
eb63c14
Update api.rs
al8n Aug 29, 2024
e8c52de
Add miri ignore
al8n Aug 29, 2024
9878809
WIP
al8n Aug 30, 2024
045f0d5
Fix miri bug on ZST
al8n Aug 30, 2024
f0dff07
remove ptr in NodePointer
al8n Aug 30, 2024
aefbe9d
Use `among::Among`
al8n Sep 3, 2024
0a799d8
Use `dbutils`
al8n Sep 3, 2024
f4fd47e
merge
al8n Sep 5, 2024
a726eff
Make file backed API unsafe
al8n Sep 12, 2024
1de1a70
Make file backed API unsafe
al8n Sep 12, 2024
3a7a096
Update README.md
al8n Sep 12, 2024
09a0dbc
Update doc
al8n Sep 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clippy.toml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
msrv = "1.56.0"
msrv = "1.77.0"
5 changes: 5 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ codecov:
ignore:
- integration/
- src/map/error.rs
# - src/unsync/tests.rs
# - src/unsync/tests/
# - src/sync/tests.rs
# - src/sync/tests/


coverage:
status:
Expand Down
77 changes: 70 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ jobs:
# cargo +nightly build --no-default-features --features alloc --target ${{ matrix.target }} -Z build-std=core,alloc
# if: matrix.target == 'mips64-unknown-linux-gnuabi64'

test:
name: test
build:
name: build
strategy:
matrix:
os:
Expand Down Expand Up @@ -138,7 +138,39 @@ jobs:
path: ~/.cargo
key: ${{ runner.os }}-coverage-dotcargo
- name: Run test
run: cargo hack test --feature-powerset --exclude-no-default-features --exclude-features tracing
run: cargo hack build --feature-powerset --exclude-no-default-features --exclude-features tracing

test:
name: test
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 }}-test-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-test-
- name: Install Rust
# --no-self-update is necessary because the windows environment cannot self-update rustup.exe.
run: rustup update stable --no-self-update && rustup default stable
- name: Cache ~/.cargo
uses: actions/cache@v3
with:
path: ~/.cargo
key: ${{ runner.os }}-coverage-dotcargo
- name: Run test
run: cargo test --all-features

sanitizer:
name: sanitizer
Expand Down Expand Up @@ -209,8 +241,38 @@ jobs:
working-directory: integration


miri:
name: miri
miri-tb:
name: miri-tb
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.sh
if: matrix.os == 'ubuntu-latest'
- name: Miri
run: ci/miri_tb_generic.sh
if: matrix.os != 'ubuntu-latest'

miri-sb:
name: miri-sb
strategy:
matrix:
os:
Expand All @@ -233,10 +295,10 @@ jobs:
- name: Install cargo-hack
run: cargo install cargo-hack
- name: Miri (Linux)
run: ci/miri.sh
run: ci/miri_sb.sh
if: matrix.os == 'ubuntu-latest'
- name: Miri
run: ci/miri_generic.sh
run: ci/miri_sb_generic.sh
if: matrix.os != 'ubuntu-latest'

# loom:
Expand Down Expand Up @@ -271,6 +333,7 @@ jobs:
needs:
- rustfmt
- clippy
- build
- test
- sanitizer
- valgrind
Expand Down
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# CHANGELOG

## 0.14.0

- Supports unsync version `SkipMap`s
- Fix: dealloc potential in-unsed memory chunk
- Add `CompressionPolicy` as a configuration
- Increase the discarded tracker when find new version of a key

## 0.13.0

- Remove `Comparator` generic on `Entry*`
Expand Down Expand Up @@ -87,5 +94,3 @@
- Add `flush` API

## UNRELEASED


19 changes: 13 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
[package]
name = "skl"
version = "0.13.1"
version = "0.14.0"
edition = "2021"
rust-version = "1.56.0"
rust-version = "1.77.0"
repository = "https://github.com/al8n/skl"
description = "A lock-free thread-safe concurrent ARENA based (heap backend or memory map backend) skiplist implementation which helps develop MVCC memtable for LSM-Tree."
documentation = "https://docs.rs/skl"
homepage = "https://github.com/al8n/skl"
keywords = ["skiplist", "lock-free", "memtable", "concurrency", "arena"]
categories = ["database", "data-structures", "concurrency", "no-std"]
license = "MIT/Apache-2.0"
license = "MIT OR Apache-2.0"

[[bench]]
path = "benches/bench.rs"
Expand All @@ -34,7 +34,7 @@ required-features = ["memmap"]
default = ["std"]
alloc = ["rarena-allocator/alloc"]
memmap = ["rarena-allocator/memmap", "std"]
std = ["rand/default", "either/default", "rarena-allocator/std"]
std = ["rand/default", "either/default", "rarena-allocator/std", "memchr/default", "among/default"]
tracing = ["dep:tracing", "rarena-allocator/tracing"]

# loom = ["dep:loom", "rarena-allocator/loom"]
Expand All @@ -43,11 +43,18 @@ tracing = ["dep:tracing", "rarena-allocator/tracing"]
getrandom = { version = "0.2", features = ["js"] }

[dependencies]
among = { version = "0.1", default-features = false }
derive_more = "0.99"
dbutils = { version = "0.3", default-features = false }
either = { version = "1", default-features = false }
memchr = { version = "2", default-features = false }
rand = { version = "0.8", default-features = false, features = ["getrandom"] }
rarena-allocator = { version = "0.1", default-features = false }
ux2 = { version = "0.8", default-features = false, features = ["32"] }
# rarena-allocator = { version = "0.2", default-features = false, path = "../arena/rarena-allocator" }
rarena-allocator = { version = "0.2", default-features = false }
arbitrary-int = { version = "1.2", default-features = false }
paste = "1"

time = { version = "0.3", optional = true, features = ["std"] }
tracing = { version = "0.1", optional = true }

[dev-dependencies]
Expand Down
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,33 @@
## Features

- **MVCC and 3D access**: Builtin MVCC (multiple versioning concurrency control) and key-value-version access support.
- **Lock-free and Concurrent-Safe:** SkipMap provide lock-free operations, ensuring efficient concurrent access without the need for explicit locking mechanisms.
- **Extensible for Key-Value Database Developers:** Designed as a low-level crate, SkipMap offer a flexible foundation for key-value database developers. You can easily build your own memtable or write-ahead-log (WAL) using these structures.
- **Lock-free and Concurrent-Safe:** `SkipMap` provide lock-free operations, ensuring efficient concurrent access without the need for explicit locking mechanisms.
- **Extensible for Key-Value Database Developers:** Designed as a low-level crate, `SkipMap` offer a flexible foundation for key-value database developers. You can easily build your own memtable or durable storage using these structures.
- **Memory Efficiency:** These data structures are optimized for minimal memory overhead. They operate around references, avoiding unnecessary allocations and deep copies, which can be crucial for efficient memory usage.
- **Segment tracker:** Builtin segment recollection support, a lock-free freelist helps reuse free segments.
- **Prefix compression:**
- Same key will only be stored once.
- Keys with common prefix will be stored once (longest one must be inserted first).
- Keys are sub-slice of negeibours will be stored once (require `CompressionPolicy::High`).
- **Discard tracker:** Builtin discard tracker, which will track discarded bytes to help end-users decide when to compact or rewrite.
- **Efficient Iteration:** Enjoy fast forward and backward iteration through the elements in your SkipMap. Additionally, bounded iterators are supported, allowing you to traverse only a specified range of elements efficiently.
- **Snapshot Support:** Create snapshots of your SkipMap, offering a read-only view of the contents at a specific moment in time. Snapshots provide a consistent view of the data, enabling implementations of transactional semantics and other use cases where data consistency is crucial.
- **Efficient Iteration:** Enjoy fast forward and backward iteration through the elements in your `SkipMap`. Additionally, bounded iterators are supported, allowing you to traverse only a specified range of elements efficiently.
- **Snapshot Support:** Create snapshots of your `SkipMap`, offering a read-only view of the contents at a specific moment in time. Snapshots provide a consistent view of the data, enabling implementations of transactional semantics and other use cases where data consistency is crucial.
- **Memory Management Options:**
- **Heap Allocation:** Memory allocation is handled by Rust's allocator, ensuring all data resides in RAM.
- **Mmap:** Data can be mapped to a disk file by the operating system, making it suitable for write-ahead-logs (WAL) and durable storage.
- **Mmap:** Data can be mapped to a disk file by the operating system, making it suitable for durable storage.
- **Mmap Anonymous:** Mapped to anonymous memory (virtual memory) by the OS, ideal for large in-memory memtables, optimizing memory utilization.

## Examples

Please see [examples](https://github.com/al8n/skl/tree/main/examples) folder for more details.

## Q & A

- Does the on-disk version `SkipMap` ensure crash safety or power failure resilience?

No, on-disk version `SkipMap` does not ensure crash safety or power failure resilience. Hence, it is not recommended to directly
use the `SkipMap` as a durable database. It is recommended to use the on-disk version `SkipMap` as a final frozen file for quick lookup.

## Tests

- `test`:
Expand Down
12 changes: 6 additions & 6 deletions benches/bench.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use criterion::*;
use parking_lot::Mutex;
use rand::prelude::*;
use skl::*;
use skl::{sync::map::SkipMap, *};
use std::{
collections::*,
sync::{atomic::*, *},
Expand All @@ -25,11 +25,11 @@ fn fixed_map_round(

fn fixed_skiplist_round(l: &SkipMap, case: &(Vec<u8>, bool), exp: &Vec<u8>) {
if case.1 {
if let Some(v) = l.get(0, &case.0) {
if let Some(v) = l.get(&case.0) {
assert_eq!(v.value(), exp);
}
} else {
l.insert(0, &case.0, exp).unwrap();
l.insert(&case.0, exp).unwrap();
}
}

Expand All @@ -42,7 +42,7 @@ fn random_key(rng: &mut ThreadRng) -> Vec<u8> {
fn bench_read_write_fixed_skiplist_frac(b: &mut Bencher<'_>, frac: &usize) {
let frac = *frac;
let value = b"00123".to_vec();
let list = Arc::new(SkipMap::with_options(Options::new().with_capacity(512 << 20)).unwrap());
let list = Arc::new(SkipMap::new(Options::new().with_capacity(512 << 20)).unwrap());
let l = list.clone();
let stop = Arc::new(AtomicBool::new(false));
let s = stop.clone();
Expand Down Expand Up @@ -164,7 +164,7 @@ fn bench_write_fixed_map(c: &mut Criterion) {
}

fn bench_write_fixed_skiplist(c: &mut Criterion) {
let list = Arc::new(SkipMap::with_options(Options::new().with_capacity(512 << 21)).unwrap());
let list = Arc::new(SkipMap::new(Options::new().with_capacity(512 << 21)).unwrap());
let value = b"00123".to_vec();
let l = Arc::clone(&list);
let stop = Arc::new(AtomicBool::new(false));
Expand All @@ -182,7 +182,7 @@ fn bench_write_fixed_skiplist(c: &mut Criterion) {
b.iter_batched(
|| random_key(&mut rng),
|key| {
list.insert(0, &key, &value).unwrap();
list.insert(&key, &value).unwrap();
},
BatchSize::SmallInput,
)
Expand Down
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions ci/miri_tb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash
set -e

rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri setup

export MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-disable-isolation -Zmiri-symbolic-alignment-check -Zmiri-tree-borrows"

cargo miri test --all-features --target x86_64-unknown-linux-gnu
# cargo miri test --tests --target aarch64-unknown-linux-gnu #crossbeam_utils has problem on this platform
cargo miri test --all-features --target i686-unknown-linux-gnu
cargo miri test --all-features --target powerpc64-unknown-linux-gnu
10 changes: 10 additions & 0 deletions ci/miri_tb_generic.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -e

rustup toolchain install nightly --component miri
rustup override set nightly
cargo miri setup

export MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-disable-isolation -Zmiri-symbolic-alignment-check -Zmiri-tree-borrows"

cargo miri test --tests --features memmap
20 changes: 9 additions & 11 deletions examples/heap.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use skl::*;
use std::sync::Arc;
use skl::{sync::map::*, *};

pub fn key(i: usize) -> Vec<u8> {
format!("{:05}", i).into_bytes()
Expand All @@ -11,24 +10,23 @@ pub fn new_value(i: usize) -> Vec<u8> {

fn main() {
const N: usize = 1000;
let l = SkipMap::with_options(Options::new().with_capacity(1 << 20)).unwrap();
let mut wg = Arc::new(());

let l = SkipMap::new(Options::new().with_capacity(1 << 20)).unwrap();

for i in 0..N {
let w = wg.clone();
let l = l.clone();
std::thread::spawn(move || {
l.insert(0, &key(i), &new_value(i)).unwrap();
drop(w);
l.insert(&key(i), &new_value(i)).unwrap();
});
}
while Arc::get_mut(&mut wg).is_none() {}

while l.refs() > 1 {}

for i in 0..N {
let w = wg.clone();
let l = l.clone();
std::thread::spawn(move || {
let k = key(i);
assert_eq!(l.get(0, &k).unwrap().value(), new_value(i), "broken: {i}");
drop(w);
assert_eq!(l.get(&k).unwrap().value(), new_value(i), "broken: {i}");
});
}
}
20 changes: 9 additions & 11 deletions examples/mmap.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use skl::SkipMap;
use std::sync::Arc;
use skl::{sync::map::SkipMap, Options};

pub fn key(i: usize) -> Vec<u8> {
format!("{:05}", i).into_bytes()
Expand All @@ -17,24 +16,23 @@ fn main() {
.read(true)
.write(true);

let l = SkipMap::map_mut("test.wal", open_options, mmap_options).unwrap();
let mut wg = Arc::new(());
let l =
unsafe { SkipMap::map_mut("test.wal", Options::new(), open_options, mmap_options).unwrap() };

for i in 0..N {
let w = wg.clone();
let l = l.clone();
std::thread::spawn(move || {
l.insert(0, &key(i), &new_value(i)).unwrap();
drop(w);
l.insert(&key(i), &new_value(i)).unwrap();
});
}
while Arc::get_mut(&mut wg).is_none() {}

while l.refs() > 1 {}

for i in 0..N {
let w = wg.clone();
let l = l.clone();
std::thread::spawn(move || {
let k = key(i);
assert_eq!(l.get(0, &k).unwrap().value(), new_value(i), "broken: {i}");
drop(w);
assert_eq!(l.get(&k).unwrap().value(), new_value(i), "broken: {i}");
});
}
}
Loading
Loading