組み込みのWALにログを書き込むすべてのモジュールは、それぞれに独自の型のWALレコードがありますが、ページへの変更を汎用的な方法で記述する汎用WALレコード型もあります。 カスタムアクセスメソッドを提供する拡張では、独自のWALの再実行(redo)ルーチンを登録できないため、汎用WALレコードが役立ちます。
汎用WALレコードを構築するためのAPIはaccess/generic_xlog.h
に定義されており、access/transam/generic_xlog.c
で実装されています。
汎用WALレコードの機能を使ってWAL書き込みを伴うデータ更新を行うには、以下の手順に従ってください。
state = GenericXLogStart(relation)
により、指定のリレーションについての汎用WALレコードの構築を開始します。
page = GenericXLogRegisterBuffer(state, buffer, flags)
により、現在の汎用WALレコード内で更新されるバッファを登録します。
この関数はバッファページの一時コピーへのポインタを返すので、更新はそれに対して行ってください。
(バッファの内容は直接更新しないでください。)
3番目の引数は、操作についてのフラグのビットマスクです。
現在のところ、使用できるフラグはGENERIC_XLOG_FULL_IMAGE
のみで、これはWALレコードには変更の差分ではなく、ページ全体のイメージが含まれることを示します。
典型的には、このフラグはページが新しいか、あるいは完全に書き換えられるときにセットされます。
WAL書き込み対象の動作が複数のページを更新する必要がある場合は、GenericXLogRegisterBuffer
を繰り返すことができます。
前の手順で取得したページのイメージに更新を適用する。
GenericXLogFinish(state)
により、バッファの変更を適用し、汎用WALレコードを送出する。
WALレコードの構築は、上記の手順内の間のどこででも、GenericXLogAbort(state)
を呼び出すことで中止できます。
これによりページイメージのコピーに対する変更はすべて廃棄されます。
汎用WALレコードの機能を使うときは、以下の点に注意してください。
バッファの直接更新は許されません!
すべての更新はGenericXLogRegisterBuffer()
で取得したコピーに対して行わなければなりません。
言い換えれば、汎用WALレコードを使うコードではBufferGetPage()
を呼び出してはいけません。
しかし、適切なときにバッファにピンを立てる、外す、そしてロックする、解除するのが呼び出し側の責任であることに変わりはありません。
各ターゲットバッファの排他的ロックをGenericXLogRegisterBuffer()
の前からGenericXLogFinish()
の後まで保持していなければなりません。
手順2のバッファの登録と、手順3のページイメージの更新は自由に混在させることができます。 つまり、両方の手順を任意の順序で繰り返すことができます。 バッファの登録は、再生時にロックを取得する順序と同じにすべきであることを覚えていてください。
汎用WALレコードに登録できるバッファの最大数はMAX_GENERIC_XLOG_PAGES
です。
この制限を超えるとエラーが発生します。
汎用WALでは、更新対象のページが標準的なレイアウトになっている、特にpd_lower
とpd_upper
の間には意味のあるデータがないということを想定しています。
ここではバッファページのコピーを更新するため、GenericXLogStart()
はクリティカルセクションを開始しません。
従って、GenericXLogStart()
とGenericXLogFinish()
の間では、メモリの割り当て、エラーの発生などを安全に実行できます。
唯一の本当のクリティカルセクションはGenericXLogFinish()
の内部にあります。
エラー終了の中でGenericXLogAbort()
を呼び出すことについても心配する必要はありません。
GenericXLogFinish()
はバッファをダーティにして、LSNの設定をすることの処理をします。
これについて明示的な処理をする必要はありません。
ログを取らないリレーションは、実際のWALレコードが送出されないことを除けば、すべてが同じように動作します。 従って、通常は、ログを取らないリレーションについて明示的な検査をする必要はありません。
汎用WALを再生する機能は、バッファの排他的ロックを、バッファが登録されたのと同じ順序で取得します。 すべての変更を再生した後で、ロックは同じ順序で解放されます。
登録バッファにGENERIC_XLOG_FULL_IMAGE
が指定されない場合、汎用WALレコードは古いページイメージと新しいページイメージの間の差分を含むものとされます。
この差分はバイト毎の比較に基づくものです。
これはデータをページ内で移動する場合、あまり小さくなりませんが、将来は改善されるかもしれません。