Skip to content

Commit

Permalink
Support custom trailer
Browse files Browse the repository at this point in the history
  • Loading branch information
al8n authored May 5, 2024
1 parent 2e6da36 commit a159a34
Show file tree
Hide file tree
Showing 15 changed files with 726 additions and 714 deletions.
23 changes: 15 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,25 @@ jobs:
# --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: Test
run: . ci/test-stable.sh test
run: . ci/test-stable.sh test

# Nightly
nightly:
name: nightly
runs-on: ubuntu-latest
# no std
no_std:
name: no_std
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Install Rust
run: rustup update $nightly && rustup default $nightly
# --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: Test
run: . ci/test-stable.sh test
run: cargo test --no-default-features --features alloc

# Run tests on some extra platforms
cross:
Expand Down Expand Up @@ -212,7 +219,7 @@ jobs:
- rustfmt
- clippy
- stable
- nightly
- no_std
- sanitizer
- valgrind
- minrust
Expand Down
7 changes: 2 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "skl"
version = "0.4.0"
version = "0.5.0"
edition = "2021"
repository = "https://github.com/al8n/skl-rs"
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."
Expand Down Expand Up @@ -40,13 +40,10 @@ loom = "0.7"

[target.'cfg(target_family = "wasm")'.dependencies]
getrandom = { version = "0.2", features = ["js"] }
rand = { version = "0.8", default-features = false, features = ["getrandom"] }

[target.'cfg(not(target_family = "wasm"))'.dependencies]
rand = { version = "0.8", default-features = false }

[dependencies]
crossbeam-utils = { version = "0.8", default-features = false }
rand = { version = "0.8", default-features = false, features = ["getrandom"] }

fs4 = { version = "0.8", optional = true }
memmap2 = { version = "0.9", optional = true }
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,19 @@

```toml
[dependencies]
skl = "0.4"
skl = "0.5"
```

- Enable memory map backend

```toml
[dependencies]
skl = { version = "0.4", features = ["memmap"] }
skl = { version = "0.5", features = ["memmap"] }
```

## Features

- **MVCC and 3D access**: Builtin MVCC (multiple versioning concurrency control) and key-value-version access support.
- **Lock-free and Concurrent-Safe:** SkipMap and SkipSet 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 and SkipSet offer a flexible foundation for key-value database developers. You can easily build your own memtable or write-ahead-log (WAL) 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 Expand Up @@ -85,10 +86,12 @@ Please see [examples](https://github.com/al8n/skl-rs/tree/main/examples) folder

## Pedigree

This code is inspired and modified based on Cockroachdb's pebble arenaskl code:
This code is inspired and modified based on Cockroachdb's pebble arenaskl and Dgraph's badger skl code:

https://github.com/cockroachdb/pebble/tree/master/internal/arenaskl

https://github.com/dgraph-io/badger/tree/master/skl

The pebble's arenaskl code is based on Andy Kimball's arenaskl code:

https://github.com/andy-kimball/arenaskl
Expand Down
62 changes: 7 additions & 55 deletions src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,32 +69,28 @@ impl Arena {

impl Arena {
#[inline]
const fn min_cap<const N: u64>() -> usize {
(N * 2) as usize
}

#[inline]
pub(super) fn new_vec<const N: u64>(n: usize) -> Self {
pub(super) fn new_vec(n: usize, min_cap: usize) -> Self {
Self::new(Shared::new_vec(
n.max(Self::min_cap::<N>()),
n.max(min_cap),
mem::align_of::<u64>().max(NODE_ALIGNMENT_FACTOR),
))
}

#[cfg(all(feature = "memmap", not(target_family = "wasm")))]
#[inline]
pub(super) fn new_mmap<const N: u64>(
pub(super) fn new_mmap(
n: usize,
min_cap: usize,
file: std::fs::File,
lock: bool,
) -> std::io::Result<Self> {
Shared::new_mmaped(n.max(Self::min_cap::<N>()), file, lock).map(Self::new)
Shared::new_mmaped(n.max(min_cap), file, lock).map(Self::new)
}

#[cfg(all(feature = "memmap", not(target_family = "wasm")))]
#[inline]
pub(super) fn new_anonymous_mmap<const N: u64>(n: usize) -> std::io::Result<Self> {
Shared::new_mmaped_anon(n.max(Self::min_cap::<N>())).map(Self::new)
pub(super) fn new_anonymous_mmap(n: usize, min_cap: usize) -> std::io::Result<Self> {
Shared::new_mmaped_anon(n.max(min_cap)).map(Self::new)
}

#[inline]
Expand Down Expand Up @@ -191,29 +187,6 @@ impl Arena {
}
}

impl Clone for Arena {
fn clone(&self) -> Self {
unsafe {
let shared: *mut Shared = self.inner.load(Ordering::Relaxed).cast();

let old_size = (*shared).refs.fetch_add(1, Ordering::Release);
if old_size > usize::MAX >> 1 {
abort();
}

// Safety:
// The ptr is always non-null, we just initialized it.
// And this ptr is only deallocated when the arena is dropped.
Self {
cap: (*shared).cap(),
inner: AtomicPtr::new(shared as _),
data_ptr: self.data_ptr,
n: self.n.clone(),
}
}
}
}

impl Drop for Arena {
fn drop(&mut self) {
unsafe {
Expand Down Expand Up @@ -255,24 +228,3 @@ impl Drop for Arena {
}
}
}

#[inline(never)]
#[cold]
fn abort() -> ! {
#[cfg(feature = "std")]
{
std::process::abort();
}

#[cfg(not(feature = "std"))]
{
struct Abort;
impl Drop for Abort {
fn drop(&mut self) {
panic!();
}
}
let _a = Abort;
panic!("abort");
}
}
16 changes: 15 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, allow(unused_attributes))]
#![deny(missing_docs)]
#![allow(clippy::type_complexity, clippy::mut_from_ref)]
#![allow(unexpected_cfgs, clippy::type_complexity, clippy::mut_from_ref)]

#[cfg(not(feature = "std"))]
extern crate alloc as std;
Expand Down Expand Up @@ -99,6 +99,20 @@ impl Comparator for Descend {
}
}

/// A trait for extra information that can be stored with entry in the skiplist.
pub trait Trailer: Copy {
/// Returns the version of the trailer.
fn version(&self) -> u64;
}

impl Trailer for u64 {
/// Returns the version of the trailer.
#[inline]
fn version(&self) -> u64 {
*self
}
}

mod sync {
#[cfg(not(loom))]
pub(crate) use core::sync::atomic::*;
Expand Down
Loading

0 comments on commit a159a34

Please sign in to comment.