CLOG

CLOGのフォーマット

CLOGではトランザクションごとのコミット状態のデータを持つ。ひとつのトランザクションにつき2ビットしか使わない。要するに状態は4種類だけということ。とりうる状態は次のように定義されている。

#define TRANSACTION_STATUS_IN_PROGRESS      0x00
#define TRANSACTION_STATUS_COMMITTED        0x01
#define TRANSACTION_STATUS_ABORTED          0x02
#define TRANSACTION_STATUS_SUB_COMMITTED    0x03

ただし、TRANSACTION_STATUS_IN_PROGRESSは初期状態のこと。これを書き込んでいるところはなかった。ふつーに疑問なのはSUB_ABORTEDはいらないのだろうか?サブトランザクションの概念が把握できていないのでなんともいえない。

トランザクションIDから、どのファイルの何番目のページの何バイト目のどの2ビットを使うかが一意に決まるロジックになっている。
1バイトに限って見てみる。最初のトランザクションがコミットされると右から数えて1ビット目と2ビット目が使用される。

00000001

次のトランザクションもコミットされると右から数えて3ビット目と4ビット目が使用される。

00000101

その次のトランザクションロールバックされるとと右から数えて5ビット目と6ビット目が使用される。

00100101

CLOGとWAL

チェックポイントで共有バッファやCLOGがディスクにフラッシュされる前にクラッシュする次のようなケースを考えてみた。

1. BEGIN;
2. INSERT; … WALプロトコルによりタプルを追加したことが記録される
3. COMMIT; … WALプロトコルによりコミットされたことが記録される
4. チェックポイントの前にクラッシュ

リカバリで、INSERTで追加されたタプルは他のトランザクションから見えるようにしなければいけない。しかし、CLOGが失われてしまっているのだから、INSERTを行ったトランザクションがコミットされたかどうかわからないじゃないか、と最初考えた。でも、これはおかしい。WALログにはトランザクションがコミットされたことがちゃんと記録されている。では、コミットされたかどうかを確認するのにCLOGをみたりWALログをみたり場合わけするのか?

そうではない。どうやら、リカバリ時にデータの復旧よりも先にWALログからCLOGが復旧される(コミット処理やロールバック処理が実行されてCLOGが作成される)ようだ。そして、その後でデータが復旧されるが、コミットされたかどうかはCLOGをみて判断すると推測できる(この判断が前のエントリで述べたMVCCのチェックでされるのか、別のところでなされるのかは未確認)。CLOGがWALログから復旧されるという観点になかなか気づかなかった。

コミット処理やロールバック処理のやり直しはxact_redo関数で行われる。