async-skipdb 0.1.3

An embedded, in-memory, ACID, MVCC, almost lock-free and serializable snapshot isolation database engine.
Documentation
async-skipdb-0.1.3 has been yanked.

Blazing fast ACID and MVCC in memory database based on lock-free skiplist.

async-skipdb uses the same SSI (Serializable Snapshot Isolation) transaction model used in badger.

English | 简体中文

Introduction

Blazing fast ACID and MVCC in memory database based on lock-free skiplist.

async-skipdb uses the same SSI (Serializable Snapshot Isolation) transaction model used in badger.

For sync version, please see skipdb.

Features

  • ACID, MVCC, serializable snapshot isolation, concurrent safe and almost lock-free.
  • No extra allocation and copy, there is no Arc wrapper for both key and value stored in the database, which means that users provide K and V, and database store K and V directly.
  • Zero-copy and in-place compaction, which means there is no copy, no extra allocation when compacting.
  • Concurrent execution of transactions, providing serializable snapshot isolation, avoiding write skews.
  • Both read transaction and write transaction are Send + Sync + 'static, which means you do not need to handle annoying lifetime problem anymore.
  • Lock-free and concurrent safe read transaction: the read transaction is totally concurrent safe and can be shared in multiple threads, there is no lock in read transaction.
  • BTreeMap like user friendly API and all iterators implement Iterator trait, which means users use Rust powerful conbinators when iterating over the database.
  • Runtime agnostic, tokio, async-std, smol, wasm-bindgen-futures and any other async runtime.
  • 100% safe, sets [forbid(unsafe_code)].

Installation

  • tokio

    [dependencies]
    async-skipdb = { version = "0.1", features = ["tokio"] }
    
  • async-std

    [dependencies]
    async-skipdb = { version = "0.1", features = ["async-std"] }
    
  • smol

    [dependencies]
    async-skipdb = { version = "0.1", features = ["smol"] }
    
  • wasm-bindgen-futures

    [dependencies]
    async-skipdb = { version = "0.1", features = ["wasm"] }
    

Example

  • If your K implement Hash.

    use async_skipdb::equivalent::TokioEquivalentDb;
    
    #[derive(Debug)]
    struct Person {
      hobby: String,
      age: u8,
    }
    
    #[tokio::main]
    async fn main() {
      let db: TokioEquivalentDb<String, Person> = TokioEquivalentDb::new().await;
      
      {
        let alice = Person { hobby: "swim".to_string(), age: 20 };
        let bob = Person { hobby: "run".to_string(), age: 30 };
    
        let mut txn = db.write().await;
        txn.insert("Alice".to_string(), alice).unwrap();
        txn.insert("Bob".to_string(), bob).unwrap();
    
        {
          let alice = txn.get("Alice").unwrap().unwrap();
          assert_eq!(alice.value().age, 20);
          assert_eq!(alice.value().hobby, "swim");
        }
    
        txn.commit().await.unwrap();
      }
    
      {
        let txn = db.read().await;
        let alice = txn.get("Alice").unwrap();
        assert_eq!(alice.value().age, 20);
        assert_eq!(alice.value().hobby, "swim");
    
        let bob = txn.get("Bob").unwrap();
        assert_eq!(bob.value().age, 30);
        assert_eq!(bob.value().hobby, "run"); 
      }
    }
    
  • If your key cannot implement Hash for some reasons.

    Then you can use ComparableDb, but this will require K: CheapClone + Ord, you can see cheap_clone trait for more details.

    use async_skipdb::comparable::TokioComparableDb;
    
    #[derive(Debug)]
    struct Person {
      name: String,
      hobby: String,
      age: u8,
    }
    
    #[tokio::main]
    async fn main() {
      let db: TokioComparableDb<u64, Person> = TokioComparableDb::new().await;
    
      {
        let alice = Person { name: "Alice".to_string(), hobby: "swim".to_string(), age: 20 };
        let bob = Person { name: "Bob".to_string(), hobby: "run".to_string(), age: 30 };
    
        let mut txn = db.write().await;
        txn.insert(1, alice).unwrap();
        txn.insert(2, bob).unwrap();
    
        {
          let alice = txn.get(&1).unwrap().unwrap();
          assert_eq!(alice.value().name, "Alice");
          assert_eq!(alice.value().age, 20);
          assert_eq!(alice.value().hobby, "swim");
        }
    
        txn.commit().await.unwrap();
      }
    
      {
        let txn = db.read().await;
        let alice = txn.get(&1).unwrap();
        assert_eq!(alice.value().name, "Alice");
        assert_eq!(alice.value().age, 20);
        assert_eq!(alice.value().hobby, "swim");
    
        let bob = txn.get(&2).unwrap();
        assert_eq!(bob.value().name, "Bob");
        assert_eq!(bob.value().age, 30);
        assert_eq!(bob.value().hobby, "run"); 
      }
    }
    

License

async-skipdb is under the terms of both the MIT license and the Apache License (Version 2.0).

See LICENSE-APACHE, LICENSE-MIT for details.

Copyright (c) 2024 Al Liu.