diff options
Diffstat (limited to 'src/backend/storage/page/bufpage.c')
-rw-r--r-- | src/backend/storage/page/bufpage.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index 147ba4d9232..366d57ea7ac 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -688,22 +688,14 @@ compactify_tuples(itemIdCompact itemidbase, int nitems, Page page, bool presorte * * This routine is usable for heap pages only, but see PageIndexMultiDelete. * - * Never removes unused line pointers. PageTruncateLinePointerArray can - * safely remove some unused line pointers. It ought to be safe for this - * routine to free unused line pointers in roughly the same way, but it's not - * clear that that would be beneficial. - * - * PageTruncateLinePointerArray is only called during VACUUM's second pass - * over the heap. Any unused line pointers that it sees are likely to have - * been set to LP_UNUSED (from LP_DEAD) immediately before the time it is - * called. On the other hand, many tables have the vast majority of all - * required pruning performed opportunistically (not during VACUUM). And so - * there is, in general, a good chance that even large groups of unused line - * pointers that we see here will be recycled quickly. + * This routine removes unused line pointers from the end of the line pointer + * array. This is possible when dead heap-only tuples get removed by pruning, + * especially when there were HOT chains with several tuples each beforehand. * * Caller had better have a full cleanup lock on page's buffer. As a side * effect the page's PD_HAS_FREE_LINES hint bit will be set or unset as - * needed. + * needed. Caller might also need to account for a reduction in the length of + * the line pointer array following array truncation. */ void PageRepairFragmentation(Page page) @@ -718,6 +710,7 @@ PageRepairFragmentation(Page page) int nline, nstorage, nunused; + OffsetNumber finalusedlp = InvalidOffsetNumber; int i; Size totallen; bool presorted = true; /* For now */ @@ -771,10 +764,13 @@ PageRepairFragmentation(Page page) totallen += itemidptr->alignedlen; itemidptr++; } + + finalusedlp = i; /* Could be the final non-LP_UNUSED item */ } else { /* Unused entries should have lp_len = 0, but make sure */ + Assert(!ItemIdHasStorage(lp)); ItemIdSetUnused(lp); nunused++; } @@ -798,6 +794,19 @@ PageRepairFragmentation(Page page) compactify_tuples(itemidbase, nstorage, page, presorted); } + if (finalusedlp != nline) + { + /* The last line pointer is not the last used line pointer */ + int nunusedend = nline - finalusedlp; + + Assert(nunused >= nunusedend && nunusedend > 0); + + /* remove trailing unused line pointers from the count */ + nunused -= nunusedend; + /* truncate the line pointer array */ + ((PageHeader) page)->pd_lower -= (sizeof(ItemIdData) * nunusedend); + } + /* Set hint bit for PageAddItemExtended */ if (nunused > 0) PageSetHasFreeLinePointers(page); |