プログラミング
TurboKV: 驚異的に高速なRust製キーバリューストア
TurboKV: Insanely fast Rust key-value store (github.com)
要約
TurboKVはRustで書かれた非同期組み込み型キーバリューストアで、アトミックバッチ処理、順序付き範囲スキャン、設定可能な耐久性、圧縮、バックグラウンドコンパクションなどの機能を備えています。パフォーマンス向上のためのハードウェアAESやCPU固有の最適化もサポートしています。
全文翻訳
Rust製の高速な組み込み型キーバリューストア
TurboKVは、アトミックバッチ、順序付き範囲スキャン、設定可能な耐久性、圧縮、バックグラウンドコンパクションを備えた非同期組み込み型キーバリューストアです。
インストール
cargo add turbokv
cargo add tokio --features full
または依存関係を直接追加します:
[dependencies]
turbokv = "0.6"
tokio = { version = "1", features = ["full"] }
TurboKVの永続化されたブルームフィルタ形式はハードウェアAESを使用します。
RUSTFLAGS="-C target-feature=+aes,+sse2" を使用してx86/x86_64ターゲットをビルドするか、RUSTFLAGS="-C target-feature=+aes,+neon" を使用してARM/AArch64ターゲットをビルドしてください。バイナリが同じCPUモデルまたはその機能のスーパーセットでのみ実行される場合は、代わりに-C target-cpu=nativeを使用することもできます。
クイックスタート
use turbokv::{Db, DbOptions, WriteBatch};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let db = Db::open_with_options("./my-database", DbOptions::durable()).await?;
db.insert(b"user:1", b"Ada").await?;
assert_eq!(db.get(b"user:1").await?, Some(b"Ada".to_vec()));
let mut batch = WriteBatch::new();
batch.put(b"user:2", b"Grace");
batch.put(b"user:3", b"Linus");
batch.delete(b"user:1");
db.write_batch(&batch).await?;
for (key, value) in db.scan_prefix(b"user:").await? {
println!(
"{} = {}",
String::from_utf8_lossy(&key),
String::from_utf8_lossy(&value)
);
}
db.close().await?;
Ok(())
}
実行可能な例:
basic: insert, get, update, and remove
batch_writes: atomic puts and deletes
range_queries: ordered range and prefix scans
concurrent: shared access from Tokio tasks
persistence: paranoid WAL recovery
configuration: cache, memtable, and compression options
APIの内訳
耐久性プリセット
プリセット
確認
境界
ユースケース
DbOptions::fast()
インメモリ可視性; WALなし
キャッシュと再現可能なデータ
DbOptions::durable()
WALに追加されますが、書き込みごとの同期はありません
プロセスクラッシュからの復旧; 推奨されるデフォルト
DbOptions::paranoid()
完了したWALグループが返す前にsync_all
ファイルシステム/デバイスの保証の対象となる最も強力なモード
1つの開いているDbまたはEngineがそのデータディレクトリを排他的に所有します。クリーンシャットダウンにはclose()またはclose_with_status()を使用してください。ハンドルをドロップすることはクリーンシャットダウンの契約ではありません。
データベース操作
キーと値は、AsRef<[u8]>を介して提供される任意のバイトシーケンスです。文字列は呼び出し元がエンコードする必要があります。ミューテーションAPIは、返す前にその入力をコピーします。ポイントリードとコレクションリードは、所有されたVec<u8>値を返します。空の値は有効なデータであり、削除されたキーとは区別されます。
オープンおよび設定API
パラメータ
結果と動作
Db::open(path)
path: AsRef<Path>
DbOptions::durable()でディレクトリを開くか作成します。開いたハンドルはディレクトリを排他的に所有します。
Db::open_with_options(path, options)
データベースパスとDbOptions値
明示的な耐久性、メモリ、キャッシュ、圧縮設定で開きます。WALが無効になっている場合にsync_writes = trueのような矛盾した設定を拒否します。
DbOptions::fast()
なし
WALなしプリセットを返します。
DbOptions::durable()
なし
プロセスクラッシュからの復旧可能なWALプリセットを返します。
DbOptions::paranoid()
なし
同期前の確認プリセットを返します。
options.with_compression(compression)
Compressionバリアント
変更されたオプションを返すビルダー形式の更新。すべてのプリセットは、64 MiBのメンテーブル、64 MiBのブロックキャッシュ、およびLZ4圧縮から始まります。それらの公開フィールドは、開く前に調整できます:
DbOptionsフィールド
意味
wal_enabled: bool
ミューテーションをWALに追記します。無効にすると、正常なフラッシュまたはクローズまでプロセスクラッシュによるデータ損失が発生する可能性があります。
sync_writes: bool
各ミューテーショングループの確認前にWAL同期バリアを待ちます。wal_enabledが必要です。
memtable_size: usize
メンテーブルのローテーションとバックグラウンドフラッシュをトリガーするおおよそのインメモリバイトしきい値。
block_cache_size: usize
非圧縮SSTableブロックキャッシュのバイト予算。キャッシュを無効にするには0に設定します。
compression: Compression
新規書き込みデータ用のSSTable圧縮: Lz4, Snappy, Zstd, または None。既存のテーブルはエンコードされた形式を保持します。
ポイント、バルク、バッチ操作API
パラメータ
戻り値とセマンティクス
insert(key, value)
バイトライクなキーと値
Result<()>
キーを挿入または置換します。選択された耐久性境界が成功前に到達します。
insert_many(entries)
(キー、値)ペアの任意のイテレータ
Result<()>
イテレータ全体をコピーし、エントリを順序通りに適用します。重複する最後のキーが優先されます。これはバルクAPIであり、アトミックな可視性遷移ではありません。
get(key)
バイトライクなキー
Result<Option<Vec<u8>>>
欠落または削除されたキーの場合はNone、保存された空の値の場合はSome(Vec::new())を返します。
remove(key)
バイトライクなキー
Result<()>
トゥームストーンを書き込みます。存在しないキーの削除は許可されます。
contains_key(key)
バイトライクなキー
Result<bool>
getと同じ状態を解決し、現在のところ値の割り当てが発生します。
write_batch(batch)
&WriteBatch
Result<()>
すべての操作をアトミックに公開します。リーダーは、バッチ前の状態または完全なバッチのいずれかを見ます。重複するキーの最後の操作が優先されます。WALが有効な場合、1つのレコードまたは完全なバッチはWALのu32ペイロード長に収まる必要があります。失敗またはキャンセルされたミューテーションは既にWALに到達している可能性があります。非冪等な操作を再試行する前に、キーを検査するか、再オープンしてください。WriteBatchは、すべてのキーと値のコピーを所有します:
API
パラメータ
効果
WriteBatch::new()
なし
空のバッチを作成します。
WriteBatch::with_capacity(capacity)
予想される操作数
操作スロットを事前割り当てしますが、キーまたは値のバイトは割り当てません。
batch.put(key, value)
バイトライクなキーと値
所有されたput操作を追記します。
batch.delete(key)
バイトライクなキー
所有されたdelete操作を追記します。
batch.ops()
なし
順序付けられた &[BatchOp] 操作リストを借用します。
batch.len() / batch.is_empty()
なし
現在の操作数を報告します。
batch.clear()
なし
バッチの割り当てを再利用のために保持しながら、すべての操作を削除します。
範囲およびプレフィックススキャン
キーは生のバイトで辞書順にソートされます。すべてのスキャンは、一貫した時点のスナップショットをキャプチャします。スキャンの作成は、空でないアクティブなメンテーブルをフリーズさせる可能性があるため、頻繁な小さなスキャンは後続のフラッシュ作業を増加させる可能性があります。
API
パラメータ
戻り値と割り当て
range(start, end)
含まれる開始キーと含まれない終了キー
Result<Vec<(Vec<u8>, Vec<u8>)>>; すべての返されるキーと値を積極的に割り当てます。
scan_prefix(prefix)
バイトプレフィックス; 空のプレフィックスはすべてに一致します
順序通りに一致するすべてのキー/値ペアを積極的に収集します。
range_iter(start, end)
同じ [start, end) の境界
RangeIterを作成します。イテレータ項目は、破損が進行中に検出される可能性があるため、Result<EntryGuard, ScanError>です。
scan_prefix_iter(prefix)
バイトプレフィックス
PrefixIterを作成します。これは同じストリーミング実装のエイリアスです。ストリーミングイテレータの進行は同期的に行われ、mmap読み取り、チェックサム検証、解凍、キャッシュロックが発生する可能性があります。速やかにドロップしてください。イテレータはスナップショットリーダーとデータベースディレクトリの所有権をピン留めします。
イテレータまたはガードAPI
パラメータ
結果
iter.count()
なし
イテレータを消費し、Result<usize, ScanError>を返します。
iter.keys()
なし
イテレータを消費し、メンテーブル値を具体化せずに所有されたキーを収集します。
iter.collect_pairs()
なし
イテレータを消費し、所有されたキー/値ペアを収集します。
iter.paginate(offset, limit)
スキップするエントリ数とyieldする最大エントリ数
遅延イテレータを返します。スキップされたエントリはトラバースされますが、メンテーブル値はコピーされません。
guard.key()
なし
値をロードせずにキーを借用します。
guard.value() / guard.value_len()
なし
値を借用するか、その長さを報告します。メンテーブル値は、value()が最初に要求されたときにのみコピーされます。
guard.into_pair() / into_key() / into_value()
なし
ガードを消費し、要求された所有されたバイトを返します。
永続化、メンテナンス、統計API
パラメータ
戻り値とコスト
flush()
なし
Result<()>
保留中の書き込みをドレインし、SSTableとマニフェストをインストールし、WALを同期し、適格なWALセグメントを再利用します。同時に開始された書き込みは、後でフラッシュする必要がある場合があります。
compact()
なし
Result<CompactionResult>
キャプチャされたコンパクションスコープをドレインし、実際のファイル、バイト、期間、再利用されたトゥームストーンを報告します。