Skip to content

Commit

Permalink
Update doc (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
al8n authored Feb 17, 2025
1 parent 60d5d32 commit a281708
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 85 deletions.
10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "skl"
version = "0.22.17"
version = "0.22.18"
edition = "2021"
rust-version = "1.81.0"
repository = "https://github.com/al8n/skl"
Expand All @@ -20,6 +20,14 @@ harness = false
name = "heap"
path = "examples/heap.rs"

[[example]]
name = "generic"
path = "examples/generic.rs"

[[example]]
name = "multiple-version"
path = "examples/multiple_version.rs"

[[example]]
name = "mmap"
path = "examples/mmap.rs"
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
## Features

- **MVCC and 3D access**: Builtin MVCC (multiple versioning concurrency control) and key-value-version access support.
- **Customable Statefull Comparator**: Not limited by `Borrow` and the stateless comparator like `HashMap` or `BTreeMap`, `SkipMap` supports statefull custom comparators.
- **Multiple Maps**: Users can create multiple `SkipMap`s on the same ARENA.
- **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.
Expand Down
42 changes: 42 additions & 0 deletions examples/generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use skl::generic::{
unique::{sync::SkipMap, Map},
Builder,
};

pub fn key(i: usize) -> String {
format!("{:05}", i)
}

pub fn new_value(i: usize) -> String {
format!("{:05}", i)
}

fn main() {
const N: usize = 1000;

let l = Builder::new()
.with_capacity(1 << 20)
.alloc::<SkipMap<str, str>>()
.unwrap();

for i in 0..N {
let l = l.clone();
std::thread::spawn(move || {
l.insert(key(i).as_str(), new_value(i).as_str()).unwrap();
});
}

while l.refs() > 1 {}

for i in 0..N {
let l = l.clone();
std::thread::spawn(move || {
let k = key(i);
assert_eq!(
l.get(k.as_str()).unwrap().value(),
new_value(i).as_str(),
"broken: {i}"
);
});
}
}
11 changes: 4 additions & 7 deletions examples/heap.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use skl::{
generic::{
unique::{sync::SkipMap, Map},
Builder,
},
Arena,
use skl::dynamic::{
unique::{sync::SkipMap, Map},
Builder,
};

pub fn key(i: usize) -> Vec<u8> {
Expand All @@ -19,7 +16,7 @@ fn main() {

let l = Builder::new()
.with_capacity(1 << 20)
.alloc::<SkipMap<[u8], [u8]>>()
.alloc::<SkipMap>()
.unwrap();

for i in 0..N {
Expand Down
11 changes: 4 additions & 7 deletions examples/mmap.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use skl::{
generic::{
unique::{sync::SkipMap, Map},
Builder,
},
Arena,
use skl::dynamic::{
unique::{sync::SkipMap, Map},
Builder,
};

pub fn key(i: usize) -> Vec<u8> {
Expand All @@ -23,7 +20,7 @@ fn main() {
.with_read(true)
.with_write(true)
.with_create_new(true)
.map_mut::<SkipMap<[u8], [u8]>, _>("test.wal")
.map_mut::<SkipMap, _>("test.wal")
.unwrap()
};

Expand Down
11 changes: 4 additions & 7 deletions examples/mmap_anon.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use skl::{
generic::{
unique::{sync::SkipMap, Map},
Builder,
},
Arena,
use skl::dynamic::{
unique::{sync::SkipMap, Map},
Builder,
};

pub fn key(i: usize) -> Vec<u8> {
Expand All @@ -19,7 +16,7 @@ fn main() {

let l = Builder::new()
.with_capacity(1 << 20)
.map_anon::<SkipMap<[u8], [u8]>>()
.map_anon::<SkipMap>()
.unwrap();

for i in 0..N {
Expand Down
13 changes: 5 additions & 8 deletions examples/multiple_maps.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use skl::{
generic::{
dynamic::{
unique::{sync::SkipMap, Map},
Ascend, Builder,
},
Expand All @@ -23,10 +23,9 @@ fn main() {
.with_read(true)
.with_write(true)
.with_capacity(1024 * 1024)
.map_mut::<SkipMap<[u8], [u8]>, _>("multiple_maps.wal")
.map_mut::<SkipMap, _>("multiple_maps.wal")
.unwrap();
let l2 =
SkipMap::<[u8], [u8]>::create_from_allocator(l.allocator().clone(), Ascend::new()).unwrap();
let l2 = SkipMap::create_from_allocator(l.allocator().clone(), Ascend::new()).unwrap();
let h2 = l2.header().copied().unwrap();

let t1 = std::thread::spawn(move || {
Expand Down Expand Up @@ -55,11 +54,9 @@ fn main() {
.with_read(true)
.with_write(true)
.with_capacity((1024 * 1024 * 2) as u32)
.map_mut::<SkipMap<[u8], [u8]>, _>("multiple_maps.wal")
.map_mut::<SkipMap, _>("multiple_maps.wal")
.unwrap();
let l2 =
SkipMap::<[u8], [u8]>::open_from_allocator(header, l.allocator().clone(), Ascend::new())
.unwrap();
let l2 = SkipMap::open_from_allocator(header, l.allocator().clone(), Ascend::new()).unwrap();
assert_eq!(500, l.len());
assert_eq!(500, l2.len());

Expand Down
49 changes: 49 additions & 0 deletions examples/multiple_version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use skl::generic::{
multiple_version::{sync::SkipMap, Map},
Builder,
};

pub fn key(i: usize) -> String {
format!("{:05}", i)
}

pub fn new_value(i: usize) -> String {
format!("{:05}", i)
}

fn main() {
const N: usize = 1000;

let l = Builder::new()
.with_capacity(1 << 20)
.alloc::<SkipMap<str, str>>()
.unwrap();

for i in 0..(N / 2) {
let l = l.clone();
std::thread::spawn(move || {
l.insert(0, key(i).as_str(), new_value(i).as_str()).unwrap();
});
}

for i in (N / 2)..N {
let l = l.clone();
std::thread::spawn(move || {
l.insert(1, key(i).as_str(), new_value(i).as_str()).unwrap();
});
}

while l.refs() > 1 {}

for i in 0..N {
let l = l.clone();
std::thread::spawn(move || {
let k = key(i);
assert_eq!(
l.get(2, k.as_str()).unwrap().value(),
new_value(i).as_str(),
"broken: {i}"
);
});
}
}
9 changes: 3 additions & 6 deletions integration/src/bin/test-mmap-anon.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use integration::{big_value, key, new_value};
use skl::{
generic::{
unique::{sync::SkipMap, Map},
Builder,
},
Arena,
use skl::generic::{
unique::{sync::SkipMap, Map},
Builder,
};

fn main() {
Expand Down
9 changes: 3 additions & 6 deletions integration/src/bin/test-mmap.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use integration::{key, new_value};
use skl::{
generic::{
unique::{sync::SkipMap, Map},
Builder,
},
Arena,
use skl::generic::{
unique::{sync::SkipMap, Map},
Builder,
};

fn main() {
Expand Down
9 changes: 3 additions & 6 deletions integration/src/bin/test-vec.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use integration::{big_value, key, new_value};
use skl::{
generic::{
unique::{sync::SkipMap, Map},
Builder,
},
Arena,
use skl::generic::{
unique::{sync::SkipMap, Map},
Builder,
};

fn main() {
Expand Down
6 changes: 6 additions & 0 deletions src/dynamic/multiple_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,12 @@ where
self.as_ref().minimum_version()
}

/// Returns the references for the `SkipMap`.
#[inline]
fn refs(&self) -> usize {
self.as_ref().refs()
}

/// Returns a random generated height.
///
/// This method is useful when you want to check if the underlying allocator can allocate a node.
Expand Down
6 changes: 6 additions & 0 deletions src/dynamic/unique.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,12 @@ where
self.as_ref().random_height()
}

/// Returns the references for the `SkipMap`.
#[inline]
fn refs(&self) -> usize {
self.as_ref().refs()
}

/// Returns `true` if the key exists in the map.
///
/// ## Example
Expand Down
6 changes: 6 additions & 0 deletions src/generic/unique.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ where
self.as_ref().random_height()
}

/// Returns the references for the `SkipMap`.
#[inline]
fn refs(&self) -> usize {
self.as_ref().refs()
}

/// Returns `true` if the key exists in the map.
///
/// ## Example
Expand Down
Loading

0 comments on commit a281708

Please sign in to comment.