Rustで書かれたKey-Valueストア CannyLS の基本機能を、コマンドラインから用いるためのツールです。
O_DIRECT
を用いた読み書きを行うことに起因している KaNiLSはRustで書かれています。
Rustの開発環境がインストールされていない場合は rustup などを用いてインストールしてください。
(参考: https://www.rust-lang.org/ja-JP/install.html)
$ git clone https://github.com/frugalos/kanils
$ cd kanils
kanils$ cargo build # この場合は target/debug に kanilsバイナリができます
kanils$ cargo build --release # この場合は target/release に kanilsバイナリができます
$ cargo install kanils
kanils Create --storage=storage_path --capacity=num
storage_path
に、num
バイトをデータ領域にもつcannylsストレージファイル(lusfファイルと呼ぶ)が作成されるkanils Put --storage=storage_path --key=num(128bit) --value=string
storage_path
のlusfファイルに、key-valueペア<num, string>
を追加num
が存在する場合は上書きが行われるkanils Get --storage=storage_path --key=num(128bit)
storage_path
のlusfファイル中のデータをkey num
を用いて読み込むkanils Delete --storage=storage_path --key=num(128bit)
storage_path
のlusfファイル中のデータをkey num
を用いて削除するkanils Header --storage=storage_path
kanils Dump --storage=storage_path
kanils Journal --storage=storage_path
kanils JournalGC --storage=storage_path
kanils Open --storage=storage_path
storage_path
を開き、対話モードに入るput key value
, get key
, delete key
, dump
, header
, journal
, journal_gc
```
$ ./kanils Create --storage demo.lusf --capacity 2048
actual data region size = 2048 actual journal size = 1536 actual journal size ratio = 0.42857142857142855
$ ./kanils Header --storage demo.lusf header => major version = 1 minor version = 1 block size = 512 uuid = 731d2970-b03f-4f1b-9da8-8b4617ace5fc journal region size = 1536 // ジャーナル領域全体のサイズは以下2つからなる journal header size = 512 // ジャーナル領域のメタ情報を格納するヘッダ部分 journal record size = 1024 // ジャーナルエントリを実際に書き込む部分 data region size = 2048 storage header size => 512 storage total size = 4096
$ ./kanils Put --storage demo.lusf --key 42 --value teststring put key=42, value=teststring
$ ./kanils Put --storage demo.lusf --key 7 --value 🦀
put key=7, value=🦀
$ ./kanils Dump --storage demo.lusf
$ ./kanils Journal --storage demo.lusf
journal [unreleased head] position = 0
journal [head] position = 0
journal [tail] position = 56
$ ./kanils Delete --storage demo.lusf --key 42 delete result => true
$ ./kanils Dump --storage demo.lusf
$ ./kanils Journal --storage demo.lusf
journal [unreleased head] position = 0
journal [head] position = 0
journal [tail] position = 77
$ ./kanils JournalGC --storage demo.lusf run journal full GC ... journal full GC succeeded!
$ ./kanils Journal --storage demo.lusf
journal [unreleased head] position = 77
journal [head] position = 77
journal [tail] position = 105
$ ./kanils Put --storage demo.lusf --key 100 --value x put key=100, value=x
$ ./kanils Put --storage demo.lusf --key 200 --value y put key=200, value=y
$ ./kanils Put --storage demo.lusf --key 300 --value z put key=300, value=z
$ ./kanils Put --storage demo.lusf --key 400 --value o
thread 'main' panicked at '
EXPRESSION: self.storage.put(&lumpid, &lumpdata)
ERROR: StorageFull (cause; assertion failed: self.allocator.allocate(block_size).is_some()
)
HISTORY:
[0] at /Users/ferris/.cargo/git/checkouts/cannyls-3a0f9a30cf1773f1/281ae5b/src/storage/data_region.rs:58
[1] at /Users/ferris/.cargo/git/checkouts/cannyls-3a0f9a30cf1773f1/281ae5b/src/storage/mod.rs:350
[2] at /Users/ferris/.cargo/git/checkouts/cannyls-3a0f9a30cf1773f1/281ae5b/src/storage/mod.rs:206
[3] at src/main.rs:165
', src/main.rs:165:22
note: Run with RUST_BACKTRACE=1
for a backtrace.
```
--storage storage_path
を逐一指定するのが面倒な場合は、Create
した後にOpen
すると良い。
上の一連の作業は、対話モードでは次のようになる: ``` $ ./kanils Create --storage demo.lusf --capacity 2048
actual data region size = 2048 actual journal size = 1536 actual journal size ratio = 0.42857142857142855
$ ./kanils Open --storage demo.lusf
put 42 teststring put key=42, value=teststring put 7 🦀 put key=7, value=🦀 dump
(LumpId("00000000000000000000000000000007"), "🦀") (LumpId("0000000000000000000000000000002a"), "teststring") journal journal [unreleased head] position = 0 journal [head] position = 0 journal [tail] position = 56JournalEntry { start: Address(0), record: Put(LumpId("0000000000000000000000000000002a"), DataPortion { start: Address(0), len: 1 }) } JournalEntry { start: Address(28), record: Put(LumpId("00000000000000000000000000000007"), DataPortion { start: Address(1), len: 1 }) } delete 42 delete result => true dump(LumpId("00000000000000000000000000000007"), "🦀") journal journal [unreleased head] position = 0 journal [head] position = 0 journal [tail] position = 77JournalEntry { start: Address(0), record: Put(LumpId("0000000000000000000000000000002a"), DataPortion { start: Address(0), len: 1 }) } JournalEntry { start: Address(28), record: Put(LumpId("00000000000000000000000000000007"), DataPortion { start: Address(1), len: 1 }) } JournalEntry { start: Address(56), record: Delete(LumpId("0000000000000000000000000000002a")) } journalgc run journal full GC ... journal full GC succeeded! journal journal [unreleased head] position = 77 journal [head] position = 77 journal [tail] position = 105JournalEntry { start: Address(77), record: Put(LumpId("00000000000000000000000000000007"), DataPortion { start: Address(1), len: 1 }) } put 100 x put key=100, value=x put 200 y put key=200, value=y put 300 z put key=300, value=z put 400 o thread 'main' panicked at ' EXPRESSION: self.storage.put(&lumpid, &lumpdata) ERROR: StorageFull (cause; assertion failed:self.allocator.allocate(block_size).is_some()
) HISTORY: [0] at /Users/ferris/.cargo/git/checkouts/cannyls-3a0f9a30cf1773f1/281ae5b/src/storage/data_region.rs:58 [1] at /Users/ferris/.cargo/git/checkouts/cannyls-3a0f9a30cf1773f1/281ae5b/src/storage/mod.rs:350 [2] at /Users/ferris/.cargo/git/checkouts/cannyls-3a0f9a30cf1773f1/281ae5b/src/storage/mod.rs:206 [3] at src/main.rs:165
', src/main.rs:165:22
note: Run with RUST_BACKTRACE=1
for a backtrace.
```
```
kanils RandomGetBench --storage test.lusf --count 1000 --size 3MB
以下は出力の例
[src/bench.rs:91] path.clone() = "test.lusf"
[src/bench.rs:91] count = 1000
[src/bench.rs:91] size = 3145728
[Putting Data] start
[00:00:03] [########################################] 1000/1000 (0s, done)
[Putting Data] finish @ 3s 507ms
[Getting Data] start
[00:00:03] [########################################] 1000/1000 (0s, done)
[Getting Data] finish @ 3s 539ms
```