PostgreSQL Source Code interpretation (133)-MVCC#17 (vacuum procedure-lazy_vacuum_index function # 2)
Right, return 1. * / static intvac_cmp_itemptr (const void * left, const void * right) {BlockNumber lblk, rblk; OffsetNumber loff, roff; lblk = ItemPointerGetBlockNumber ((ItemPointer) left); rblk = ItemPointerGetBlockNumber ((ItemPointer) right); if (lblk
< rblk) return -1; if (lblk >Rblk) return 1; loff = ItemPointerGetOffsetNumber ((ItemPointer) left); roff = ItemPointerGetOffsetNumber ((ItemPointer) right); if (loff)
< roff) return -1; if (loff >Roff) return 1; return 0;} III. Tracking analysis
Test script: delete data, execute vacuum
14:24:12 (xdb@ [local]: 5432) testdb=# delete from T1 where id
< 1300;DELETE 10014:24:23 (xdb@[local]:5432)testdb=# checkpoint;CHECKPOINT14:24:26 (xdb@[local]:5432)testdb=# 14:25:28 (xdb@[local]:5432)testdb=# vacuum verbose t1; btvacuumscan 启动gdb,设置断点 (gdb) b btvacuumscanBreakpoint 1 at 0x509951: file nbtree.c, line 959.(gdb) cContinuing.Breakpoint 1, btvacuumscan (info=0x7ffd33d29b70, stats=0x23ea988, callback=0x6bf507 , callback_state=0x23eaaf8, cycleid=37964, oldestBtpoXact=0x7ffd33d29a40) at nbtree.c:959959 Relation rel = info->Index; (gdb)
Input parameters
(gdb) p * info$1 = {index = 0x7f6b76bcc688, analyze_only = false, estimated_count = true, message_level = 17, num_heap_tuples = 14444, strategy = 0x2413708} (gdb) p * stats$2 = {num_pages = 0, pages_removed = 0, estimated_count = false, num_index_tuples = 0, tuples_removed = 0, pages_deleted = 0 Pages_free = 0} (gdb) p * oldestBtpoXact$3 = 869440096 (gdb) (gdb) p (LVRelStats *) callback_state$4 = (LVRelStats *) 0x23eaaf8 (gdb) p * (LVRelStats *) callback_state$5 = {hasindex = true, old_rel_pages = 124,124, scanned_pages = 52, pinskipped_pages = 0, frozenskipped_pages = 1, tupcount_pages = 52, old_live_tuples = 14444, new_rel_tuples = 14840, new_live_tuples = 14840, new_dead_tuples = 0, pages_removed = 0 Tuples_deleted = 100,124,124,100,100, max_dead_tuples = 36084, dead_tuples = 0x7f6b76ad7050, num_index_scans = 0, latestRemovedXid = 397077, lock_waiter_detected = false}
1. Initialization statistics (IndexBulkDeleteResult structure)
(gdb) n969 stats- > estimated_count = false; (gdb) 970 stats- > num_index_tuples = 0; (gdb) 971 stats- > pages_deleted = 0; (gdb)
two。 Initialize vstate state information (BTVacState structure)
974 vstate.info = info; (gdb) 975 vstate.stats = stats; (gdb) 976 vstate.callback = callback; (gdb) 977 vstate.callback_state = callback_state; (gdb) 978 vstate.cycleid = cycleid; (gdb) 979 vstate.lastBlockVacuumed = BTREE_METAPAGE; / * Initialise at first block * / (gdb) 980 vstate.lastBlockLocked = BTREE_METAPAGE; (gdb) 981 vstate.totFreePages = 0; (gdb) 982 vstate.oldestBtpoXact = InvalidTransactionId (gdb) (gdb) p vstate$6 = {info = 0x7ffd33d29b70, stats = 0x23ea988, callback = 0x6bf507, callback_state = 0x23eaaf8, cycleid = 37964, lastBlockVacuumed = 0, lastBlockLocked = 0, totFreePages = 0, oldestBtpoXact = 0, pagedelcontext = 0x23c1d00}
3. Construct temporary context
Vstate.pagedelcontext = AllocSetContextCreate (CurrentMemoryContext, (gdb))
4. Loop through page
4.1 acquire relation Lock
1012 needLock =! RELATION_IS_LOCAL (rel); (gdb) p vstate$6 = {info = 0x7ffd33d29b70, stats = 0x23ea988, callback = 0x6bf507, callback_state = 0x23eaaf8, cycleid = 37964, lastBlockVacuumed = 0, lastBlockLocked = 0, totFreePages = 0, oldestBtpoXact = 0, pagedelcontext = 0x23c1d00} (gdb) (gdb) n1014 blkno = BTREE_METAPAGE + 1; (gdb) 1018 if (needLock) (gdb) p needLock$7 = true (gdb) n1019 LockRelationForExtension (rel, ExclusiveLock) (gdb) 1020 num_pages = RelationGetNumberOfBlocks (rel); (gdb) 1021 if (needLock) (gdb) p num_pages$8 = 60 (gdb) n1022 UnlockRelationForExtension (rel, ExclusiveLock); (gdb) 1025 if (blkno > = num_pages) (gdb) p blkno$9 = 1 (gdb) n1028 for (; blkno)
< num_pages; blkno++)(gdb) 4.2遍历block,执行btvacuumpage (gdb) 1030 btvacuumpage(&vstate, blkno, blkno);(gdb) 1028 for (; blkno < num_pages; blkno++)(gdb) 1030 btvacuumpage(&vstate, blkno, blkno);(gdb) 4.3如需要,多次遍历relation (gdb) b nbtree.c:1018Breakpoint 2 at 0x509a1f: file nbtree.c, line 1018.(gdb) cContinuing.Breakpoint 2, btvacuumscan (info=0x7ffd33d29b70, stats=0x23ea988, callback=0x6bf507 , callback_state=0x23eaaf8, cycleid=37964, oldestBtpoXact=0x7ffd33d29a40) at nbtree.c:10181018 if (needLock)(gdb) n1019 LockRelationForExtension(rel, ExclusiveLock);(gdb) 1020 num_pages = RelationGetNumberOfBlocks(rel);(gdb) 1021 if (needLock)(gdb) 1022 UnlockRelationForExtension(rel, ExclusiveLock);(gdb) 1025 if (blkno >= num_pages) (gdb) p blkno$11 = 60 (gdb) n1026 break; (gdb)
5.WAL Record processing
(gdb) n1048 if (XLogStandbyInfoActive () & & (gdb))
6. Delete temporary context
(gdb) 1067 MemoryContextDelete (vstate.pagedelcontext); (gdb)
7. Deal with free space
(gdb) 1081 if (vstate.totFreePages > 0) (gdb) 1082 IndexFreeSpaceMapVacuum (rel); (gdb)
8. Update statistics
(gdb) 1085 stats- > num_pages = num_pages; (gdb) 1086 stats- > pages_free = vstate.totFreePages; (gdb) 1088 if (oldestBtpoXact) (gdb) 1089 * oldestBtpoXact = vstate.oldestBtpoXact (gdb) p oldestBtpoXact$12 = (TransactionId *) 0x7ffd33d29a40 (gdb) p * oldestBtpoXact$13 = 869440096 (gdb) p vstate.oldestBtpoXact$14 = 397078 (gdb) n1090} (gdb) p * stats$15 = {num_pages = 60, pages_removed = 0, estimated_count = false, num_index_tuples = 8701, tuples_removed = 8701, pages_deleted = 7, pages_free = 6} (gdb)
Complete the call
(gdb) nbtbulkdelete (info=0x7ffd33d29b70, stats=0x23ea988, callback=0x6bf507, callback_state=0x23eaaf8) at nbtree.c:880880 _ bt_update_meta_cleanup_info (info- > index, oldestBtpoXact, (gdb)
Btvacuumpage
14:50:45 (xdb@ [local]: 5432) testdb=# vacuum verbose T1 politics. (gdb) b btvacuumpageBreakpoint 3 at 0x509b82: file nbtree.c, line 1106. (gdb) (gdb) cContinuing.Breakpoint 3, btvacuumpage (vstate=0x7ffd33d298d0, blkno=1, orig_blkno=1) at nbtree.c:11061106 IndexVacuumInfo * info = vstate- > info; (gdb)
Input parameters
(gdb) p * vstate$16 = {info = 0x7ffd33d29b70, stats = 0x24157e8, callback = 0x6bf507, callback_state = 0x2415958, cycleid = 37965, lastBlockVacuumed = 0, lastBlockLocked = 0, totFreePages = 0, oldestBtpoXact = 0, pagedelcontext = 0x23ea7a0} (gdb)
1. Initialize related variables
(gdb) n1107 IndexBulkDeleteResult * stats = vstate- > stats; (gdb) 1108 IndexBulkDeleteCallback callback = vstate- > callback; (gdb) 1109 void * callback_state = vstate- > callback_state; (gdb) 1110 Relation rel = info- > index; (gdb) 1115 BTPageOpaque opaque = NULL; (gdb) 1118 delete_now = false; (gdb) 1119 recurse_to = playing None; (gdb) 1122 vacuum_delay_point () (gdb) p * info$17 = {index = 0x7f6b76b0c268, analyze_only = false, estimated_count = true, message_level = 17, num_heap_tuples = 14840, strategy = 0x2403478} (gdb) p * stats$18 = {num_pages = 0, pages_removed = 0, estimated_count = false, num_index_tuples = 0, tuples_removed = 0, pages_deleted = 0, pages_free = 0} (gdb) p rel$19 = (Relation) 0x7f6b76b0c268 (gdb) p * rel$20 = {rd_node = {spcNode = 1663, dbNode = 16402, relNode = 50823} Rd_smgr = 0x23d0270, rd_refcnt = 1, rd_backend =-1, rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true, rd_indexvalid = 0'\ 000mm, rd_statvalid = false, rd_createSubid = 0, rd_newRelfilenodeSubid = 0, rd_rel = 0x7f6b76bccd20, rd_att = 0x7f6b76bcc9b8, rd_id = 50823, rd_lockInfo = {lockRelId = {relId = 50823, dbId = 16402}}, rd_rules = 0x0, rd_rulescxt = 0x0, trigdesc = 0x0, rd_rsdesc = 0x0 Rd_fkeylist = 0x0, rd_fkeyvalid = false, rd_partkeycxt = 0x0, rd_partkey = 0x0, rd_pdcxt = 0x0, rd_partdesc = 0x0, rd_partcheck = 0x0, rd_indexlist = 0x0, rd_oidindex = 0, rd_pkindex = 0, rd_replidindex = 0, rd_statlist = 0x0, rd_indexattr = 0x0, rd_projindexattr = 0x0, rd_keyattr = 0x0, rd_pkattr = 0x0, rd_idattr = 0x0, rd_projidx = 0x0, rd_pubactions = 0x0, rd_options = rd_options, 0x0 = 0x0 Rd_indextuple = 0x7f6b76bcc8a0, rd_amhandler = 330,rd_indexcxt = 0x236b340, rd_amroutine = 0x236b480, rd_opfamily = 0x236b598, rd_opcintype = 0x236b5b8, rd_support = 0x236b5d8, rd_supportinfo = 0x236b600, rd_indoption = 0x236b738, rd_indexprs = 0x0, rd_indpred = 0x0, rd_exclops = 0x0, rd_exclprocs = 0x0, rd_exclstrats = 0x0, rd_amcache = 0x0, rd_indcollation = 0x236b718, rd_fdwroutine = 0x0, rd_toastoid = 0, pgstat_info = 0x23c4198} (0x23c4198)
two。 Call ReadBufferExtended to read block into buffer, lock buffer, and get page
(gdb) 1130 buf = ReadBufferExtended (rel, MAIN_FORKNUM, blkno, RBM_NORMAL, (gdb) n1132 LockBuffer (buf, BT_READ); (gdb) 1133 page = BufferGetPage (buf) (gdb) 1134 if (! PageIsNew (page)) (gdb) p * page$21 = 1'\ 001' (gdb) p page$22 = (Page) 0x7f6b4add8380 "\ 001" (gdb) p * (PageHeader) page$23 = {pd_lsn = {xlogid = 1, xrecoff = 1320733408}, pd_checksum = 0, pd_flags = 0, pd_lower = 28, pd_upper = 8168, pd_special = 8176, pd_pagesize_version = 8196, pd_prune_xid = 0, pd_linp = 0x7f6b4add8398} (gdb)
3. If it is not new page, perform a check and get the BTPageOpaque
(gdb) n1136 _ bt_checkpage (rel, buf); (gdb) 1137 opaque = (BTPageOpaque) PageGetSpecialPointer (page); (gdb) p buf$24 = 224 (gdb) n1145 if (blkno! = orig_blkno) (gdb) p opaque$25 = (BTPageOpaque) 0x7f6b4adda370 (gdb) p * opaque$26 = {btpo_prev = 0, btpo_next = 33, btpo = {level = 397073, xact = 397073}, btpo_flags = 5, btpo_cycleid = 0} (gdb)
4. If the block number is different from the original, recursive processing is in progress, such as page recyclable or negligible, or not leaf node or cycleid is different, call _ bt_relbuf, return; otherwise continue to execute
(gdb) n1145 if (blkno! = orig_blkno)
5. Carry out relevant judgments
5.1If page can be recycled, the recycled page
(gdb) n1158 if (_ bt_page_recyclable (page)) (gdb) 1161 RecordFreeIndexPage (rel, blkno); (gdb) 1162 vstate- > totFreePages++; (gdb) p blkno$27 = 1 (gdb) n1163 stats- > pages_deleted++; (gdb)
5.2 update statistics if page has been deleted but cannot be recycled
N/A
5.3 if page is Half-dead, try to delete (set delete_now to T)
N/A
5.5.If you try to delete (delete_now is T), call _ bt_pagedel to delete and update the statistics
Otherwise, call _ bt_relbuf
1329 if (delete_now) (gdb) 1353 _ bt_relbuf (rel, buf)
5.6. judge recurse_to! = P_NONE, if T, restart, otherwise exit
1362 if (recurse_to! = P_NONE) (gdb) p recurse_to$29 = 0 (gdb) p P_NONE$30 = 0 (gdb) n1367} (gdb)
Enter the logic of page as a leaf node
5.4 for example, page is a leaf node.
(gdb) del Delete all breakpoints? (y or n) y (gdb) b nbtree.c:1182Breakpoint 5 at 0x509e61: file nbtree.c, line 1182. (gdb) cContinuing.Breakpoint 5, btvacuumpage (vstate=0x7ffd33d298d0, blkno=6, orig_blkno=6) at nbtree.c:11941194 LockBuffer (buf, BUFFER_LOCK_UNLOCK); (gdb)
5.4.1 initialization variables
N/A
5.4.2 Lock buffer
1194 LockBuffer (buf, BUFFER_LOCK_UNLOCK); (gdb) N1195 LockBufferForCleanup (buf); (gdb)
5.4.3 record has obtained the maximum leaf page number of cleanup lock
(gdb) 1201 if (blkno > vstate- > lastBlockLocked) (gdb) p blkno$31 = 6 (gdb) p vstate- > lastBlockLocked$32 = 0 (gdb) n1202 vstate- > lastBlockLocked = blkno; (gdb)
5.4.4 check whether we need to recursively return to the previous page
(gdb) 1211 if (vstate- > cycleid! = 0 & & (gdb) p vstate- > cycleid$33 = 37965 (gdb) p opaque- > btpo_cycleid$34 = 0 (gdb) p vstate- > cycleid$35 = 37965 (gdb) n1212 opaque- > btpo_cycleid = = vstate- > cycleid & & (gdb) 1211 if (vstate- > cycleid! = 0 & & (gdb) 1222 ndeletable = 0; (gdb) 1223 minoff = P_FIRSTDATAKEY (opaque) (gdb) 1224 maxoff = PageGetMaxOffsetNumber (page); (gdb) 1225 if (callback) (gdb) p minoff$36 = 2 (gdb) p maxoff$37 = 174( gdb)
5.4.5 scan all entries to see which entries need to be deleted according to the callback function (written to the deletable array)
(gdb) n1227 for (offnum = minoff; (gdb) 1234 itup = (IndexTuple) PageGetItem (page, (gdb) 1236 htup = & (itup- > t_tid) (gdb) p * itup$38 = {t_tid = {ip_blkid = {bi_hi = 0, bi_lo = 103}, ip_posid = 138}, t_info = 16} (gdb) n1259 if (callback (htup, callback_state)) (gdb) p * htup$41 = {ip_blkid = {bi_hi = 0, bi_lo = 103}, ip_posid = 138} (gdb)
Enter the callback function lazy_tid_reaped
(gdb) steplazy_tid_reaped (itemptr=0x7f6b4addfd40, state=0x2415958) at vacuumlazy.c:21402140 LVRelStats * vacrelstats = (LVRelStats *) state; (gdb)
Call bsearch to determine whether the condition is met, and return NULL, which is not satisfied.
(gdb) n2145 vacrelstats- > num_dead_tuples, (gdb) 2143 res = (ItemPointer) bsearch ((void *) itemptr, (gdb) 2144 (void *) vacrelstats- > dead_tuples, (gdb) 2143 res = (ItemPointer) bsearch ((void *) itemptr, (gdb) 2149 return (res! = NULL)) (gdb) p res$42 = (ItemPointer) 0x0 (gdb) (gdb) n2150} (gdb) btvacuumpage (vstate=0x7ffd33d298d0, blkno=6, orig_blkno=6) at nbtree.c:12291229 offnum = OffsetNumberNext (offnum)) (gdb)
5.4.6 if the array is not empty, _ bt_delitems_vacuum is called to record the relevant information
If the array is empty, determine whether the page is split in this vacuum cycle, clear the btpo_cycleid tag, and the tag buffer is dirty
(gdb) delDelete all breakpoints? (y or n) y (gdb) b nbtree.c:1284Breakpoint 7 at 0x50a035: file nbtree.c, line 1284. (gdb) cContinuing.Breakpoint 7, btvacuumpage (vstate=0x7ffd33d298d0, blkno=48, orig_blkno=48) at nbtree.c:12841284 _ bt_delitems_vacuum (rel, buf, deletable, ndeletable, (gdb) (gdb) n1291 if (blkno > vstate- > lastBlockVacuumed) (gdb) p blkno$43 = 48 (gdb) p vstate- > lastBlockVacuumed$44 = 0 (gdb) n1292 vstate- > lastBlockVacuumed = blkno (gdb) 1294 stats- > tuples_removed + = ndeletable; (gdb) 1296 maxoff = PageGetMaxOffsetNumber (page); (gdb) 1323 if (minoff > maxoff) (gdb) p minoff$45 = 2 (gdb) p maxoff$46 = 67 (gdb) n1326 stats- > num_index_tuples + = maxoff-minoff + 1; (gdb)
DONE!
IV. Reference materials
PG Source Code