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