まえがき
今回はトランザクションをCOMMITした場合に、ローカルデータ領域に積み上がっているクエリの実行履歴を、どのように共有データ領域へ反映するかについて考えます。その前に机上で整理したらすごくわかりやすくなったので、変更操作と共有データ領域とローカルデータ領域について再度まとめます。
共有データ領域とローカルデータ領域の遷移
トランザクションを開始した時の初期状態として、[りんご,100円]と[みかん,80円]を持つテーブルを考える。上段4段は共有データ領域のキーバリューストアと、カラムインデックステーブル2つの状態を表す。下段はローカルデータ領域のキーバリューストアとカラムインデックスに対応するテーブルの状態を表す。
このテーブルに対して、[ぶどう,300円]を挿入し、りんごの値段を120円に上げ、みかんの行を削除する、という操作を順に行う。クエリIDをそれぞれ0001,0002,0003とする。
INSERT
[ぶどう,300円]を挿入したときの状態は下記になる。
このとき、共有データとローカルデータをマージすると、下記のように見えるはずである。(この時点でトランザクションをCOMMITした場合は、共有データ領域はこうなる、という仮想状態。このトランザクション内でSELECTした場合は、この仮想状態を参照する。)
UPDATE
上記のマージテーブルを今のテーブルの状態と見て、りんごの値段を120円に値上げする。ローカルデータ領域の最下段にクエリID:0002の行が追加された。
このとき仮想マージテーブルはクエリID:0001と0002合わせて下記になるはずである。
DELETE
最後に、この仮想状態から[みかん, 80円]の行を削除する。ローカルデータ領域の最下段にクエリID:0003が追加された。
この時、マージテーブルは下記のようになるはずである。
COMMIT時の挙動
今回の本題である、COMMIT時の挙動であるが、共有データ領域を仮想マージテーブルと同じ状態にしてあげれば良い、ということになる。上記では各操作後、仮想マージテーブルはこうなる、と記載しただけだが正確には次のような処理が必要になる。
INSERT
キーバリューストアについては行追加する操作になる。
カラムインデックスについては、追加するレコードのカラム値が、すでに存在しているかしていないかによって処理が変わる。もし、カラム値が既存でないならば、カラムインデックスのテーブルに対して行追加の操作になる。一方、既存であるならば、カラム値が保持するオブジェクトIDのリストに対して、追加するレコードのオブジェクトIDを追加する処理となる。例えば、初期状態として、100円のフルーツが1つ入っているテーブルに、さらに別の100円のフルーツを追加した場合は下記のようになる。
DELETE
説明の都合上、先にDELETEのパターンを説明する。
キーバリューストアは、対象を行削除すれば良い。
カラムインデックスについては、削除するレコードのカラム値が、すでに存在しているかしていないかによって処理が変わる(INSERTの逆のイメージ)。すなわち、削除するレコードのカラム値が既存でない場合、カラムインデックスから行削除すればよい。カラム値が既存の場合、そのカラム値が保持するオブジェクトIDリストから削除するレコードのオブジェクトIDを削除すれば良い。
UPDATE
さて、UPDATEの場合について。
キーバリューストアは更新後の値でそのまま更新してあげればよい。
カラムインデックスについては、値の変更があるカラムインデックスに対してのみ、変更前の値が持つオブジェクトIDを削除し、変更後の値が持つオブジェクトIDを挿入する必要がある。つまり、上のDELETEとINSERTの処理を組み合わせてあげれば良い。
まとめ
よし、実装するぞー。。