#lsm-tree #persistence #column-family #embedded #rate-limiting

bin+lib rexrocksdb

Facebook's RocksDB 可嵌入数据库的 Rust 封装的分支

1 个不稳定发布

使用旧的 Rust 2015

0.3.2 2019 年 4 月 16 日

#1809数据库接口

Apache-2.0

9.5MB
208K SLoC

C++ 176K SLoC // 0.1% comments Java 19K SLoC // 0.3% comments Rust 6.5K SLoC // 0.1% comments Shell 2.5K SLoC // 0.2% comments Python 1.5K SLoC // 0.2% comments C 1.5K SLoC // 0.1% comments PowerShell 285 SLoC // 0.2% comments PHP 254 SLoC // 0.2% comments Bitbake 158 SLoC // 0.2% comments INI 107 SLoC // 0.2% comments JavaScript 94 SLoC // 0.0% comments

rust-rocksdb

此库已在 Linux 和 macOS 上针对 RocksDB 5.6.1 进行了测试。

状态

  • 基本打开/插入/获取/删除/关闭
  • Rustic 合并运算符
  • 写批处理(感谢 @dgrnbrg!)
  • 保存点
  • 压缩过滤器,样式
  • LRU 缓存
  • 销毁/修复
  • 迭代器
  • 比较器
  • 快照
  • 列族操作
  • 前缀搜索
  • 切片转换
  • 速率限制器
  • 统计信息
  • 恢复
  • 备份
  • 暂停/继续后台工作
  • 删除范围
  • 摄取外部 sst 文件
  • Windows 支持

欢迎反馈和拉取请求!如果您认为 RocksDB 的某个特性很重要,请通过创建问题让我们知道,我们将优先处理。

先决条件:RocksDB

首先,使用您的系统包管理器安装 snappy。这是可选的,但可以让 rocksdb 利用更好的压缩,并且某些代码可能需要它。

要安装 rocksdb,请参阅其安装指南。对于 Windows 用户,请确保您已启用 CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS 配置 rocksdb。

或启用功能 static-link,crate 将自动下载和编译 RocksDB,包括其依赖项。

cargo build --features static-link

运行

Cargo.toml
[dependencies.rocksdb]
git = "https://github.com/pingcap/rust-rocksdb.git"
代码
extern crate rocksdb;
use rocksdb::{DB, Writable};

fn main() {
    let mut db = DB::open_default("/path/for/rocksdb/storage").unwrap();
    db.put(b"my key", b"my value");
    match db.get(b"my key") {
        Ok(Some(value)) => println!("retrieved value {}", value.to_utf8().unwrap()),
        Ok(None) => println!("value not found"),
        Err(e) => println!("operational problem encountered: {}", e),
    }

    db.delete(b"my key");
}
执行多个写入的原子提交
extern crate rocksdb;
use rocksdb::{DB, WriteBatch, Writable};

fn main() {
    // NB: db is automatically freed at end of lifetime
    let mut db = DB::open_default("/path/for/rocksdb/storage").unwrap();
    {
        let mut batch = WriteBatch::new(); // WriteBatch and db both have trait Writable
        batch.put(b"my key", b"my value");
        batch.put(b"key2", b"value2");
        batch.put(b"key3", b"value3");
        db.write(batch); // Atomically commits the batch
    }
}
获取一个迭代器
extern crate rocksdb;
use rocksdb::{DB, Direction, IteratorMode};

fn main() {
    // NB: db is automatically freed at end of lifetime
    let mut db = DB::open_default("/path/for/rocksdb/storage").unwrap();
    let mut iter = db.iterator(IteratorMode::Start); // Always iterates forward
    for (key, value) in iter {
        println!("Saw {} {}", key, value); //actually, need to convert [u8] keys into Strings
    }
    iter = db.iterator(IteratorMode::End);  // Always iterates backward
    for (key, value) in iter {
        println!("Saw {} {}", key, value);
    }
    iter = db.iterator(IteratorMode::From(b"my key", Direction::forward)); // From a key in Direction::{forward,reverse}
    for (key, value) in iter {
        println!("Saw {} {}", key, value);
    }

    // You can seek with an existing Iterator instance, too
    iter.set_mode(IteratorMode::From(b"another key", Direction::reverse));
    for (key, value) in iter {
        println!("Saw {} {}", key, value);
    }
}
从快照获取迭代器
extern crate rocksdb;
use rocksdb::{DB, Direction};

fn main() {
    // NB: db is automatically freed at end of lifetime
    let mut db = DB::open_default("/path/for/rocksdb/storage").unwrap();
    let snapshot = db.snapshot(); // Creates a longer-term snapshot of the DB, but freed when goes out of scope
    let mut iter = snapshot.iterator(IteratorMode::Start); // Make as many iterators as you'd like from one snapshot
}
Rustic 合并运算符
extern crate rocksdb;
use rocksdb::{Options, DB, MergeOperands, Writable};

fn concat_merge(new_key: &[u8], existing_val: Option<&[u8]>,
    operands: &mut MergeOperands) -> Vec<u8> {
    let mut result: Vec<u8> = Vec::with_capacity(operands.size_hint().0);
    existing_val.map(|v| {
        for e in v {
            result.push(*e)
        }
    });
    for op in operands {
        for e in op {
            result.push(*e)
        }
    }
    result
}

fn main() {
    let path = "/path/to/rocksdb";
    let mut opts = Options::new();
    opts.create_if_missing(true);
    opts.add_merge_operator("test operator", concat_merge);
    let mut db = DB::open(&opts, path).unwrap();
    let p = db.put(b"k1", b"a");
    db.merge(b"k1", b"b");
    db.merge(b"k1", b"c");
    db.merge(b"k1", b"d");
    db.merge(b"k1", b"efg");
    let r = db.get(b"k1");
    assert!(r.unwrap().unwrap().to_utf8().unwrap() == "abcdefg");
}
应用一些调整

请阅读 官方调整指南,最重要的是,在真实硬件和真实工作负载下测量性能。

use rocksdb::{Options, DB};
use rocksdb::DBCompactionStyle::DBUniversalCompaction;

fn badly_tuned_for_somebody_elses_disk() -> DB {
    let path = "_rust_rocksdb_optimizetest";
    let mut opts = Options::new();
    opts.create_if_missing(true);
    opts.set_max_open_files(10000);
    opts.set_use_fsync(false);
    opts.set_bytes_per_sync(8388608);
    opts.set_disable_data_sync(false);
    opts.set_block_cache_size_mb(1024);
    opts.set_table_cache_num_shard_bits(6);
    opts.set_max_write_buffer_number(32);
    opts.set_write_buffer_size(536870912);
    opts.set_target_file_size_base(1073741824);
    opts.set_min_write_buffer_number_to_merge(4);
    opts.set_level_zero_stop_writes_trigger(2000);
    opts.set_level_zero_slowdown_writes_trigger(0);
    opts.set_compaction_style(DBUniversalCompaction);
    opts.set_max_background_compactions(4);
    opts.set_max_background_flushes(4);
    opts.set_disable_auto_compactions(true);

    DB::open(&opts, path).unwrap()
}

依赖项

~6MB
~102K SLoC