3 releases (breaking)
0.3.0 | Sep 29, 2024 |
---|---|
0.2.0 | Sep 27, 2024 |
0.1.0 | Sep 25, 2024 |
#143 in Memory management
126 downloads per month
31KB
717 lines
Rust SkipList
A Rust implementation of the SkipList data structure, inspired by LevelDB's SkipList. This project provides a SkipList implementation with lock-free reads and locked writes, suitable for efficient key-value storage and retrieval.
Features
- Lock-free read operations
- Efficient insertion (with locking) and lookup
- Iterator support for traversal
- Configurable maximum height and branching factor
- Written in safe Rust with minimal unsafe code
- Memory management through a shared Arena allocator
- No explicit delete operation (following LevelDB's design)
Memory Management
The SkipList uses a shared Arena
for memory allocation. This means:
- All nodes are allocated from the Arena
- There's no need for manual memory deallocation
- The entire SkipList is deallocated when the Arena is dropped
Usage
Add this to your Cargo.toml
:
[dependencies]
skiplist-rust = "0.3.0"
Then you can use the SkipList in your Rust code:
use skiplist_rust::{SkipList, SkipListIterator};
use skiplist_rust::arena::Arena;
use std::sync::Arc;
fn main() {
let arena = Arena::new();
let skiplist = Arc::new(SkipList::new(arena));
let mut write_handles = vec![];
for i in 0..5 {
let skiplist_clone = Arc::clone(&skiplist);
let handle = thread::spawn(move || {
let start = i * 100;
let end = start + 100;
for k in start..end {
skiplist_clone.insert(k);
println!("Thread {} inserted: {}", i, k);
}
});
write_handles.push(handle);
}
let mut read_handles = vec![];
for i in 0..3 {
let skiplist_clone = Arc::clone(&skiplist);
let handle = thread::spawn(move || {
let mut rng = rand::thread_rng();
let start = i * 100;
let end = start + 100;
for _ in start..end {
let key = rng.gen_range(0..1000);
let contains = skiplist_clone.contains(&key);
println!("Thread {} queried: {}, result: {}", i, key, contains);
thread::sleep(Duration::from_millis(1));
}
});
read_handles.push(handle);
}
for handle in write_handles {
handle.join().unwrap();
}
for handle in read_handles {
handle.join().unwrap();
}
let mut iter = skiplist.iter();
iter.seek_to_first();
println!("Final SkipList contents:");
while iter.valid() {
println!("{:?}", iter.key());
iter.next();
}
}
API
Arena
new() -> Arena
: Create a new Arenaallocate(bytes: usize) -> *mut u8
: Allocate memory of the specified sizeallocate_aligned(bytes: usize) -> *mut u8
: Allocate memory of the specified size with alignmentmemory_usage(&self) -> usize
: Get the current memory usage of the arena
SkipList<K>
-
new(arena: Arena) -> SkipList<K>
: Create a new SkipListCreates and returns a new
SkipList
instance using the provided memory arena. -
insert(key: K)
: Insert a key into the SkipList (requires locking)Inserts the given key into the SkipList. This operation acquires a write lock to ensure thread-safe modification.
-
contains(&key: &K) -> bool
: Check if a key exists in the SkipList (lock-free)Checks whether the given key exists in the SkipList. This is a lock-free operation that allows concurrent reads.
-
iter(&self) -> SkipListIterator<K>
: Get an iterator over the SkipList (lock-free)Returns an iterator that can be used to traverse the elements in the SkipList. This operation is lock-free, allowing concurrent iteration with other operations.
SkipListIterator<K>
new(list: &SkipList<K>) -> SkipListIterator<K>
: Create a new iterator over a SkipListvalid(&self) -> bool
: Check if the iterator is pointing to a valid nodekey(&self) -> &K
: Get the key of the current nodenext(&mut self)
: Move to the next nodeprev(&mut self)
: Move to the previous nodeseek(&mut self, target: &K)
: Seek to the first node with a key >= targetseek_to_first(&mut self)
: Seek to the first nodeseek_to_last(&mut self)
: Seek to the last node
Performance
This implementation aims to provide similar performance characteristics to LevelDB's SkipList. It uses atomic operations for concurrent read access and locking for write operations, providing a balance between concurrency and data consistency.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License.
Acknowledgments
- Inspired by LevelDB's SkipList implementation
- Built with Rust's powerful type system and memory safety guarantees
Dependencies
~320KB