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データを作成し、
インデックスのページ数、アイテム数、削除されたアイテム数を設定する。