@@ -688,22 +688,14 @@ compactify_tuples(itemIdCompact itemidbase, int nitems, Page page, bool presorte
688
688
*
689
689
* This routine is usable for heap pages only, but see PageIndexMultiDelete.
690
690
*
691
- * Never removes unused line pointers. PageTruncateLinePointerArray can
692
- * safely remove some unused line pointers. It ought to be safe for this
693
- * routine to free unused line pointers in roughly the same way, but it's not
694
- * clear that that would be beneficial.
695
- *
696
- * PageTruncateLinePointerArray is only called during VACUUM's second pass
697
- * over the heap. Any unused line pointers that it sees are likely to have
698
- * been set to LP_UNUSED (from LP_DEAD) immediately before the time it is
699
- * called. On the other hand, many tables have the vast majority of all
700
- * required pruning performed opportunistically (not during VACUUM). And so
701
- * there is, in general, a good chance that even large groups of unused line
702
- * pointers that we see here will be recycled quickly.
691
+ * This routine removes unused line pointers from the end of the line pointer
692
+ * array. This is possible when dead heap-only tuples get removed by pruning,
693
+ * especially when there were HOT chains with several tuples each beforehand.
703
694
*
704
695
* Caller had better have a full cleanup lock on page's buffer. As a side
705
696
* effect the page's PD_HAS_FREE_LINES hint bit will be set or unset as
706
- * needed.
697
+ * needed. Caller might also need to account for a reduction in the length of
698
+ * the line pointer array following array truncation.
707
699
*/
708
700
void
709
701
PageRepairFragmentation (Page page )
@@ -718,6 +710,7 @@ PageRepairFragmentation(Page page)
718
710
int nline ,
719
711
nstorage ,
720
712
nunused ;
713
+ OffsetNumber finalusedlp = InvalidOffsetNumber ;
721
714
int i ;
722
715
Size totallen ;
723
716
bool presorted = true; /* For now */
@@ -771,10 +764,13 @@ PageRepairFragmentation(Page page)
771
764
totallen += itemidptr -> alignedlen ;
772
765
itemidptr ++ ;
773
766
}
767
+
768
+ finalusedlp = i ; /* Could be the final non-LP_UNUSED item */
774
769
}
775
770
else
776
771
{
777
772
/* Unused entries should have lp_len = 0, but make sure */
773
+ Assert (!ItemIdHasStorage (lp ));
778
774
ItemIdSetUnused (lp );
779
775
nunused ++ ;
780
776
}
@@ -798,6 +794,19 @@ PageRepairFragmentation(Page page)
798
794
compactify_tuples (itemidbase , nstorage , page , presorted );
799
795
}
800
796
797
+ if (finalusedlp != nline )
798
+ {
799
+ /* The last line pointer is not the last used line pointer */
800
+ int nunusedend = nline - finalusedlp ;
801
+
802
+ Assert (nunused >= nunusedend && nunusedend > 0 );
803
+
804
+ /* remove trailing unused line pointers from the count */
805
+ nunused -= nunusedend ;
806
+ /* truncate the line pointer array */
807
+ ((PageHeader ) page )-> pd_lower -= (sizeof (ItemIdData ) * nunusedend );
808
+ }
809
+
801
810
/* Set hint bit for PageAddItemExtended */
802
811
if (nunused > 0 )
803
812
PageSetHasFreeLinePointers (page );
0 commit comments