2 个版本

0.1.1 2024年1月21日
0.1.0 2024年1月1日

#25 in #memory-mapped

MIT 许可证

125KB
3.5K SLoC

Bitcasky

Crates.io MIT licensed codecov Build Status

Bitcasky 是 Bitcask 键值存储的 Rust 实现。它是一个符合 ACID 规范的只追加键值存储,提供高写入吞吐量。它针对高写入负载进行了优化,常用于日志存储和时间序列数据等应用。

功能

  • 只追加存储以提供持久性和一致性
  • 内存映射文件以实现高效的 I/O
  • 具有 O(1) 读写性能的键值存储
  • 存储可过期值

用法

基本用法

要使用 Bitcasky,只需将其添加到您的 Cargo.toml 文件中

[dependencies]
bitcasky = "0.1.2"

然后,在您的 Rust 代码中,导入 bitcasky 包并开始使用键值存储

use bitcasky::Bitcasky;

fn main() {
    let mut db = Bitcasky::open("/path/to/db", BitcaskyOptions::default()).unwrap()

    db.put("key", "value").unwrap();

    assert!(db.has("key").unwrap());

    let value = db.get("key").unwrap().unwrap();

    println!("{:?}", value);
}

存储可过期值

db.put_with_ttl("key", "value", Duration::from_secs(60)).unwrap();

// 60 seconds later
assert!(db.get("key").unwrap().is_none());

删除某些值或整个数据库

db.put("key1", "value1").unwrap();
db.put("key2", "value2").unwrap();

// delete some value
db.delete("key1").unwrap();
assert!(db.get("key1").unwrap().is_none());

// drop database
db.drop().unwrap();
assert!(db.get("key2").unwrap().is_none());

迭代数据库

迭代所有键。

// iterate and print all keys in database
bc.foreach_key(|k| println!("{}", String::from_utf8_lossy(k))).unwrap();

// fold all keys by concatenate them
let ret = bc.fold_key(
        |k, accumulator: Option<String>| match accumulator {
            // concatenate new key to folded key string
            Some(folded_k) => Ok(Some(folded_k + &String::from_utf8_lossy(k))),
            
            // if we have not fold anything, use this new key as folded key
            None => Ok(Some(String::from_utf8_lossy(k).into())),
        },
        // init accumulator
        None,
    )
    .unwrap();
assert!(ret.is_some());
println!("{}", ret.unwrap());

迭代所有键和值。

// iterate and print all keys and values in database
bc.foreach(|k, v| {
    println!(
        "key: {}, value: {}",
        String::from_utf8_lossy(k),
        String::from_utf8_lossy(v)
    )
})
.unwrap();

// fold all keys and values by concatenate them
let ret = bc
    .fold(
        |k, v, accumulator: Option<String>| match accumulator {
            // concatenate new key and value to folded values
            Some(folded_vals) => Ok(Some(format!(
                "{} key: {}, val: {};",
                folded_vals,
                String::from_utf8_lossy(k),
                String::from_utf8_lossy(v)
            ))),

            // if we have not fold anything, use this new key and value as folded values
            None => Ok(Some(format!(
                "key: {}, val: {};",
                String::from_utf8_lossy(k),
                String::from_utf8_lossy(v)
            ))),
        },
        // init accumulator
        None,
    )
    .unwrap();
assert!(ret.is_some());
println!("{}", ret.unwrap());

同步策略

通过选择同步策略,您可以通过指定何时将数据同步到磁盘来配置写入的持久性。

以下同步策略可用

  • None — 由操作系统管理同步写入
  • OSync — 使用 O_SYNC 标志,强制每次写入都进行同步
  • 时间间隔 — 在指定的时间间隔内同步(默认:60 秒)

例如,创建一个每 35 秒同步一次的 Bitcasky 数据库,如下所示

let db = Bitcasky::open(
        "/path/to/db", 
        BitcaskyOptions::default().sync_strategy(SyncStrategy::Interval(Duration::from_secs(35)))
    ).unwrap();

合并过程

Bitcasky 需要定期调用合并以减少磁盘使用。合并过程遍历数据文件,通过消除过期的或已删除的键值对来回收空间,只将当前键值对写入目录中的新文件集。

通过在 Bitcaksy 实例上调用 merge 来启动合并过程,如下所示

db.merge().unwrap();

许可证

本项目采用 MIT 许可证

依赖项

~4–13MB
~158K SLoC