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(削除済みなどの情報をもつ)はどこで更新されるのか?