KaNiLS

Kind and Nice tool for Lump Storage

Rustで書かれたKey-Valueストア CannyLS の基本機能を、コマンドラインから用いるためのツールです。

CannyLSの基本的な仕組み

KaNiLSのビルド

KaNiLSはRustで書かれています。
Rustの開発環境がインストールされていない場合は rustup などを用いてインストールしてください。
(参考: https://www.rust-lang.org/ja-JP/install.html)

kanils$ cargo build (or cargo build --release)

KaNiLSの機能

KaNiLSを使ったCannyLSストレージの操作

```

2048バイトをデータ領域に割り当てるようなストレージファイルを作成

$ ./kanils Create --storage demo.lusf --capacity 2048

passed data region size = 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

(key=42, value="test_string")の組をストレージにput

$ ./kanils Put --storage demo.lusf --key 42 --value teststring put key=42, value=teststring

(key=7, value="🦀")の組をストレージにput

$ ./kanils Put --storage demo.lusf --key 7 --value 🦀
put key=7, value=🦀

現在のストレージ中のデータ領域をダンプ

$ ./kanils Dump --storage demo.lusf (LumpId("00000000000000000000000000000007"), "🦀") (LumpId("0000000000000000000000000000002a"), "test_string")

現在のストレージ中のジャーナル領域をダンプ

$ ./kanils Journal --storage demo.lusf journal [unreleased head] position = 0 journal [head] position = 0 journal [tail] position = 56 JournalEntry { 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 }) }

key=42を持つデータを削除

$ ./kanils Delete --storage demo.lusf --key 42 delete result => true

削除されたかどうかを確認

$ ./kanils Dump --storage demo.lusf (LumpId("00000000000000000000000000000007"), "🦀")

ジャーナル領域を確認

ジャーナルファイルシステムと同じ様に、ジャーナル領域には操作を記録していくので、

PUTに対するDELETEの場合でも、データ領域のように打ち消し合って消えることはない

$ ./kanils Journal --storage demo.lusf journal [unreleased head] position = 0 journal [head] position = 0 journal [tail] position = 77 JournalEntry { 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")) }

ジャーナル領域へのGC

ただし、ジャーナル領域へのGCを実行することで、ジャーナル側の情報のうち、削除しても問題がないことが分かっているものを消すことができる。

削除しても問題がないジャーナルエントリ(もしくはGC対象になるジャーナルエントリ)についての詳細は

https://github.com/frugalos/cannyls/wiki/Journal-Region-GC を参照

$ ./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 JournalEntry { start: Address(77), record: Put(LumpId("00000000000000000000000000000007"), DataPortion { start: Address(1), len: 1 }) }

$ ./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

5件目のデータを書き込もうとするとエラーになる。

これは2048バイトをデータ領域に確保しており、かつ512バイトを1書き込みに使っているからである。

$ ./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

passed data region size = 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 = 56 JournalEntry { 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 = 77 JournalEntry { 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 = 105 JournalEntry { 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. ```