Skip to content

Getting Started

Yuya Uezato edited this page Oct 19, 2018 · 7 revisions

組み込みKVSであるCannyLSを実際にRustから呼び出して利用する。

PUTとGETのみを行う例

準備

CannyLSはcratesで公開済みであり、cargoを経由して簡単に利用できる。 次のように作業用ディレクトリを作成し

$ cargo new cannyls_wks
$ cd cannyls_wks
cannyls_wks$ ls .
Cargo.toml	src

Cargo.toml[dependencies]cannyls = "0.9.0"を追加する。 これは例えば次のようになる:

[package]
name = "cannyls_wks"
version = "0.1.0"
authors = ["yuuya uezato <[email protected]>"]

[dependencies]
cannyls = "0.9.0" # <-- 追加

Hello, CannyLS

src/main.rsを次のようにする:

extern crate cannyls;

use cannyls::lump::{LumpData, LumpId};
use cannyls::nvm::FileNvm;
use cannyls::storage::Storage;

fn main() {
    // Storageモジュールが利用するファイルを demo.lusf という名前で作成する
    // このファイルは最大で 1MB を利用する
    // cf. https://docs.rs/cannyls/0.9.0/cannyls/nvm/struct.FileNvm.html
    let file: FileNvm = FileNvm::create("demo.lusf", 1_000_000).unwrap();

    // 作成したファイル `file` をCannyLSのストレージとして使えるようにする
    // cf. https://docs.rs/cannyls/0.9.0/cannyls/storage/struct.Storage.html
    let mut storage: Storage<FileNvm> = Storage::create(file).unwrap();

    // CannyLSでは、keyは `LumpId` と呼ばれる構造体
    // cf. https://docs.rs/cannyls/0.9.0/cannyls/lump/struct.LumpId.html
    // ここでは数0からLumpIdを一つ作成する
    let lump_id: LumpId = LumpId::new(0);

    // CannyLSでは、valueは `LumpData` と呼ばれる構造体
    // cf. https://docs.rs/cannyls/0.9.0/cannyls/lump/struct.LumpData.html
    // ここでは文字列 `"Hello, CannyLS"` からLumpDataを一つ作成する
    let lump_data: LumpData = LumpData::new(Vec::from("Hello, CannyLS")).unwrap();

    // 作ったLumpIdとLumpDataを作成したストレージにputする
    let result: bool = storage.put(&lump_id, &lump_data).unwrap();

    if !result {
        // データのputに成功したならば、`result==true`なのでここには来ない
        panic!("put failed for some reason...");
    }

    println!("Put succeeded!");

    // key=`lump_id`を用いてputしたLumpDataを取得する
    let stored_data: Option<LumpData> = storage.get(&lump_id).unwrap();

    if let Some(data) = stored_data {
        // keyに対応するデータが存在した場合の処理
        println!("Dumping the obtained data:\n {:?}", data);

        let byte_data: &[u8] = data.as_bytes();
        let string_data: &str = std::str::from_utf8(byte_data).unwrap();

        println!("{}", string_data);
        assert_eq!(string_data, "Hello, CannyLS");
    } else {
        // keyに対応するデータが存在しない場合の処理
        panic!("CannyLS failed to find your data");
    }
}

実行

cannyls_wks$ cargo run
Put succeeded!
Dumping the obtained data:
 LumpData { block_size: Some(BlockSize(512)), bytes: [72, 101, 108, 108, 111, 44, 32, 67, 97, 110, 110, 121, 76, 83] }
Hello, CannyLS

実行すると cannyls_wks/demo.lusf ファイルが出来る。このファイルはrmコマンドなどで削除して良い。

CannyLSの実装上の中心的な構造体として、上でも用いたStorage構造体がある。
この構造体については、Storage構造体のドキュメントを参考にされたい。
上で用いなかったメソッドのうちで分かりやすいものに、ストレージのメタ情報を取得するための Storage::header や、ストレージに入っているデータ一覧を返す Storage::list などもある。

少し複雑な例

KaNiLSという、 CannyLSのStorageモジュールの公開メソッドを組み合わせたコマンドラインツールが参考になる。

Deviceモジュールを用いた実践例

CannyLSに限らず、大規模なサービスの中でKVSを用いると、複数のスレッドで一つのストレージを扱いたくなる。 Rust流の作法ではArc<Mutex<...>>としてmutex lockを用いた方法もあるが、CannyLSではDeviceモジュールというより良いStorage構造体を管理する方法を提供している。

extern crate cannyls;
extern crate futures;

use cannyls::device::DeviceBuilder;
use cannyls::lump::{LumpData, LumpId};
use cannyls::nvm::FileNvm;
use cannyls::storage::Storage;

use futures::Future;

use std::{thread, time};

fn wait<E, F: Future<Error = E>>(mut f: F) -> Result<(), E> {
    while !(f.poll())?.is_ready() {}
    Ok(())
}

fn main() {
    let file = FileNvm::create("demo.lusf", 1_000_000_000).unwrap();
    let storage = Storage::create(file).unwrap();
    let device = DeviceBuilder::new().spawn(|| Ok(storage));
    let d = device.handle();
    let _ = wait(d.request().wait_for_running().list()); // デバイスの起動を待機

    let data = LumpData::new(vec![42; 1_000_000]).unwrap();
    for i in 0..10 {
        let lump_id = LumpId::new(i);
        let future0 = d.request().put(lump_id, data.clone());
        wait(future0).unwrap();
    }
    // thread::sleep(time::Duration::from_secs(3));
}
$ cargo run
$ kanils List --storage demo.lusf
there are no lumps

……?