vacuum (1)

lazy_vacuum_rel

テーブルをlazy vacuumする。(full vacuumではなく、オプション無しで実行したときのvacuum)
(1)vac_open_indexesでテーブルのインデックスを全部オープンする。
(2)lazy_scan_heapでvacuumのメイン処理を実行する。
(3)vac_close_indexesでインデックスをcloseする。
(4)lazy_update_fsmでFSM(Free Space Map)を更新
(5)vac_update_relstatsでpg_classの統計情報更新

lazy_scan_heap

テーブルの先頭のブロックから順にvacuumの処理を行う
(1)ページの共有ロックを取得する
(2)ページの状態を確認する

  • PageIsNewのとき

新しいページを作成した後、ページを初期化する前にクラッシュした可能性を調べる。以下の順にロックの操作を行い、ページの排他ロックを取得する。

    LockBuffer(buf, BUFFER_LOCK_UNLOCK);
    LockRelationForExtension(onerel, ExclusiveLock);
    UnlockRelationForExtension(onerel, ExclusiveLock);
    LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);

排他ロックを取得した後もPageIsNewだったら、ページを初期化前にクラッシュしたと判断し、ページを初期化してからlazy_record_free_spaceでfree spaceリストに追加する。

  • PageIsEmptyのとき

laze_recore_free_spaceでfree spaceリストに追加する。

  • その他

ページに登録されている全てのタプルの状態をHeapTupleSatisfiesVacuumで調べる。タプルがHEAPTUPLE_DEADだったら、lazy_space_dead_tupleでdead tupleリストに追加する。

(3)dead tupleリストにある程度タプルが登録されたら、lazy_vacuum_index, lazy_vacuum_heapでインデックスとテーブルのタプルを削除する。

        if ((vacrelstats->max_dead_tuples - vacrelstats->num_dead_tuples) < MaxHeapTuplesPerPage &&
            vacrelstats->num_dead_tuples > 0)
        {
            /* Remove index entries */
            for (i = 0; i < nindexes; i++)
                lazy_vacuum_index(Irel[i],
                                  &index_tups_vacuumed[i],
                                  &index_pages_removed[i],
                                  vacrelstats);
            did_vacuum_index = true;
            /* Remove tuples from heap */
            lazy_vacuum_heap(onerel, vacrelstats);
            /* Forget the now-vacuumed tuples, and press on */
            vacrelstats->num_dead_tuples = 0;
        }

(4)dead tupleが無かった場合、lazy_scan_indexでインデックスの統計情報を更新する。(dead tupleがある場合は、統計情報はlazy_vacuum_indexで更新されるので、lazy_scan_indexを実行する必要はない。)

lazy_vacuum_index

インデックスから、vacrelstats->dead_tupleに登録されたタプルのアイテムを削除する。

(1)indexをロックする
indexがconcurrent safeな場合、RowExclusiveLock, unsafeならAccessExclusiveLock。btree indexはconcurrent safeなので、RowExclusiveLock。

(2)index_bulk_deleteで削除を実行
callbackにlazy_tid_reapedを指定している。btree indexの場合、btbulkdeleteが実行される。

(3)index_vacuum_cleanupでvacuumの後処理を実行
btree indexの場合、btvacuumcleanupが実行される。

(4)ロックを開放し、インデックスの統計情報を更新する

lazy_tid_reaped

index_bulk_deleteのcallback関数。
インデックスのbulk delete関数から、アイテムを削除していいか確認するために実行される。bsearchでvacrelstats->dead_tuplesを検索し、見付かったらtrueを返す。

btbulkdelete

btree indexに登録されている全てのアイテムについて、削除していいかチェックして削除する。リーフページを左から右へチェックしていく。

(1)_bt_getendpointで左端のページを取得

(2)ページにアイテムがある場合、LockBufferForCleanupでsuper-exclusive lockを取得する。super-exclusive lockはexclusive lockかつ参照カウンタが1(自分しか参照していない)の状態。exclusive lockだけではconcurrent safeが保証されない。

(3)ページのアイテムを順に取り出し、callback関数で削除していいかチェックする。削除できる場合、deletable配列に登録する。

(4)_bt_delitemsでdeletable配列に登録されたアイテムを削除する。
WALの量を少なくするために、ページごとにdeletable配列を作成してから_bt_delitems関数を実行している。

(5)右端のリーフページにたどり着くまで、(2)から繰り返す。

(6)btbulkdeleteの戻り値として返すIndexBulkDeleteResultデータを作成し、
インデックスのページ数、アイテム数、削除されたアイテム数を設定する。