LinHash
Concurrent Linear Hashing implementation in Rust.
Best suit for metadata store for a database.
What's good about Linear Hashing?
- It is a on-disk data structure to maintain key-value mappings.
- It doesn't use much RAM except temporary buffers.
- Since GETs need only one or two reads from the disk, it is very fast.
- The GET performance isn't affected by the database size.
- Concurrency is well studied in Concurrency in linear hashing.
- The algorithm is simple and elegant.
What's good about this implementation?
- GETs are never blocked by other operations except LIST.
- GETs and INSERTs are fully concurrent.
- Use rkyv's zero-copy deserialization for fast queries.
- Use RWF_ATOMIC flag for avoiding torn writes.
Type-safe concurrency
Each operation is designed to take a hierarchy of locks before doing its work. This is type-checked by Rust compiler.
| Read Lock | Selective Lock | Exclusive Lock | |
|---|---|---|---|
| Read Lock | ✅️ | ✅️ | ❌ |
| Selective Lock | ✅️ | ❌️ | ❌️ |
| Exclusive Lock | ❌️ | ❌️ | ❌️ |
| Operation | Root Lock | Bucket Lock |
|---|---|---|
| INSERT | Read Lock | Selective Lock |
| DELETE | Read Lock | Exclusive Lock |
| GET | Read Lock | Read Lock |
| LIST | Exclusive Lock | |
| SPLIT | Read Lock | Selective Lock |
Limitations
- Key size and value size must be fixed.
Example
The API is as same as HashMap.
use LinHash;
let dir = tempdir.unwrap;
let ksize = 2;
let vsize = 4;
let db = open.unwrap;
db.insert.unwrap;
let old = db.insert.unwrap;
assert_eq!;
assert_eq!;
let old = db.delete.unwrap;
assert_eq!;
assert_eq!;
Cargo Features
| flag | default | description |
|---|---|---|
| hash | on | Enabled → Hash function is used to calculate hash from key. Disabled → 64 bit from the given key is taken as a hash, eliminating the cost of hashing. |
| atomic-write | off | Enabled → writes are atomic using RWF_ATOMIC. Disabled → crash tolerance is not guaranteed but high speed. |