@@ -844,39 +844,115 @@ heap_page_prune_execute(Buffer buffer,
844
844
{
845
845
Page page = (Page ) BufferGetPage (buffer );
846
846
OffsetNumber * offnum ;
847
- int i ;
847
+ HeapTupleHeader htup PG_USED_FOR_ASSERTS_ONLY ;
848
848
849
849
/* Shouldn't be called unless there's something to do */
850
850
Assert (nredirected > 0 || ndead > 0 || nunused > 0 );
851
851
852
852
/* Update all redirected line pointers */
853
853
offnum = redirected ;
854
- for (i = 0 ; i < nredirected ; i ++ )
854
+ for (int i = 0 ; i < nredirected ; i ++ )
855
855
{
856
856
OffsetNumber fromoff = * offnum ++ ;
857
857
OffsetNumber tooff = * offnum ++ ;
858
858
ItemId fromlp = PageGetItemId (page , fromoff );
859
+ ItemId tolp PG_USED_FOR_ASSERTS_ONLY ;
860
+
861
+ #ifdef USE_ASSERT_CHECKING
862
+
863
+ /*
864
+ * Any existing item that we set as an LP_REDIRECT (any 'from' item)
865
+ * must be the first item from a HOT chain. If the item has tuple
866
+ * storage then it can't be a heap-only tuple. Otherwise we are just
867
+ * maintaining an existing LP_REDIRECT from an existing HOT chain that
868
+ * has been pruned at least once before now.
869
+ */
870
+ if (!ItemIdIsRedirected (fromlp ))
871
+ {
872
+ Assert (ItemIdHasStorage (fromlp ) && ItemIdIsNormal (fromlp ));
873
+
874
+ htup = (HeapTupleHeader ) PageGetItem (page , fromlp );
875
+ Assert (!HeapTupleHeaderIsHeapOnly (htup ));
876
+ }
877
+ else
878
+ {
879
+ /* We shouldn't need to redundantly set the redirect */
880
+ Assert (ItemIdGetRedirect (fromlp ) != tooff );
881
+ }
882
+
883
+ /*
884
+ * The item that we're about to set as an LP_REDIRECT (the 'from'
885
+ * item) will point to an existing item (the 'to' item) that is
886
+ * already a heap-only tuple. There can be at most one LP_REDIRECT
887
+ * item per HOT chain.
888
+ *
889
+ * We need to keep around an LP_REDIRECT item (after original
890
+ * non-heap-only root tuple gets pruned away) so that it's always
891
+ * possible for VACUUM to easily figure out what TID to delete from
892
+ * indexes when an entire HOT chain becomes dead. A heap-only tuple
893
+ * can never become LP_DEAD; an LP_REDIRECT item or a regular heap
894
+ * tuple can.
895
+ */
896
+ tolp = PageGetItemId (page , tooff );
897
+ Assert (ItemIdHasStorage (tolp ) && ItemIdIsNormal (tolp ));
898
+ htup = (HeapTupleHeader ) PageGetItem (page , tolp );
899
+ Assert (HeapTupleHeaderIsHeapOnly (htup ));
900
+ #endif
859
901
860
902
ItemIdSetRedirect (fromlp , tooff );
861
903
}
862
904
863
905
/* Update all now-dead line pointers */
864
906
offnum = nowdead ;
865
- for (i = 0 ; i < ndead ; i ++ )
907
+ for (int i = 0 ; i < ndead ; i ++ )
866
908
{
867
909
OffsetNumber off = * offnum ++ ;
868
910
ItemId lp = PageGetItemId (page , off );
869
911
912
+ #ifdef USE_ASSERT_CHECKING
913
+
914
+ /*
915
+ * An LP_DEAD line pointer must be left behind when the original item
916
+ * (which is dead to everybody) could still be referenced by a TID in
917
+ * an index. This should never be necessary with any individual
918
+ * heap-only tuple item, though. (It's not clear how much of a problem
919
+ * that would be, but there is no reason to allow it.)
920
+ */
921
+ if (ItemIdHasStorage (lp ))
922
+ {
923
+ Assert (ItemIdIsNormal (lp ));
924
+ htup = (HeapTupleHeader ) PageGetItem (page , lp );
925
+ Assert (!HeapTupleHeaderIsHeapOnly (htup ));
926
+ }
927
+ else
928
+ {
929
+ /* Whole HOT chain becomes dead */
930
+ Assert (ItemIdIsRedirected (lp ));
931
+ }
932
+ #endif
933
+
870
934
ItemIdSetDead (lp );
871
935
}
872
936
873
937
/* Update all now-unused line pointers */
874
938
offnum = nowunused ;
875
- for (i = 0 ; i < nunused ; i ++ )
939
+ for (int i = 0 ; i < nunused ; i ++ )
876
940
{
877
941
OffsetNumber off = * offnum ++ ;
878
942
ItemId lp = PageGetItemId (page , off );
879
943
944
+ #ifdef USE_ASSERT_CHECKING
945
+
946
+ /*
947
+ * Only heap-only tuples can become LP_UNUSED during pruning. They
948
+ * don't need to be left in place as LP_DEAD items until VACUUM gets
949
+ * around to doing index vacuuming.
950
+ */
951
+ Assert (ItemIdHasStorage (lp ) && ItemIdIsNormal (lp ));
952
+ htup = (HeapTupleHeader ) PageGetItem (page , lp );
953
+ Assert (HeapTupleHeaderIsHeapOnly (htup ));
954
+ #endif
955
+
880
956
ItemIdSetUnused (lp );
881
957
}
882
958
0 commit comments