#lsm-tree #persistence #嵌入式数据库 #嵌入式

bin+lib susy-rocksdb

Facebook 的 RocksDB 嵌入式数据库的 Rust 封装

1 个不稳定版本

使用旧的 Rust 2015

0.5.0 2019年3月16日

#1833数据库接口

每月 26 次下载

Apache-2.0

10MB
223K SLoC

C++ 190K SLoC // 0.1% comments Java 24K SLoC // 0.3% comments Shell 2.5K SLoC // 0.2% comments Rust 2K SLoC // 0.1% comments C 1.5K SLoC // 0.1% comments Python 1.5K SLoC // 0.2% comments GNU Style Assembly 538 SLoC // 0.1% comments PowerShell 312 SLoC // 0.2% comments PHP 254 SLoC // 0.2% comments Bitbake 143 SLoC // 0.2% comments INI 107 SLoC // 0.2% comments JavaScript 94 SLoC // 0.0% comments

rust-rocksdb

此库已在 Linux 和 OSX 上与 RocksDB 3.13.1 进行了测试。0.3.5 crate 应该可以从 2016 年 5 月 1 日起与 Rust 1.5 稳定版和夜间版一起使用。

分支特性

此分支添加了以下功能

  • 从源代码构建 RocksDB。请注意,如果系统未检测到库,则仅构建库。
  • 前缀查找。

状态

  • 基本打开/设置/获取/删除/关闭
  • rustic 合并运算符
  • 写批处理(感谢 @dgrnbrg!)
  • 压缩过滤器,风格
  • LRU 缓存
  • 销毁/修复
  • 迭代器
  • 比较器
  • 快照
  • 列族操作
  • 前缀查找
  • 切片转换
  • 窗口支持

欢迎反馈和拉取请求!如果您特别关注 RocksDB 的某个特性,请通过 打开一个问题 告诉我们,我们将优先处理。

先决条件:Snappy

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

运行

Cargo.toml
[dependencies]
rocksdb = { git = "https://github.com/arkpar/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_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_filter_deletes(false);
    opts.set_disable_auto_compactions(true);

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

依赖关系