kevy4.0

中に組み込む

ストアを、
そのものの中へ

サーバーもソケットもネットワークもありません。エンジンは、呼び出せる struct であり、151 KB の WebAssembly モジュールであり、OS のないチップの上の no_std ライブラリです——そして 3 つとも、同じコマンドを持つ、同じエンジンです。

なぜ向いているのか

オフラインで動く必要のあるアプリケーションは、どれも結局ストレージ層を書くことになります。デスクトップアプリは SQLite と、誰も望まなかったスキーマを手に入れます。Web アプリは localStorage を使い、5 MB の上限と、同期でしかも文字列しか扱えないという事実を知り、次に IndexedDB とその上の抽象を手に入れます。デバイスは、フラッシュ上に手書きのリングバッファを手に入れます。

3 つとも同じ問題であり、同じ解になりえます。kevy はプロセス境界なしで組み込め、本物の TTL と pub/sub を持ったままブラウザに届き、固定 arena とアロケータなしで Cortex-M でも起動します。最後のひとつは、CI が push のたびに証明しています。

手順——Rust のプログラムの中で

ソケットも、シリアライズも、2 つ目のプロセスもありません。永続化され、開くときにログを再生します。
kevy-embedded = "4.0"

let db = Db::open("data/")?;
db.set(b"session:7f3a", b"{\"user\":\"ada\"}", Some(Duration::from_secs(3600)))?;
assert_eq!(db.get(b"session:7f3a")?.is_some(), true);

// need other processes to reach it later? open the RESP listener
// and your redis-cli works, without changing any of the above.
db.listen("127.0.0.1:6379")?;

手順——ブラウザのタブで

gzip 後 151 KB。ブラウザ自身のファイルシステムに永続化され、リロードにも耐え、タブをまたいで pub/sub を話します。
import { open } from "@goliajp/kevy";

const db = await open({ persist: { name: "app" } });

db.set("cart:u881", JSON.stringify(items), { ttlMs: 86_400_000 });
db.get("cart:u881");        // still there after a reload
db.pttl("cart:u881");       // the engine expires it, not your code

db.subscribe("sync", (payload) => merge(payload));   // other tabs

手順——マイコンの上で

no_std、アロケータなし、OS なし。大きさを自分で決める、固定の arena。
# Cargo.toml
kevy-store = { version = "4.0", default-features = false }

# no_std, no heap: the store lives in an arena you provide
let mut arena = [0u8; 64 * 1024];
let mut store = Store::new_in(&mut arena);
store.set(b"temp", b"21.4")?;
何を差し出すことになるか

ブラウザでは、小さな同期の読み取りなら localStorage のほうが速いです——あれはページ自身のアドレス空間にあるマップであり、OPFS の上に作られたものが、そこで勝つことはありません。kevy が勝つのは、そもそも localStorage を選ぶべきでない理由のほうです。本物の TTL、5 MB の上限がないこと、値が文字列ではなくバイト列であること、書き込みがメインスレッドを止めないこと。マイコンでは、arena の大きさを自分で決めますし、実行中に広げることはできません。アロケータがないとは、そういうことです。そして組み込みのストアは共有されません。2 つ目のプロセスがデータを必要とするなら、必要なのはサーバーか、組み込みの RESP リスナーです。

次に