Skip to content

Commit 7526314

Browse files
committed
Have the heap check if current page needs scan-time pruning
Add scan-time heap page pruning functionality and a mechanism to track page modifications during scans and re-evaluate pruning eligibility. This addresses the issue where multiple updates during a scan don't trigger heap page pruning until the next scan.
1 parent 3d21ed2 commit 7526314

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

src/backend/access/heap/heapam.c

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,11 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
446446
scan->rs_ntuples = 0;
447447
scan->rs_cindex = 0;
448448

449+
/* Initialize scan-time pruning tracking */
450+
scan->rs_page_updates = 0;
451+
scan->rs_page_pruned = false;
452+
scan->rs_last_pruned_block = InvalidBlockNumber;
453+
449454
/*
450455
* Initialize to ForwardScanDirection because it is most common and
451456
* because heap scans go forward before going backward (e.g. CURSORs).
@@ -925,6 +930,10 @@ heapgettup(HeapScanDesc scan,
925930

926931
Assert(BufferGetBlockNumber(scan->rs_cbuf) == scan->rs_cblock);
927932

933+
/* Reset page tracking for new page */
934+
scan->rs_page_updates = 0;
935+
scan->rs_page_pruned = false;
936+
928937
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
929938
page = heapgettup_start_page(scan, dir, &linesleft, &lineoff);
930939
continue_page:
@@ -942,7 +951,12 @@ heapgettup(HeapScanDesc scan,
942951
ItemId lpp = PageGetItemId(page, lineoff);
943952

944953
if (!ItemIdIsNormal(lpp))
954+
{
955+
/* Track dead line pointers as potential modifications */
956+
if (ItemIdIsDead(lpp))
957+
scan->rs_page_updates++;
945958
continue;
959+
}
946960

947961
tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
948962
tuple->t_len = ItemIdGetLength(lpp);
@@ -972,10 +986,27 @@ heapgettup(HeapScanDesc scan,
972986
}
973987

974988
/*
975-
* if we get here, it means we've exhausted the items on this page and
976-
* it's time to move to the next.
989+
* Before moving to next page, check if current page needs scan-time
990+
* pruning. This addresses the issue where multiple updates during a
991+
* scan don't trigger pruning until the next scan.
977992
*/
978993
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
994+
if (scan->rs_page_updates > 0 &&
995+
scan->rs_cblock != scan->rs_last_pruned_block &&
996+
PageNeedsScanPruning(page, scan->rs_page_updates))
997+
{
998+
/* Attempt opportunistic pruning */
999+
heap_page_prune_opt(scan->rs_base.rs_rd, scan->rs_cbuf, 0);
1000+
1001+
/* Mark this block as pruned to avoid repeated attempts */
1002+
scan->rs_last_pruned_block = scan->rs_cblock;
1003+
scan->rs_page_pruned = true;
1004+
}
1005+
1006+
/*
1007+
* If we get here, it means we've exhausted the items on this page and
1008+
* it's time to move to the next.
1009+
*/
9791010
}
9801011

9811012
/* end of scan */
@@ -1042,6 +1073,10 @@ heapgettup_pagemode(HeapScanDesc scan,
10421073

10431074
Assert(BufferGetBlockNumber(scan->rs_cbuf) == scan->rs_cblock);
10441075

1076+
/* Reset page tracking for new page */
1077+
scan->rs_page_updates = 0;
1078+
scan->rs_page_pruned = false;
1079+
10451080
/* prune the page and determine visible tuple offsets */
10461081
heap_prepare_pagescan((TableScanDesc) scan);
10471082
page = BufferGetPage(scan->rs_cbuf);
@@ -1079,6 +1114,15 @@ heapgettup_pagemode(HeapScanDesc scan,
10791114
}
10801115
}
10811116

1117+
/* Before ending scan, check if current page needs scan-time pruning */
1118+
if (BufferIsValid(scan->rs_cbuf) && scan->rs_page_updates > 0 &&
1119+
scan->rs_cblock != scan->rs_last_pruned_block &&
1120+
PageNeedsScanPruning(BufferGetPage(scan->rs_cbuf), scan->rs_page_updates))
1121+
{
1122+
heap_page_prune_opt(scan->rs_base.rs_rd, scan->rs_cbuf, 0);
1123+
scan->rs_last_pruned_block = scan->rs_cblock;
1124+
}
1125+
10821126
/* end of scan */
10831127
if (BufferIsValid(scan->rs_cbuf))
10841128
ReleaseBuffer(scan->rs_cbuf);

src/include/access/heapam.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ typedef struct HeapScanDescData
9797
uint32 rs_cindex; /* current tuple's index in vistuples */
9898
uint32 rs_ntuples; /* number of visible tuples on page */
9999
OffsetNumber rs_vistuples[MaxHeapTuplesPerPage]; /* their offsets */
100+
101+
/* scan-time pruning tracking */
102+
int rs_page_updates; /* count of updates/deletes on current
103+
* page */
104+
bool rs_page_pruned; /* whether current page was already pruned */
105+
BlockNumber rs_last_pruned_block; /* last block we attempted pruning on */
100106
} HeapScanDescData;
101107
typedef struct HeapScanDescData *HeapScanDesc;
102108

src/include/storage/bufpage.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,12 @@ PageHasPrunable(const PageData *page)
424424
return PageHasFreeLinePointers(page) && PageGetMaxOffsetNumber(page) >= 4;
425425
}
426426

427+
static inline bool
428+
PageNeedsScanPruning(const PageData *page, int modifications)
429+
{
430+
return modifications >= 3 && PageHasPrunable(page);
431+
}
432+
427433
static inline void
428434
PageSetFull(Page page)
429435
{

0 commit comments

Comments
 (0)