#数据库引擎 #键值存储 #嵌入式数据库 #数据库 #原子性 #memdb #memodb

async-skipdb

一个嵌入式、内存中、零拷贝、原子性、一致性、MVCC、几乎无锁且可序列化快照隔离的数据库引擎

2 个版本

0.2.1 2024年4月27日
0.2.0 2024年4月27日
0.1.5 2024年4月25日

#117 in 并发

Download history 499/week @ 2024-04-22 52/week @ 2024-04-29 2/week @ 2024-06-10 2/week @ 2024-06-17 2/week @ 2024-06-24 79/week @ 2024-07-01 21/week @ 2024-07-08 57/week @ 2024-07-22 42/week @ 2024-07-29 31/week @ 2024-08-05

130 次每月下载

MIT/Apache

300KB
8K SLoC

Async SkipDB

一个嵌入式、内存中、零拷贝、原子性、一致性、MVCC、几乎无锁且可序列化快照隔离的数据库引擎。

github Build codecov license

LoC docs.rs crates.io crates.io

英文 | 简体中文

介绍

一个嵌入式、内存中、零拷贝、MVCC、几乎无锁且可序列化快照隔离的数据库引擎。

async-skipdb 的 SSI(可序列化快照隔离)事务模型参考了 foundationdb 的论文badger

同步版本请参见 skipdb

该 crate 包含两种内存中的键值数据库

  1. SerializableDb

    支持并发执行完全可序列化快照隔离事务和乐观并发控制事务。

    通过 SerializableDb::serializable_write 创建的事务可以正确处理所有类型的写偏斜。

    通过 SerializableDb::optimistic_write 创建的事务可以处理所有类型的直接依赖写偏斜,但不能处理所有类型的间接依赖写偏斜,例如 https://wiki.postgresql.ac.cn/wiki/SSI#Intersecting_Data

  2. OptimisticDb

    仅支持乐观并发控制的并发执行,这意味着写事务无法检测所有类型的写偏斜。

    可以正确处理所有类型的直接依赖写偏斜,但不能处理所有类型的间接依赖写偏斜,例如 https://wiki.postgresql.ac.cn/wiki/SSI#Intersecting_Data

特性

  • 原子性、一致性、隔离性、MVCC、并发安全且几乎无锁。
  • 没有额外的分配和复制,数据库中存储的键和值都没有 Arc 包装器,这意味着用户提供 KV,数据库直接存储 KV
  • 零拷贝和原地压缩,意味着在压缩时没有拷贝,没有额外的分配。
  • 事务并发执行,提供可序列化快照隔离,避免写倾斜。
  • 读事务和写事务都是 Send + Sync + 'static,这意味着您不再需要处理烦人的生命周期问题。
  • 无锁且并发安全的读事务:读事务完全并发安全,可以在多个线程中共享,读事务中没有锁。
  • BTreeMap 类的用户友好 API 和所有迭代器实现 Iterator 特性,这意味着用户在遍历数据库时可以使用 Rust 强大的组合器。
  • 运行时无关,支持 tokioasync-stdsmolwasm-bindgen-futures 和任何其他异步运行时。
  • 100% 安全,使用 [forbid(unsafe_code)]

安装

  • tokio

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

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

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

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

示例

use async_skipdb::serializable::TokioSerializableDb;

#[derive(Debug)]
struct Person {
  name: String,
  hobby: String,
  age: u8,
}

#[tokio::main]
async fn main() {
  let db: TokioSerializableDb<u64, Person> = TokioSerializableDb::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.serializable_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"); 
  }
}

许可协议

async-skipdb 同时遵守 MIT 许可协议和 Apache 许可协议(版本 2.0)。

有关详细信息,请参阅 LICENSE-APACHELICENSE-MIT

版权所有 (c) 2024 Al Liu。

依赖项

~3–15MB
~194K SLoC