#include "storage/bufmgr.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "storage/procarray.h"
 #include "utils/snapmgr.h"
 
 
        SpGistState spgstate;           /* for SPGiST operations that need one */
        spgVacPendingItem *pendingList;         /* TIDs we need to (re)visit */
        TransactionId myXmin;           /* for detecting newly-added redirects */
-       TransactionId OldestXmin;       /* for deciding a redirect is obsolete */
        BlockNumber lastFilledBlock;    /* last non-deletable block */
 } spgBulkDeleteState;
 
  * Unlike the routines above, this works on both leaf and inner pages.
  */
 static void
-vacuumRedirectAndPlaceholder(Relation index, Buffer buffer,
-                                                        TransactionId OldestXmin)
+vacuumRedirectAndPlaceholder(Relation index, Buffer buffer)
 {
        Page            page = BufferGetPage(buffer);
        SpGistPageOpaque opaque = SpGistPageGetOpaque(page);
        xlrec.node = index->rd_node;
        xlrec.blkno = BufferGetBlockNumber(buffer);
        xlrec.nToPlaceholder = 0;
+       xlrec.newestRedirectXid = InvalidTransactionId;
 
        START_CRIT_SECTION();
 
                dt = (SpGistDeadTuple) PageGetItem(page, PageGetItemId(page, i));
 
                if (dt->tupstate == SPGIST_REDIRECT &&
-                       TransactionIdPrecedes(dt->xid, OldestXmin))
+                       TransactionIdPrecedes(dt->xid, RecentGlobalXmin))
                {
                        dt->tupstate = SPGIST_PLACEHOLDER;
                        Assert(opaque->nRedirection > 0);
                        opaque->nRedirection--;
                        opaque->nPlaceholder++;
 
+                       /* remember newest XID among the removed redirects */
+                       if (!TransactionIdIsValid(xlrec.newestRedirectXid) ||
+                               TransactionIdPrecedes(xlrec.newestRedirectXid, dt->xid))
+                               xlrec.newestRedirectXid = dt->xid;
+
                        ItemPointerSetInvalid(&dt->pointer);
 
                        itemToPlaceholder[xlrec.nToPlaceholder] = i;
                else
                {
                        vacuumLeafPage(bds, index, buffer, false);
-                       vacuumRedirectAndPlaceholder(index, buffer, bds->OldestXmin);
+                       vacuumRedirectAndPlaceholder(index, buffer);
                }
        }
        else
        {
                /* inner page */
-               vacuumRedirectAndPlaceholder(index, buffer, bds->OldestXmin);
+               vacuumRedirectAndPlaceholder(index, buffer);
        }
 
        /*
                        /* deal with any deletable tuples */
                        vacuumLeafPage(bds, index, buffer, true);
                        /* might as well do this while we are here */
-                       vacuumRedirectAndPlaceholder(index, buffer, bds->OldestXmin);
+                       vacuumRedirectAndPlaceholder(index, buffer);
 
                        SpGistSetLastUsedPage(index, buffer);
 
        initSpGistState(&bds->spgstate, index);
        bds->pendingList = NULL;
        bds->myXmin = GetActiveSnapshot()->xmin;
-       bds->OldestXmin = GetOldestXmin(true, false);
        bds->lastFilledBlock = SPGIST_LAST_FIXED_BLKNO;
 
        /*
 
 #include "postgres.h"
 
 #include "access/spgist_private.h"
+#include "access/transam.h"
 #include "access/xlogutils.h"
-#include "storage/bufmgr.h"
+#include "storage/standby.h"
 #include "utils/memutils.h"
 
 
        ptr += sizeof(spgxlogVacuumRedirect);
        itemToPlaceholder = (OffsetNumber *) ptr;
 
+       /*
+        * If any redirection tuples are being removed, make sure there are no
+        * live Hot Standby transactions that might need to see them.  This code
+        * behaves similarly to btree's XLOG_BTREE_REUSE_PAGE case.
+        */
+       if (InHotStandby && TransactionIdIsValid(xldata->newestRedirectXid))
+               ResolveRecoveryConflictWithSnapshot(xldata->newestRedirectXid,
+                                                                                       xldata->node);
+
        if (!(record->xl_info & XLR_BKP_BLOCK_1))
        {
                buffer = XLogReadBuffer(xldata->node, xldata->blkno, false);
                        break;
                case XLOG_SPGIST_VACUUM_REDIRECT:
                        out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
-                       appendStringInfo(buf, "vacuum redirect tuples on page %u",
-                                                        ((spgxlogVacuumRedirect *) rec)->blkno);
+                       appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
+                                                        ((spgxlogVacuumRedirect *) rec)->blkno,
+                                                        ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
                        break;
                default:
                        appendStringInfo(buf, "unknown spgist op code %u", info);