B-Treeインデックス。btbulkdelete()。PageからItemを削除するところ

インデックスの削除のときに呼ばれるbtbulkdelete()を見てみる。削除はSQLのDELETE実行時ではなくVACUUMのときに行われる。概要はインタフェースであるambulkdeleteのところをみるとわかる。インデックスアクセスメソッド関数

GDBでbtしたときの呼び出しシーケンス(抜粋)。psqlでVACUUMを呼び出した。

(gdb) bt
#0  PageIndexTupleDelete (page=0xb58d5260 "", offnum=2) at bufpage.c:577
#1  0x08244085 in PageIndexMultiDelete (page=0xb58d5260 "", itemnos=0xbf8181b4, nitems=0) at bufpage.c:711
#2  0x080ad39e in _bt_delitems (rel=0xb5601678, buf=208, itemnos=0xbf8181b4, nitems=1) at nbtpage.c:662
#3  0x080afb60 in btvacuumpage (vstate=0xbf819228, blkno=1, orig_blkno=1) at nbtree.c:892
#4  0x080af6ec in btvacuumscan (info=0xbf81961c, stats=0x84f7408, callback=0x81878f9 <lazy_tid_reaped>, callback_state=0x84f6b40, cycleid=34907) at nbtree.c:696
#5  0x080af47b in btbulkdelete (fcinfo=0xbf819370) at nbtree.c:547
#6  0x0831e0c5 in FunctionCall4 (flinfo=0x8528c40, arg1=3212940828, arg2=0, arg3=135821561, arg4=139422528) at fmgr.c:1331
#7  0x080a8e9f in index_bulk_delete (info=0xbf81961c, stats=0x0, callback=0x81878f9 <lazy_tid_reaped>, callback_state=0x84f6b40) at indexam.c:741
#8  0x0818703e in lazy_vacuum_index (indrel=0xb5601678, stats=0x84f6b30, vacrelstats=0x84f6b40) at vacuumlazy.c:753
#9  0x08186ac0 in lazy_scan_heap (onerel=0xb5602368, vacrelstats=0x84f6b40, Irel=0x84f6be0, nindexes=1) at vacuumlazy.c:586
#10 0x08185f8d in lazy_vacuum_rel (onerel=0xb5602368, vacstmt=0x84ad0d0, bstrategy=0x84fa9d0) at vacuumlazy.c:191
#11 0x0818138d in vacuum_rel (relid=24694, vacstmt=0x84ad0d0, expected_relkind=114 'r', for_wraparound=0 '\0') at vacuum.c:1126
#12 0x08180746 in vacuum (vacstmt=0x84ad0d0, relids=0x0, bstrategy=0x84fa9d0, for_wraparound=0 '\0', isTopLevel=1 '\001') at vacuum.c:427

今日は、_bt_delitems()以下を見てみる。

  • _bt_delitems()
    • この関数までくるとどのPageのどのItemを削除すべきがわかっている。_bt_delitemsとあるように同時に複数削除できる。
    • PageIndexMultiDelete()を呼び出して削除したら、ページをダーティにしてWALのログを出力。
  • PageIndexMultiDelete()
    • 削除するItemが少なければ(2件以下ならば)PageIndexTupleDelete()を呼び出して1件ずつ処理。
    • 削除するItemが多ければ、削除しないItemIdを取り出す。
    • 削除しないItemIdからItemを求め、Pageの後ろから順に並べる。そして、ItemIdのオフセットを更新する。これを削除しないItemId全てに行う。
    • フリースペース(PageHeaderのpd_lowerとpd_upper)を調整する。
  • PageIndexTupleDelete()
    • 削除対象のItemIdをつぶす(前にずらす)。
    • 削除対象のItemをつぶす(後ろにずらす)。
    • フリースペース(PageHeaderのpd_lowerとpd_upper)を調整する。
    • 削除したのより後ろのItemを指すItemIdのオフセットを更新。

課題

  • インデックスのPageのすべてのItemが削除されたらどうなる?追加のときにページが分割されたがその逆(ページの統合?)のようなことは起きるのか?
  • BTPageOpaqueDataのbtpo_flags(削除済みなどの情報をもつ)はどこで更新されるのか?