WAL(2)
Recovery
バックエンドが異常終了した後、再起動時に実行されるリカバリは,StartupXLOGのdo-whileループで実行される。(コメントにmain redo apply loopとある箇所)
ログレコードにページ(ブロック)のバックアップが含まれている場合,RestoreBkpBlocksを実行する。次にRmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record)で,ログレコードの種類に対応するREDO処理が実行される。(RmgrTableはrmgr.cで定義されている)
例えばinsertをredoする場合,heap_redo->heap_xlog_insertが実行される。
REDO処理は,ReadRecordでログレコードが無くなるまでループする。(または,recoveryStopsHereでリカバリの停止条件が成立するまで)
RestoreBkpBlocks
ログレコードにあるブロックを,データファイルにリストアする。
バックエンドがクラッシュしたときは,ブロックが部分的にしか更新されていないなど信頼できない状態にあるためログから無条件にリストアしている。
heap_xlog_insert
ログレコードのデータを使ってinsertをREDOする。
RestoreBkpBlocksでブロックをリストアしたときは,tupleがinsertされた状態のブロックがリストアされているため,insert処理を実行しない。
リカバリ処理の観察
リカバリはpostgresのstartup processで実行されるので,デバッガでアタッチするのがめんどくさい。xlog.cのStartupXLOGを以下のように修正し,recoveryメッセージを表示する箇所でProcessIDを表示して30秒待つようにした。
if (InArchiveRecovery) { ereport(LOG, (errmsg("automatic recovery in progress:%d", getpid()))); sleep(30); } else { ereport(LOG, (errmsg("database system was not properly shut down; " "automatic recovery in progress:%d", getpid()))); sleep(30); }
これでautomatic recovery in progressが表示されたあとに、gdbでアタッチすればリカバリ処理を観察できる。
gdb postgres