Open9

Deno KV connect protocolの調査

hashrockhashrock

https://github.com/denoland/v8_valueserializer/blob/a0cb96bf168bca47adc82067a207e54f1d2a71fe/src/display.rs#L1098

displayには3つのモードがある。

  1. Repl: 値をJavaScriptのREPL(Read-Eval-Print Loop)に渡せる文字列として表示します。このモードでは最後の文はセミコロンで終わらず、文を式文にするために全体が括弧で囲まれることがあります。これは通常、ユーザーに値を表示する最も明快な方法です。
  2. Expression: 値を式の位置(たとえば関数の右辺)で使用できる文字列として表示します。必要な場合には、全ての文字列を即時関数(IIFE: Immediately Invoked Function Expression)で囲みます。
  3. Eval: 値をeval()へ渡すことができる文字列として表示します。現在のスコープを汚染するのを避けるために、間接的なeval() (例: (0, eval)()) を使用するべきです。
hashrockhashrock

v8_valueserializerをテストするためには、シリアライズ済みのバイナリ表現が必要なのだが、手に入れる方法がなさそう…?

KV Connect protocolを実装してみればいいのかもしれないけど、protobuf経験ないなぁ…

とりあえずリポジトリを作ってみる。

https://github.com/hashrock/study-deno-kv-libs

hashrockhashrock

おお、読めた。面白い。

{
  ranges: [
    {
      values: [
        {
          key: [Uint8Array],
          value: [Uint8Array],
          encoding: "VE_V8",
          versionstamp: [Uint8Array]
        }
      ]
    }
  ],
  readDisabled: false,
  readIsStronglyConsistent: true
}

テストコードはここ。

https://github.com/hashrock/study-deno-kv-libs/blob/main/kv-connect/read.ts

APIキーが入っているが、これはdockerでローカルにdenokvを立てたときに自分で指定したもの。
dbのUUIDはメタ情報の取得リクエストを自分で投げる必要がある。

hashrockhashrock

Key, Valueがそれぞれバイナリで返っているが、それぞれコーデックが異なる。

Key

検索に適した独自形式フォーマットのはず。現状オープンソースのKvKeyコーデックは以下の2つ。

Value

KvValueはv8のシリアライザ・デシリアライザを使っている。じゃあそれを自分のスクリプトで使おうとするとv8そのものをバンドルすることになり大変なことになる(特にフロントエンドでやろうとする場合)。

それでv8_valueserializerが作られているというわけ。v8_valueserializerは今のところwasmで220KBくらい。

hashrockhashrock

ほとんどの人はKV Connect protocolのことを知る必要はない(Deno側にAPIがあるため)んだけど、仕事で一段ローレベルのことを知っておく必要が出てきたのが一点、あとは今作ってるdeno-kv-admin拡張で、Deno KVの型をフロントでどう扱うか迷いが出てるのがもう一点。

ひょっとしたら、そもそもJSONに変換する必要自体がないのかもしれない。例えばv8_valueserializerでシリアライザが実装されれば、クラサバのやり取りは元々使われていたKvKeyやKvValueのバイナリ表現でやってしまえばいいのかもしれない。

今のところはsuperjsonというBigintとかをよしなにやってくれるものでクラサバでオブジェクトを受け渡しているのだけど、Denoで独自定義された型(KvU64)はエラーになったりするのだった。

hashrockhashrock

よくよく考えると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用に使いたがっている人がいるね)

https://github.com/denoland/deno/issues/12379