Deno KV connect protocolの調査
v8_valueserializer
今のところv8 valueのデシリアライズのみ可能。
displayという関数でv8 valueの型を保ったまま文字列に変換できる
(JSON.stringifyではBigintやMapなどの型をシリアライズできない)
displayには3つのモードがある。
- Repl: 値をJavaScriptのREPL(Read-Eval-Print Loop)に渡せる文字列として表示します。このモードでは最後の文はセミコロンで終わらず、文を式文にするために全体が括弧で囲まれることがあります。これは通常、ユーザーに値を表示する最も明快な方法です。
- Expression: 値を式の位置(たとえば関数の右辺)で使用できる文字列として表示します。必要な場合には、全ての文字列を即時関数(IIFE: Immediately Invoked Function Expression)で囲みます。
- Eval: 値をeval()へ渡すことができる文字列として表示します。現在のスコープを汚染するのを避けるために、間接的なeval() (例: (0, eval)()) を使用するべきです。
v8_valueserializerをテストするためには、シリアライズ済みのバイナリ表現が必要なのだが、手に入れる方法がなさそう…?
KV Connect protocolを実装してみればいいのかもしれないけど、protobuf経験ないなぁ…
とりあえずリポジトリを作ってみる。
Protobufのバイナリを覗く記事。結構素直な作りかもしれない
KV Connect protocolのprotobuf仕様はここ。
しかし、KV Connect protocolを実装するのはいいんだけど、今のところv8 valueのデシリアライズしかできない(っぽい)ので、getしかできないかも。まあ普通にdeno cliから書けばいいんだけど。
おお、読めた。面白い。
{
ranges: [
{
values: [
{
key: [Uint8Array],
value: [Uint8Array],
encoding: "VE_V8",
versionstamp: [Uint8Array]
}
]
}
],
readDisabled: false,
readIsStronglyConsistent: true
}
テストコードはここ。
APIキーが入っているが、これはdockerでローカルにdenokvを立てたときに自分で指定したもの。
dbのUUIDはメタ情報の取得リクエストを自分で投げる必要がある。
Key, Valueがそれぞれバイナリで返っているが、それぞれコーデックが異なる。
Key
検索に適した独自形式フォーマットのはず。現状オープンソースのKvKeyコーデックは以下の2つ。
- https://github.com/nhrones/kv-key-codec/
- https://github.com/skymethod/kv-connect-kit/blob/master/src/kv_key.ts
Value
KvValueはv8のシリアライザ・デシリアライザを使っている。じゃあそれを自分のスクリプトで使おうとするとv8そのものをバンドルすることになり大変なことになる(特にフロントエンドでやろうとする場合)。
それでv8_valueserializerが作られているというわけ。v8_valueserializerは今のところwasmで220KBくらい。
ほとんどの人はKV Connect protocolのことを知る必要はない(Deno側にAPIがあるため)んだけど、仕事で一段ローレベルのことを知っておく必要が出てきたのが一点、あとは今作ってるdeno-kv-admin拡張で、Deno KVの型をフロントでどう扱うか迷いが出てるのがもう一点。
ひょっとしたら、そもそもJSONに変換する必要自体がないのかもしれない。例えばv8_valueserializerでシリアライザが実装されれば、クラサバのやり取りは元々使われていたKvKeyやKvValueのバイナリ表現でやってしまえばいいのかもしれない。
今のところはsuperjsonというBigintとかをよしなにやってくれるものでクラサバでオブジェクトを受け渡しているのだけど、Denoで独自定義された型(KvU64)はエラーになったりするのだった。
よくよく考えるとv8を組み込んでいるNode.jsには、直接使う方法があるようだった。
const v8 = require('v8');
const obj = {
a: 1,
b: 2,
c: {
d: 3,
e: 4,
},
};
const binary = v8.serialize(obj);
console.log(binary);
const obj2 = v8.deserialize(binary);
console.log(obj2);
余裕でシリアライズできる。
% node ./node/serialize.js
<Buffer ff 0f 6f 22 01 61 49 02 22 01 62 49 04 22 01 63 6f 22 01 64 49 06 22 01 65 49 08 7b 02 7b 03>
{ a: 1, b: 2, c: { d: 3, e: 4 } }
内部的にはserdes?という実装を参照している。そこから先は追っていない。
テストデータはこれで用意すればよかった。
Deno側では意図的にこれを公開していない(最新のコメントでまさにKV用に使いたがっている人がいるね)