1个稳定版本

1.0.0 2022年12月2日

#103数据库实现

MIT 许可证

1MB
16K SLoC

RainDB

基于LSM树实现的持久化键值存储库

Build Status

动机和目标

本项目更像是一个玩具项目和学习数据库内部结构的工具。因此,代码将被尽可能注释。我们希望通过结构化的代码、避免“优雅”的技巧以及冗余的文档来实现高可读性。设计文档、生成的API文档以及代码中都会详细阐述概念和推理。无论您最擅长通过阅读代码还是阅读文档来学习,信息通常会在多个区域重复,以便于跟随。

RainDB 追求高性能,也不追求与LevelDB的二进制兼容性。尽管如此,这些仍将是美好的副作用😀。尽管不追求二进制兼容性,但行为在很大程度上是相同的(即直接移植),并使用LevelDB的相同测试用例来检查这种一致性。

高级设计

RainDB的存储引擎是一个LSM树,并且具有/将具有以下传统组件:

  1. Memtable - 初始为跳表,但将来可以用其他数据结构进行交换
  2. 表文件
  3. 写入前日志

如上所述,RainDB的LSM树是一个双层系统,包含内存中的memtable和可持久化到单个存储介质的表文件。表文件存储可以在磁盘上,但也提供了内存存储(通常用于测试目的)。

有关架构和设计的更多信息,请参阅文档文件夹。

使用方法

use raindb::{DbOptions, ReadOptions, WriteOptions, DB};

// Use the default options to create a database that uses disk to store table files
let options = DbOptions {
    create_if_missing: true,
    ..DbOptions::default()
};

// Optionally handle any errors that can occur when opening the database
let db = DB::open(options).unwrap();

db.put(
    WriteOptions::default(),
    "some_key".into(),
    "some_value".into(),
).unwrap();

let read_result = db.get(ReadOptions::default(), "some_key".as_bytes()).unwrap();

使用内存存储

use raindb::{DbOptions, DB};
use raindb::fs::{FileSystem, InMemoryFileSystem};

let options = DbOptions {
    create_if_missing: true,
    ..DbOptions::with_memory_env()
};

// OR
let mem_fs: Arc<dyn FileSystem> = Arc::new(InMemoryFileSystem::new());
let options = DbOptions {
    filesystem_provider: Arc::clone(&mem_fs),
    create_if_missing: true,
    ..DbOptions::default()
};

let db = DB::open(options).unwrap();

其他使用示例

示例文件夹包含了一些如何将RainDB嵌入应用程序中的示例。我通常不喜欢查阅源代码来获取示例,但db/db_test.rs模块包含了许多公共API的使用示例。

血统

本项目大量借鉴了LevelDB的现有工作。对创造者将如此多的设计文档与代码本身一同提供的感谢。由于本项目在LevelDB的基础上进行了大量工作,一些选项和文档直接从中获取。

灵感也来源于LevelDB的Go端口dermesser的Rust端口

在文档注释中,如果做出了与LevelDB不同的策略性决策,将会有一个Legacy标题。这可以包括名称更改,以便在RainDB和LevelDB之间仍可以找到对应关系。

许多测试也是从LevelDB中提取的,以确保行为的一致性。

其他艺术

未来想法

  • 与Raft用于领导者选举的分布式存储一起使用
    • 添加数据分片

参考文献

免责声明

这不是一个官方支持的谷歌产品。

依赖关系

~4–13MB
~152K SLoC