From edee0124dfb7933b9953e6d78912b0962d66e3e1 Mon Sep 17 00:00:00 2001 From: yaoxin Date: Thu, 12 Dec 2024 20:12:12 +0800 Subject: [PATCH] fix spaces expansion of uheap --- .../storage/access/ustore/knl_pruneuheap.cpp | 35 +++++++++++- .../storage/access/ustore/knl_uheap.cpp | 55 +++++++++++++------ .../storage/access/ustore/knl_uhio.cpp | 39 +++++++++++-- .../storage/access/ustore/knl_undoaction.cpp | 16 ++---- .../storage/access/ustore/knl_upage.cpp | 7 ++- .../storage/freespace/freespace.cpp | 4 +- src/gausskernel/storage/freespace/fsmpage.cpp | 22 +++++--- src/include/access/ustore/knl_uheap.h | 7 +++ src/include/access/ustore/knl_upage.h | 2 + 9 files changed, 140 insertions(+), 47 deletions(-) diff --git a/src/gausskernel/storage/access/ustore/knl_pruneuheap.cpp b/src/gausskernel/storage/access/ustore/knl_pruneuheap.cpp index 801ff6cd33..dcc03865ee 100644 --- a/src/gausskernel/storage/access/ustore/knl_pruneuheap.cpp +++ b/src/gausskernel/storage/access/ustore/knl_pruneuheap.cpp @@ -239,6 +239,7 @@ int UHeapPagePrune(Relation relation, const RelationBuffer *relbuf, TransactionI } else { /* Scan the page */ maxoff = UHeapPageGetMaxOffsetNumber(page); + OffsetNumber maxTupleCount = CalculatedMaxUHeapTuplesPerPage(UPageGetTDSlotCount(page)); for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum)) { RowPtr *itemid = NULL; @@ -252,6 +253,21 @@ int UHeapPagePrune(Relation relation, const RelationBuffer *relbuf, TransactionI * deleted. */ itemid = UPageGetRowPtr(page, offnum); + if (maxoff >= maxTupleCount && RowPtrIsDeleted(itemid)) { + int tdSlot = RowPtrGetTDSlot(itemid); + if (tdSlot == UHEAPTUP_SLOT_FROZEN) { + UHeapPruneRecordDead(&prstate, offnum, relation); + ndeleted ++; + continue; + } + TD* td = (TD*)PageGetTDPointerBySlot(page, tdSlot); + TransactionId xid = td->xactid; + if (TransactionIdIsNormal(xid) && TransactionIdPrecedes(xid, oldestXmin)) { + UHeapPruneRecordDead(&prstate, offnum, relation); + ndeleted ++; + } + continue; + } if (!RowPtrIsUsed(itemid) || RowPtrIsDead(itemid) || RowPtrIsDeleted(itemid)) { continue; } @@ -445,7 +461,7 @@ bool UHeapPagePruneOpt(Relation relation, Buffer buffer, OffsetNumber offnum, Si if (spaceRequired < pagefree) forcePrune = true; } - + /* * Let's see if we really need pruning. * @@ -455,7 +471,6 @@ bool UHeapPagePruneOpt(Relation relation, Buffer buffer, OffsetNumber offnum, Si if (!UPageIsPrunableWithXminHorizon(page, oldestXmin) && !forcePrune) { return false; } - UHeapPagePruneGuts(relation, &relbuf, oldestXmin, offnum, spaceRequired, true, forcePrune, &ignore, &pruned); if (pruned) { @@ -537,6 +552,7 @@ int UHeapPagePruneGuts(Relation relation, const RelationBuffer *relbuf, Transact * rows. */ maxoff = UHeapPageGetMaxOffsetNumber(page); + OffsetNumber maxTupleCount = CalculatedMaxUHeapTuplesPerPage(UPageGetTDSlotCount(page)); for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum)) { RowPtr *itemid = NULL; @@ -550,6 +566,21 @@ int UHeapPagePruneGuts(Relation relation, const RelationBuffer *relbuf, Transact * deleted. */ itemid = UPageGetRowPtr(page, offnum); + if (maxoff >= maxTupleCount && RowPtrIsDeleted(itemid)) { + int tdSlot = RowPtrGetTDSlot(itemid); + if (tdSlot == UHEAPTUP_SLOT_FROZEN) { + UHeapPruneRecordDead(&prstate, offnum, relation); + ndeleted ++; + continue; + } + TD* td = (TD*)PageGetTDPointerBySlot(page, tdSlot); + TransactionId xid = td->xactid; + if (TransactionIdIsNormal(xid) && TransactionIdPrecedes(xid, oldestXmin)) { + UHeapPruneRecordDead(&prstate, offnum, relation); + ndeleted ++; + } + continue; + } if (!RowPtrIsUsed(itemid) || RowPtrIsDead(itemid) || RowPtrIsDeleted(itemid)) { continue; } diff --git a/src/gausskernel/storage/access/ustore/knl_uheap.cpp b/src/gausskernel/storage/access/ustore/knl_uheap.cpp index 0355b0ed1c..2543e341f2 100644 --- a/src/gausskernel/storage/access/ustore/knl_uheap.cpp +++ b/src/gausskernel/storage/access/ustore/knl_uheap.cpp @@ -505,6 +505,32 @@ template void UHeapFinalizeDML(Relation rel, Buffer buffer } } +void UHeapUpdateFSM(Relation relation, Buffer buf, bool usePotentialFreeSpace) +{ + if (!BufferIsInvalid(buf)) { + return; + } + + Size freespace = 0; + Page page = BufferGetPage(buf); + UHeapPageHeader hdr = (UHeapPageHeader)page; + BlockNumber blkno = BufferGetBlockNumber(buf); + if (usePotentialFreeSpace) { + freespace = hdr->potential_freespace; + } else { + freespace = PageGetUHeapFreeSpace(page); + } + + RecordPageWithFreeSpace(relation, blkno, freespace); + int delta = UHeapGetFreespaceDelta((UHeapPageHeader)page); + if (FSMUpdateHeuristic(delta)) { +#ifdef DEBUG_UHEAP + UHEAPSTAT_COUNT_OP_PRUNEPAGE_SPC(del, freespace); +#endif + UpdateFreeSpaceMap(relation, blkno, blkno, freespace, false); + } +} + void UHeapPagePruneFSM(Relation relation, Buffer buffer, TransactionId fxid, Page page, BlockNumber blkno) { bool hasPruned = UHeapPagePruneOptPage(relation, buffer, fxid); @@ -516,16 +542,7 @@ void UHeapPagePruneFSM(Relation relation, Buffer buffer, TransactionId fxid, Pag #endif if (hasPruned) { - Size freespace = PageGetUHeapFreeSpace(page); - double thres = RelationGetTargetPageFreeSpacePrune(relation, UHEAP_DEFAULT_FILLFACTOR); - double prob = FSM_UPDATE_HEURISTI_PROBABILITY * freespace / thres; - RecordPageWithFreeSpace(relation, blkno, freespace); - if (rand() % 100 >= 100.0 - prob * 100.0) { -#ifdef DEBUG_UHEAP - UHEAPSTAT_COUNT_OP_PRUNEPAGE_SPC(del, freespace); -#endif - UpdateFreeSpaceMap(relation, blkno, blkno, freespace, false); - } + UHeapUpdateFSM(relation, buffer, false); } } @@ -621,7 +638,6 @@ reacquire_buffer: RelationGetRelationName(rel), buffer, phdr->pd_upper - phdr->pd_lower, tuple->disk_tuple_size))); blkno = BufferGetBlockNumber(buffer); - UHeapPagePruneFSM(rel, buffer, fxid, page, blkno); /* Prepare Undo record before buffer lock since undo record length is fixed */ UndoPersistence persistence = UndoPersistenceForRelation(rel); @@ -723,6 +739,7 @@ reacquire_buffer: ItemPointerGetOffsetNumber(&(tuple->ctid))); UndoRecordVerify(undorec); } + UHeapUpdateFSM(rel, buffer, true); UHeapFinalizeDML(rel, buffer, NULL, utuple, tuple, NULL, false, false); return InvalidOid; @@ -2032,8 +2049,6 @@ TM_Result UHeapDelete(Relation relation, ItemPointer tid, CommandId cid, Snapsho RowPtr *rp = UPageGetRowPtr(page, offnum); Assert(RowPtrIsNormal(rp) || RowPtrIsDeleted(rp)); - UHeapPagePruneFSM(relation, buffer, fxid, page, blkno); - UHeapResetWaitTimeForTDSlot(); check_tup_satisfies_update: @@ -2314,8 +2329,7 @@ check_tup_satisfies_update: UndoRecord *undorec = (*t_thrd.ustore_cxt.urecvec)[0]; UndoRecordVerify(undorec); } - - + UHeapUpdateFSM(relation, buffer, true); UHeapFinalizeDML(relation, buffer, NULL, &utuple, NULL, &(utuple.ctid), hasTupLock, false); return TM_Ok; @@ -3324,7 +3338,10 @@ check_tup_satisfies_update: UndoRecord *newundorec = (*urecvec)[1]; UndoRecordVerify(newundorec); } - + UHeapUpdateFSM(relation, buffer, true); + if (!useInplaceUpdate) { + UHeapUpdateFSM(relation, newbuf, true); + } UHeapFinalizeDML(relation, buffer, &newbuf, newtup, uheaptup, &(oldtup.ctid), haveTupleLock, useInplaceUpdate); if (oldKeyTuple != NULL && isOldTupleCopied) { @@ -3900,6 +3917,7 @@ int UHeapPageReserveTransactionSlot(Relation relation, Buffer buf, TransactionId * We just extended the number of slots. * Return first slot from the extended ones. */ + UHeapRecordPotentialFreeSpace(buf, -1 * nExtended * sizeof(TD)); ereport(DEBUG5, (errmsg("TD array extended by %d slots for Rel: %s, blkno: %d", nExtended, RelationGetRelationName(relation), BufferGetBlockNumber(buf)))); pgstat_report_waitstatus(oldStatus); @@ -4268,9 +4286,10 @@ void UHeapFreezeOrInvalidateTuples(Buffer buf, int nSlots, const int *slots, boo /* * the corresponding slot is being marked as frozen. - * So, marking it as dead. + * So, marking it as unused. */ - RowPtrSetDead(rowptr); + RowPtrSetUnused(rowptr); + UPageSetHasFreeLinePointers(page); } else { tupHdr = (UHeapDiskTuple)UPageGetRowData(page, rowptr); UHeapTupleHeaderSetTDSlot(tupHdr, UHEAPTUP_SLOT_FROZEN); diff --git a/src/gausskernel/storage/access/ustore/knl_uhio.cpp b/src/gausskernel/storage/access/ustore/knl_uhio.cpp index 984950dbdf..47be604023 100644 --- a/src/gausskernel/storage/access/ustore/knl_uhio.cpp +++ b/src/gausskernel/storage/access/ustore/knl_uhio.cpp @@ -195,12 +195,22 @@ loop: */ pageFreeSpace = PageGetUHeapFreeSpace(page); + bool findAvaliableBuffer = false; if (len + saveFreeSpace <= pageFreeSpace) { - /* use this page as future insert target, too */ + findAvaliableBuffer = true; + } else if (len + saveFreeSpace <= ((UHeapPageHeader)page)->potential_freespace) { + if (UHeapPagePruneOpt(relation, buffer, InvalidOffsetNumber, 0)) { + pageFreeSpace = PageGetUHeapFreeSpace(page); + if (len + saveFreeSpace <= pageFreeSpace) { + findAvaliableBuffer = true; + } + } + } + if (findAvaliableBuffer) { + /* use this page as future insert target, too */ RelationSetTargetBlock(relation, targetBlock); return buffer; } - /* * Not enough space, so we must give up our page locks * and pin (if any) and prepare to look elsewhere. We don't care @@ -420,6 +430,21 @@ start: * Check if we have a starting block already. If so, read the latest * value and start pruning there. */ + if (pgStatInfo->startBlockArray == NULL) { + /* + * Grab the starting block for pruning. + */ + PgStat_StartBlockTableKey tabkey; + tabkey.dbid = u_sess->proc_cxt.MyDatabaseId; + tabkey.relid = RelationGetRelid(relation); + tabkey.parentid = RelationIsPartition(relation) ? relation->parentId : InvalidOid; + startBlockEntry = GetStartBlockHashEntry(&tabkey); + Assert(startBlockEntry); + + pgStatInfo->startBlockIndex = GetTopTransactionId() % START_BLOCK_ARRAY_SIZE; + pgStatInfo->startBlockArray = startBlockEntry->starting_blocks; + } + if (pgStatInfo->startBlockArray != NULL) { /* Temporarily tell other backends we are working on this subset. * pg_atomic_exchange_u32 should return the old value. @@ -520,6 +545,7 @@ BlockNumber RelationPruneBlockAndReturn(Relation relation, BlockNumber start_blo BlockNumber pruneTryCnt = 0; *next_block = start_block; PgStat_TableStatus *pgStatInfo = relation->pgstat_info; + int delta; /* Handle the case of relation truncation */ if (nblocks == 0) { @@ -596,12 +622,15 @@ BlockNumber RelationPruneBlockAndReturn(Relation relation, BlockNumber start_blo break; } + /* Done with the easy cases, we try to prune it now */ - pruned = UHeapPagePruneOpt(relation, buffer, InvalidOffsetNumber, 0); - freespace = PageGetUHeapFreeSpace(page); + delta = UHeapGetFreespaceDelta((UHeapPageHeader)page); + if (FSMUpdateHeuristic(delta)) { + pruned = UHeapPagePruneOpt(relation, buffer, InvalidOffsetNumber, 0); + } UnlockReleaseBuffer(buffer); - if (pruned) { + freespace = PageGetUHeapFreeSpace(page); RecordPageWithFreeSpace(relation, blkno, freespace); if (required_size <= freespace) { result = blkno; diff --git a/src/gausskernel/storage/access/ustore/knl_undoaction.cpp b/src/gausskernel/storage/access/ustore/knl_undoaction.cpp index ec3d824e62..bb1444cecb 100644 --- a/src/gausskernel/storage/access/ustore/knl_undoaction.cpp +++ b/src/gausskernel/storage/access/ustore/knl_undoaction.cpp @@ -636,12 +636,8 @@ void ExecuteUndoForInsert(Relation rel, Buffer buffer, OffsetNumber off, Transac /* Rollback insert - increment the potential space for the Page */ UHeapRecordPotentialFreeSpace(buffer, SHORTALIGN(rp->len)); - if (RelationGetForm(rel)->relhasindex) { - RowPtrSetDead(rp); - } else { - RowPtrSetUnused(rp); - PageSetHasFreeLinePointers(page); - } + RowPtrSetUnused(rp); + UPageSetHasFreeLinePointers(page); UPageSetPrunable(page, xid); } @@ -671,12 +667,8 @@ void ExecuteUndoForInsertRecovery(Buffer buffer, OffsetNumber off, TransactionId /* Rollback insert - increment the potential space for the Page */ UHeapRecordPotentialFreeSpace(buffer, SHORTALIGN(rp->len)); - if (relhasindex) { - RowPtrSetDead(rp); - } else { - RowPtrSetUnused(rp); - PageSetHasFreeLinePointers(page); - } + RowPtrSetUnused(rp); + UPageSetHasFreeLinePointers(page); UPageSetPrunable(page, xid); } diff --git a/src/gausskernel/storage/access/ustore/knl_upage.cpp b/src/gausskernel/storage/access/ustore/knl_upage.cpp index f4db09294d..9ecfb4c383 100644 --- a/src/gausskernel/storage/access/ustore/knl_upage.cpp +++ b/src/gausskernel/storage/access/ustore/knl_upage.cpp @@ -178,6 +178,11 @@ static bool CalculateLowerUpperPointers(Page page, OffsetNumber offsetNumber, It */ if (offsetNumber == limit || needshuffle) { lower = uphdr->pd_lower + sizeof(ItemIdData); + if (uphdr->potential_freespace >= sizeof(ItemIdData)) { + uphdr->potential_freespace -= sizeof(ItemIdData); + } else { + uphdr->potential_freespace = 0; + } } else { lower = uphdr->pd_lower; } @@ -435,7 +440,7 @@ Size PageGetUHeapFreeSpace(Page page) nline = UHeapPageGetMaxOffsetNumber(page); if (nline >= CalculatedMaxUHeapTuplesPerPage(UPageGetTDSlotCount(page))) { - if (PageHasFreeLinePointers((PageHeader)page)) { + if (UPageHasFreeLinePointers(page)) { /* * Since this is just a hint, we must confirm that there is * indeed a free line pointer diff --git a/src/gausskernel/storage/freespace/freespace.cpp b/src/gausskernel/storage/freespace/freespace.cpp index 9edd9ea68c..12c745c453 100644 --- a/src/gausskernel/storage/freespace/freespace.cpp +++ b/src/gausskernel/storage/freespace/freespace.cpp @@ -723,7 +723,7 @@ static int fsm_set_and_search(Relation rel, const FSMAddress &addr, uint16 slot, if (minValue != 0 && search) { /* Search while we still hold the lock */ - newslot = fsm_search_avail(buf, minValue, addr.level == FSM_BOTTOM_LEVEL, true); + newslot = fsm_search_avail(buf, minValue, true, true); } UnlockReleaseBuffer(buf); @@ -751,7 +751,7 @@ static BlockNumber fsm_search(Relation rel, uint8 min_cat) /* Search within the page */ if (BufferIsValid(buf)) { LockBuffer(buf, BUFFER_LOCK_SHARE); - slot = fsm_search_avail(buf, min_cat, (addr.level == FSM_BOTTOM_LEVEL), false); + slot = fsm_search_avail(buf, min_cat, true, false); if (slot == -1) max_avail = fsm_get_max_avail(BufferGetPage(buf)); UnlockReleaseBuffer(buf); diff --git a/src/gausskernel/storage/freespace/fsmpage.cpp b/src/gausskernel/storage/freespace/fsmpage.cpp index 5f0b4140ac..aa49652001 100644 --- a/src/gausskernel/storage/freespace/fsmpage.cpp +++ b/src/gausskernel/storage/freespace/fsmpage.cpp @@ -158,6 +158,7 @@ int fsm_search_avail(Buffer buf, uint8 minvalue, bool advancenext, bool exclusiv int nodeno; int target; uint16 slot; + uint32 callcount = (int32)(buf + minvalue); restart: @@ -236,16 +237,23 @@ restart: * the tree. Descend to the bottom, following a path with enough free * space, preferring to move left if there's a choice. */ + int allchild[2] = {0}; + static const int BALANCE_VALUE = 2; while (nodeno < NonLeafNodesPerPage) { - int childnodeno = leftchild(nodeno); - - if ((unsigned int)(childnodeno) < NodesPerPage && fsmpage->fp_nodes[childnodeno] >= minvalue) { - nodeno = childnodeno; + int lchild = leftchild(nodeno); + if (callcount++ % BALANCE_VALUE == 0) { + allchild[0] = lchild; + allchild[1] = lchild + 1; + } else { + allchild[0] = lchild + 1; + allchild[1] = lchild; + } + if ((unsigned int)(allchild[0]) < NodesPerPage && fsmpage->fp_nodes[allchild[0]] >= minvalue) { + nodeno = allchild[0]; continue; } - childnodeno++; /* point to right child */ - if ((unsigned int)(childnodeno) < NodesPerPage && fsmpage->fp_nodes[childnodeno] >= minvalue) { - nodeno = childnodeno; + if ((unsigned int)(allchild[1]) < NodesPerPage && fsmpage->fp_nodes[allchild[1]] >= minvalue) { + nodeno = allchild[1]; } else { /* * Oops. The parent node promised that either left or right child diff --git a/src/include/access/ustore/knl_uheap.h b/src/include/access/ustore/knl_uheap.h index 7a025c3d26..1426490d52 100644 --- a/src/include/access/ustore/knl_uheap.h +++ b/src/include/access/ustore/knl_uheap.h @@ -91,6 +91,13 @@ typedef struct { /* Controls the overall probability of conducting FSM update during page pruning */ #define FSM_UPDATE_HEURISTI_PROBABILITY 0.3 +#define UHeapGetFreespaceDelta(page) \ + ((page)->potential_freespace > ((page)->pd_upper - (page)->pd_lower) ? \ + ((page)->potential_freespace - ((page)->pd_upper - (page)->pd_lower)) : 0) + +#define FSMUpdateHeuristic(delta) \ + ((gs_random() % MaxPossibleUHeapPageFixedSpace ) < (delta * delta * 1.0 / MaxPossibleUHeapPageFixedSpace)) + typedef struct { Relation relation; Buffer buffer; diff --git a/src/include/access/ustore/knl_upage.h b/src/include/access/ustore/knl_upage.h index cca10b82d5..0ef89bb33d 100644 --- a/src/include/access/ustore/knl_upage.h +++ b/src/include/access/ustore/knl_upage.h @@ -65,6 +65,8 @@ #define PageGetTDPointer(_page) ((char *)((char *)(_page) + SizeOfUHeapPageHeaderData)) +#define PageGetTDPointerBySlot(_page, _slot) (PageGetTDPointer(_page) + _slot * sizeof(TD)) + #define GetTDCount(_uphdr) ((_uphdr)->td_count) #define UPageGetTDSlotCount(_page) ((UHeapPageHeaderData *)(_page))->td_count -- Gitee