はじめに
状態を保っていてcrudな操作をするようなcliをRustで作ろうとした時に、
sqliteなど外部ツールに依存するのもアレだなと思って、
パス1個渡すだけで、ファイルなりにcrudな操作ができる、DBみたいなライブラリがあれば良いなと思って調べていました。
すると、sledという組み込み向けのそれっぽいライブラリがあり、
スターが1800くらい付いていて、
サンプルを見た感じ、path1個通すだけで済んでcrudな操作も出来そうなので、少し触ってみました。
*載せてる公式のサンプルコードやライブラリのAPIは2019/03/10現在のものです
// https://github.com/spacejam/sled#sled
use sled::Db;
let tree = Db::start_default(path)?;
// set and get
tree.set(k, v1);
assert_eq!(tree.get(&k), Ok(Some(v1)));
// compare and swap
tree.cas(k, Some(v1), Some(v2));
// scan forward
let mut iter = tree.scan(k);
assert_eq!(iter.next(), Some(Ok((k, v2))));
assert_eq!(iter.next(), None);
// deletion
tree.del(&k);
// block until all operations are on-disk
tree.flush();
触ってみる
↓dependenciesにsledを追加する
# ...省略
[dependencies]
sled = "0.19.0"
↓ストレージ用のディレクトリを作成する
// projectのルートに作る
$ mkdir test_storage
$ tree -L 1
.
├── Cargo.lock
├── Cargo.toml
├── src
├── target
+ └── test_storage
↓こんな感じにmain.rsを書いて
extern crate sled;
use sled::Db;
fn main() {
let path = "test_storage";
let tree = Db::start_default(path).unwrap();
}
cargo runする
(test_storage以下にそれっぽいファイルとかが増えていればひとまず動いていそう)
$ cargo run
$ tree -L 2
.
├── Cargo.lock
├── Cargo.toml
├── src
│ └── main.rs
├── target
│ └── debug
└── test_storage
+ ├── blobs
+ ├── conf
+ ├── db
+ └── snap.0000000000000000
setしてgetするだけの単純なコードを書いてみる
extern crate sled;
use sled::Db;
fn main() {
let dir_path = "test_storage";
let tree = Db::start_default(dir_path).unwrap();
let key = "hoge";
let value = "abcdefg";
// `API similar to a threadsafe BTreeMap<Vec<u8>, Vec<u8>>` とのこと。
// tree.setのvalueのtypeも `type Value = Vec<u8>;`
// を要求しているので、`as_bytes().to_vec()`を噛ませる
tree.set(&key, value.as_bytes().to_vec())
.expect("set fail");
match tree.get(&key) {
Ok(Some(res)) => {
let converted: String = String::from_utf8(res.to_vec()).unwrap();
assert_eq!(value,converted);
println!("{}", converted); // abcdefg
}
_ => {}
}
}
公式のサンプルにも書いてあるが、set,get以外にもupdate(swap)したり、scanしたり、deleteしたり、簡単な操作は一通りできるよう。
// compare and swap
tree.cas(k, Some(v1), Some(v2));
// scan forward
let mut iter = tree.scan(k);
assert_eq!(iter.next(), Some(Ok((k, v2))));
assert_eq!(iter.next(), None);
// deletion
tree.del(&k);
// block until all operations are on-disk
tree.flush();
}
良いところ、イマイチなところ
sledの良いところ
- ディレクトリのパス1個渡すだけで、使える
- sqliteなど使わずにrust単体でちょっとしたツールが作れそう
sledのイマイチなところ
- 2019/03/10時点でまだアルファ版
- 32bit環境はnightly版で動かさないといけなさそう
- test_storageの中にdbというファイルが生成され、雰囲気的にこのファイルにガリガリ書き込んでいく様子
- append onlyなのか
tree.flush()
を走らせても中身は削除されず、tree.set()のたびにファイルがどんどん大きくなるようだった。 - (もしかしたら、そういうものなのかもしれない。)
- append onlyなのか
まとめ
まだアルファ版なのと、setするとひたすらでかくなるファイルが気になりますが、
ディレクトリのパス1個だけ渡すだけですぐに使えるのと、
rust単体で完結しそうなのでポータビリティ高めなツールが作れそうな気がしました。