vacuum (2)

lazy_vacuum_heap

vacrelstats->dead_tupleに登録されたタプルを、テーブルから削除する。
(1)LockBufferForCleanupでページをロックする
(2)lazy_vacuum_pageでページ内のアイテムを削除する
(3)lazy_record_free_spaceでページの空き領域を登録
(4)ロックを開放
(5)WriteBufferでページをdirtyにする

lazy_vacuum_page

指定されたページのタプルを削除する。
(1)vacrelstats->dead_tupleに登録されたタプルのItemIdのLP_USEDフラグをおろす。
(2)PageRepairFragmentationでページの断片化を修正する
(3)一時テーブルではない場合、log_heap_cleanでWALレコードを出力する

lazy_record_free_space

vacrelstats->free_pages配列にページの空き容量の情報を登録する。
free_pages配列が一杯になった場合、配列から一番容量の少ないページの情報を追い出して登録していく。(heap-based priority queuesというアルゴリズムで一番容量の少ないページが配列の先頭にくるように調整している)

PageRepairFragmentation

ページの断片化を修正する。
(1)ItemId配列を順にチェックして、使用中のアイテムの数(nused)を数える。また、削除するアイテムはunused配列にアイテムの番号を登録する。
(2)使用中のアイテムがない場合(nused == 0)の場合、ページをemptyにする。(ItemIdのlp_lenを0にして、pageのpd_upperを初期化する)
(3)使用中のアイテムがある場合、使用中のアイテムデータのoffsetをitemidbase配列に登録し、offset順にソートする。次にoffset順にデータを並べ変える。

log_heap_clean

ページから複数のタプルを削除したときのWALレコードを出力する。PageRepairFragmentationが作成したunused配列をログとして出力する。複数のタプルを削除した情報を1つのログレコードで出力することにより、ログの容量を少なく抑えている。
以下のように配列をそのままログに出力している。

    if (uncnt > 0)
    {
        rdata[1].data = (char *) unused;
        rdata[1].len = uncnt * sizeof(OffsetNumber);
    }

_bt_check_uniqueのバグ修正

_bt_check_uniqueでbufferをdirtyにするコードは以下で正解だった。

    if (nbuf == InvalidBuffer)
        SetBufferCommitInfoNeedsSave(buf);
    else
        SetBufferCommitInfoNeedsSave(nbuf);

http://archives.postgresql.org/pgsql-patches/2005-10/msg00088.php
http://archives.postgresql.org/pgsql-committers/2005-10/msg00177.php