@@ -78,7 +78,11 @@ static void heap_prune_record_redirect(PruneState *prstate,
7878static void heap_prune_record_dead (PruneState * prstate , OffsetNumber offnum , bool was_normal );
7979static void heap_prune_record_dead_or_unused (PruneState * prstate , OffsetNumber offnum , bool was_normal );
8080static void heap_prune_record_unused (PruneState * prstate , OffsetNumber offnum , bool was_normal );
81- static void heap_prune_record_unchanged (PruneState * prstate , OffsetNumber offnum );
81+
82+ static void heap_prune_record_unchanged_lp_unused (Page page , PruneState * prstate , OffsetNumber offnum );
83+ static void heap_prune_record_unchanged_lp_normal (Page page , int8 * htsv , PruneState * prstate , OffsetNumber offnum );
84+ static void heap_prune_record_unchanged_lp_dead (Page page , PruneState * prstate , OffsetNumber offnum );
85+ static void heap_prune_record_unchanged_lp_redirect (PruneState * prstate , OffsetNumber offnum );
8286
8387static void page_verify_redirects (Page page );
8488
@@ -311,7 +315,7 @@ heap_page_prune(Relation relation, Buffer buffer,
311315 /* Nothing to do if slot doesn't contain a tuple */
312316 if (!ItemIdIsUsed (itemid ))
313317 {
314- heap_prune_record_unchanged ( & prstate , offnum );
318+ heap_prune_record_unchanged_lp_unused ( page , & prstate , offnum );
315319 continue ;
316320 }
317321
@@ -324,7 +328,7 @@ heap_page_prune(Relation relation, Buffer buffer,
324328 if (unlikely (prstate .mark_unused_now ))
325329 heap_prune_record_unused (& prstate , offnum , false);
326330 else
327- heap_prune_record_unchanged ( & prstate , offnum );
331+ heap_prune_record_unchanged_lp_dead ( page , & prstate , offnum );
328332 continue ;
329333 }
330334
@@ -434,7 +438,7 @@ heap_page_prune(Relation relation, Buffer buffer,
434438 }
435439 }
436440 else
437- heap_prune_record_unchanged ( & prstate , offnum );
441+ heap_prune_record_unchanged_lp_normal ( page , presult -> htsv , & prstate , offnum );
438442 }
439443
440444 /* We should now have processed every tuple exactly once */
@@ -652,9 +656,6 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
652656 */
653657 chainitems [nchain ++ ] = offnum ;
654658
655- /*
656- * Check tuple's visibility status.
657- */
658659 switch (htsv_get_valid_status (htsv [offnum ]))
659660 {
660661 case HEAPTUPLE_DEAD :
@@ -670,9 +671,6 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
670671 case HEAPTUPLE_RECENTLY_DEAD :
671672
672673 /*
673- * This tuple may soon become DEAD. Update the hint field so
674- * that the page is reconsidered for pruning in future.
675- *
676674 * We don't need to advance the conflict horizon for
677675 * RECENTLY_DEAD tuples, even if we are removing them. This
678676 * is because we only remove RECENTLY_DEAD tuples if they
@@ -681,8 +679,6 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
681679 * tuple by virtue of being later in the chain. We will have
682680 * advanced the conflict horizon for the DEAD tuple.
683681 */
684- heap_prune_record_prunable (prstate ,
685- HeapTupleHeaderGetUpdateXid (htup ));
686682
687683 /*
688684 * Advance past RECENTLY_DEAD tuples just in case there's a
@@ -693,24 +689,8 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
693689 break ;
694690
695691 case HEAPTUPLE_DELETE_IN_PROGRESS :
696-
697- /*
698- * This tuple may soon become DEAD. Update the hint field so
699- * that the page is reconsidered for pruning in future.
700- */
701- heap_prune_record_prunable (prstate ,
702- HeapTupleHeaderGetUpdateXid (htup ));
703- goto process_chain ;
704-
705692 case HEAPTUPLE_LIVE :
706693 case HEAPTUPLE_INSERT_IN_PROGRESS :
707-
708- /*
709- * If we wanted to optimize for aborts, we might consider
710- * marking the page prunable when we see INSERT_IN_PROGRESS.
711- * But we don't. See related decisions about when to mark the
712- * page prunable in heapam.c.
713- */
714694 goto process_chain ;
715695
716696 default :
@@ -757,8 +737,15 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
757737 * No DEAD tuple was found, so the chain is entirely composed of
758738 * normal, unchanged tuples. Leave it alone.
759739 */
760- for (int i = 0 ; i < nchain ; i ++ )
761- heap_prune_record_unchanged (prstate , chainitems [i ]);
740+ int i = 0 ;
741+
742+ if (ItemIdIsRedirected (rootlp ))
743+ {
744+ heap_prune_record_unchanged_lp_redirect (prstate , rootoffnum );
745+ i ++ ;
746+ }
747+ for (; i < nchain ; i ++ )
748+ heap_prune_record_unchanged_lp_normal (page , htsv , prstate , chainitems [i ]);
762749 }
763750 else if (ndeadchain == nchain )
764751 {
@@ -784,7 +771,7 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
784771
785772 /* the rest of tuples in the chain are normal, unchanged tuples */
786773 for (int i = ndeadchain ; i < nchain ; i ++ )
787- heap_prune_record_unchanged ( prstate , chainitems [i ]);
774+ heap_prune_record_unchanged_lp_normal ( page , htsv , prstate , chainitems [i ]);
788775 }
789776}
790777
@@ -894,9 +881,81 @@ heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum, bool was_norm
894881 prstate -> ndeleted ++ ;
895882}
896883
897- /* Record a line pointer that is left unchanged */
884+ /*
885+ * Record an unused line pointer that is left unchanged.
886+ */
887+ static void
888+ heap_prune_record_unchanged_lp_unused (Page page , PruneState * prstate , OffsetNumber offnum )
889+ {
890+ Assert (!prstate -> processed [offnum ]);
891+ prstate -> processed [offnum ] = true;
892+ }
893+
894+ /*
895+ * Record LP_NORMAL line pointer that is left unchanged.
896+ */
897+ static void
898+ heap_prune_record_unchanged_lp_normal (Page page , int8 * htsv , PruneState * prstate , OffsetNumber offnum )
899+ {
900+ HeapTupleHeader htup ;
901+
902+ Assert (!prstate -> processed [offnum ]);
903+ prstate -> processed [offnum ] = true;
904+
905+ switch (htsv [offnum ])
906+ {
907+ case HEAPTUPLE_LIVE :
908+ case HEAPTUPLE_INSERT_IN_PROGRESS :
909+
910+ /*
911+ * If we wanted to optimize for aborts, we might consider marking
912+ * the page prunable when we see INSERT_IN_PROGRESS. But we
913+ * don't. See related decisions about when to mark the page
914+ * prunable in heapam.c.
915+ */
916+ break ;
917+
918+ case HEAPTUPLE_RECENTLY_DEAD :
919+ case HEAPTUPLE_DELETE_IN_PROGRESS :
920+
921+ htup = (HeapTupleHeader ) PageGetItem (page , PageGetItemId (page , offnum ));
922+
923+ /*
924+ * This tuple may soon become DEAD. Update the hint field so that
925+ * the page is reconsidered for pruning in future.
926+ */
927+ heap_prune_record_prunable (prstate ,
928+ HeapTupleHeaderGetUpdateXid (htup ));
929+ break ;
930+
931+
932+ default :
933+
934+ /*
935+ * DEAD tuples should've been passed to heap_prune_record_dead()
936+ * or heap_prune_record_unused() instead.
937+ */
938+ elog (ERROR , "unexpected HeapTupleSatisfiesVacuum result %d" , htsv [offnum ]);
939+ break ;
940+ }
941+ }
942+
943+
944+ /*
945+ * Record line pointer that was already LP_DEAD and is left unchanged.
946+ */
947+ static void
948+ heap_prune_record_unchanged_lp_dead (Page page , PruneState * prstate , OffsetNumber offnum )
949+ {
950+ Assert (!prstate -> processed [offnum ]);
951+ prstate -> processed [offnum ] = true;
952+ }
953+
954+ /*
955+ * Record LP_REDIRECT that is left unchanged.
956+ */
898957static void
899- heap_prune_record_unchanged (PruneState * prstate , OffsetNumber offnum )
958+ heap_prune_record_unchanged_lp_redirect (PruneState * prstate , OffsetNumber offnum )
900959{
901960 Assert (!prstate -> processed [offnum ]);
902961 prstate -> processed [offnum ] = true;
0 commit comments