Change Log と Cookie
sync ループは、2 つのデータ構造を使ってブラウザと Worker の間で 状態を動かします。どちらも風変わりなものではありませんが、詳しく 理解する価値があります。停止 / 行の欠落 / 妙な pull として表面化 する問題は、すべて最終的にこのどちらかへ辿れるからです。
change log — _plasma_changes
Section titled “change log — _plasma_changes”サーバー上のすべてのユーザーテーブル書き込みは、_plasma_changes
にちょうど 1 行を生成します。
CREATE TABLE _plasma_changes ( row_version BIGINT PRIMARY KEY AUTOINCREMENT, table_name TEXT NOT NULL, row_id TEXT NOT NULL, op TEXT NOT NULL, -- 'put' or 'del' value TEXT NULL, -- JSON of the full row for 'put', NULL for 'del' created_at BIGINT NOT NULL, -- unix ms client_group_id TEXT NULL, client_id TEXT NULL, mutation_id BIGINT NULL)client_group_id / client_id / mutation_id カラムは、どの
client の mutation がその変更を生んだかを識別します(生のドライバ
書き込みや cron ジョブなら NULL)。row_version が pull カーソル
です。
changeLogSuppressed: true と宣言されたテーブルは、トリガーを
完全にスキップします — サーバーが追跡はするが決して伝播しない、
ローカルの一時テーブルです。Offline mode を
参照してください。
成長とコンパクション
Section titled “成長とコンパクション”_plasma_changes は、読み取りごとではなく書き込みごとに成長
します。ユーザーあたり 1 日 10 書き込み・1 万ユーザーのアプリは、
1 日あたり約 10 万行を追加します。放っておくと、やがて遅くなり
ます。
compactChangeLog(safeUpToVersion) は、同じ
(table_name, row_id) に対する中間の put を最新のものだけに
畳み込み、打ち消し合う put+del のペアを取り除きます。Worker の
cron から実行してください。
pull cookie
Section titled “pull cookie”すべての pull レスポンスは、client が次の pull で送り返す cookie
文字列を運びます。次のような見た目です。
c1:eyJhIjoiMTIzIiwiYiI6IjQ1NiJ9c1: プレフィックスはエンコーディングのバージョンを識別します。
base64 はリージョン ID をキーとする JSON にデコードされます。
{ "0": "123", "1": "456" }単一リージョンのデプロイ(一般的なケース)では、オブジェクトは
1 つのキー "0" を持ち、その値は client が観測した最大の
row_version です。pull クエリは WHERE row_version > 123 に
なります。
マルチリージョンのデプロイはリージョンごとのカーソルを運びます。
各リージョンの SequencerDO が自分の空間で単調増加の id を発行
します。Multi-region guide がトポロジー
をカバーしています。
なぜ単なる数値ではないのか?
Section titled “なぜ単なる数値ではないのか?”2 つの理由があります。
- 前方互換性。 将来のプロトコルバージョンは、エンコーディング の契約を壊すことなく、cookie により多くの構造(リージョン カーソル、部分レプリケーションのための causal メタデータ)を 入れられます。
- サーバーの曖昧さ。 サーバー上の生のドライバ書き込みは、pull
ループが安全にスキップできない
row_versionに着地するかも しれません。バージョンを cookie で包むことで、サーバーは「この cookie は不透明だ、自分で +1 しようとするな」を契約として エンコードできます。
_plasma_client_mutations — 重複排除の台帳
Section titled “_plasma_client_mutations — 重複排除の台帳”change log の兄弟です。
CREATE TABLE _plasma_client_mutations ( client_group_id TEXT NOT NULL, client_id TEXT NOT NULL, last_mutation_id INTEGER NOT NULL, PRIMARY KEY (client_group_id, client_id))すべての push がこの行を更新します。すでに観測済みの mutation ID を持つ再送された push は no-op です — client の IDB は outbox エントリを消去しているかもしれませんが、サーバーは二重実行を 拒否します。
pull レスポンス上の lastMutationIDs は、このテーブルを pull
している client のグループにフィルタした射影です。そのため client
は、自分の outbox エントリのうちどれが確認済みかを正確に知り
ます。
origin 一時テーブル — _plasma_origin
Section titled “origin 一時テーブル — _plasma_origin”plasma が内部で使う 3 つ目のテーブルがあります。現在の mutation の
(clientGroupID, clientID, mutationID) を AFTER-write トリガーへ
運ぶ、単一行の一時テーブルです。これが _plasma_changes 上の
client_group_id / client_id / mutation_id カラムが埋められる
仕組みです。実装の詳細ですが、_plasma_* テーブル一覧に現れるので、
そこにあると知っておいてください。
blob 隣接テーブル
Section titled “blob 隣接テーブル”file() カラムを使うと、さらに 2 つのテーブルが存在します。
_plasma_blobs— アップロードされたハッシュごとに 1 行。stateはabsent/uploading/present/orphanedの いずれかです。_plasma_blob_refs— 逆引きインデックス:(hash, table_name, row_id, column_name)。read-auth の経路 (このハッシュを参照する任意の行が、その行を読める呼び出し側に blob のダウンロードを許可する)とgcOrphanedBlobs()が使い ます。
Files and blobs guide が両方をカバーして います。
次に読むもの
Section titled “次に読むもの”- Push, pull, rebase — これらの 構造がどう読み書きされるか
- Multi-region —
SequencerDOが 関わるとき cookie 構造がどう変わるか