#include "utils/rel.h"
 #include "utils/snapmgr.h"
 
+#define UINT32_ACCESS_ONCE(var)                 ((uint32)(*((volatile uint32 *)&(var))))
 
 /* Our shared memory area */
 typedef struct ProcArrayStruct
 static void
 ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
 {
-       volatile PROC_HDR *procglobal = ProcGlobal;
+       PROC_HDR   *procglobal = ProcGlobal;
        uint32          nextidx;
        uint32          wakeidx;
 
        for (i = 0; i < arrayP->numProcs; i++)
        {
                int                     pgprocno = arrayP->pgprocnos[i];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
                TransactionId pxid;
+               int                     pxids;
 
                /* Ignore my own proc --- dealt with it above */
                if (proc == MyProc)
                        continue;
 
                /* Fetch xid just once - see GetNewTransactionId */
-               pxid = pgxact->xid;
+               pxid = UINT32_ACCESS_ONCE(pgxact->xid);
 
                if (!TransactionIdIsValid(pxid))
                        continue;
                /*
                 * Step 2: check the cached child-Xids arrays
                 */
-               for (j = pgxact->nxids - 1; j >= 0; j--)
+               pxids = pgxact->nxids;
+               pg_read_barrier();              /* pairs with barrier in GetNewTransactionId() */
+               for (j = pxids - 1; j >= 0; j--)
                {
                        /* Fetch xid just once - see GetNewTransactionId */
-                       TransactionId cxid = proc->subxids.xids[j];
+                       TransactionId cxid = UINT32_ACCESS_ONCE(proc->subxids.xids[j]);
 
                        if (TransactionIdEquals(cxid, xid))
                        {
        for (i = 0; i < arrayP->numProcs; i++)
        {
                int                     pgprocno = arrayP->pgprocnos[i];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
                TransactionId pxid;
 
                /* Fetch xid just once - see GetNewTransactionId */
-               pxid = pgxact->xid;
+               pxid = UINT32_ACCESS_ONCE(pgxact->xid);
 
                if (!TransactionIdIsValid(pxid))
                        continue;
        int                     index;
        bool            allDbs;
 
-       volatile TransactionId replication_slot_xmin = InvalidTransactionId;
-       volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
+       TransactionId replication_slot_xmin = InvalidTransactionId;
+       TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
 
        /*
         * If we're not computing a relation specific limit, or if a shared
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
 
                if (pgxact->vacuumFlags & (flags & PROCARRAY_PROC_FLAGS_MASK))
                        continue;
                        proc->databaseId == 0)  /* always include WalSender */
                {
                        /* Fetch xid just once - see GetNewTransactionId */
-                       TransactionId xid = pgxact->xid;
+                       TransactionId xid = UINT32_ACCESS_ONCE(pgxact->xid);
 
                        /* First consider the transaction's own Xid, if any */
                        if (TransactionIdIsNormal(xid) &&
                         * have an Xmin but not (yet) an Xid; conversely, if it has an
                         * Xid, that could determine some not-yet-set Xmin.
                         */
-                       xid = pgxact->xmin; /* Fetch just once */
+                       xid = UINT32_ACCESS_ONCE(pgxact->xmin);
                        if (TransactionIdIsNormal(xid) &&
                                TransactionIdPrecedes(xid, result))
                                result = xid;
                }
        }
 
-       /* fetch into volatile var while ProcArrayLock is held */
+       /*
+        * Fetch into local variable while ProcArrayLock is held - the
+        * LWLockRelease below is a barrier, ensuring this happens inside the
+        * lock.
+        */
        replication_slot_xmin = procArray->replication_slot_xmin;
        replication_slot_catalog_xmin = procArray->replication_slot_catalog_xmin;
 
        int                     count = 0;
        int                     subcount = 0;
        bool            suboverflowed = false;
-       volatile TransactionId replication_slot_xmin = InvalidTransactionId;
-       volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
+       TransactionId replication_slot_xmin = InvalidTransactionId;
+       TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
 
        Assert(snapshot != NULL);
 
                for (index = 0; index < numProcs; index++)
                {
                        int                     pgprocno = pgprocnos[index];
-                       volatile PGXACT *pgxact = &allPgXact[pgprocno];
+                       PGXACT     *pgxact = &allPgXact[pgprocno];
                        TransactionId xid;
 
                        /*
                                continue;
 
                        /* Update globalxmin to be the smallest valid xmin */
-                       xid = pgxact->xmin; /* fetch just once */
+                       xid = UINT32_ACCESS_ONCE(pgxact->xmin);
                        if (TransactionIdIsNormal(xid) &&
                                NormalTransactionIdPrecedes(xid, globalxmin))
                                globalxmin = xid;
 
                        /* Fetch xid just once - see GetNewTransactionId */
-                       xid = pgxact->xid;
+                       xid = UINT32_ACCESS_ONCE(pgxact->xid);
 
                        /*
                         * If the transaction has no XID assigned, we can skip it; it
 
                                        if (nxids > 0)
                                        {
-                                               volatile PGPROC *proc = &allProcs[pgprocno];
+                                               PGPROC     *proc = &allProcs[pgprocno];
+
+                                               pg_read_barrier();      /* pairs with GetNewTransactionId */
 
                                                memcpy(snapshot->subxip + subcount,
                                                           (void *) proc->subxids.xids,
        }
 
 
-       /* fetch into volatile var while ProcArrayLock is held */
+       /*
+        * Fetch into local variable while ProcArrayLock is held - the
+        * LWLockRelease below is a barrier, ensuring this happens inside the
+        * lock.
+        */
        replication_slot_xmin = procArray->replication_slot_xmin;
        replication_slot_catalog_xmin = procArray->replication_slot_catalog_xmin;
 
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
                TransactionId xid;
 
                /* Ignore procs running LAZY VACUUM */
                /*
                 * Likewise, let's just make real sure its xmin does cover us.
                 */
-               xid = pgxact->xmin;             /* fetch just once */
+               xid = UINT32_ACCESS_ONCE(pgxact->xmin);
                if (!TransactionIdIsNormal(xid) ||
                        !TransactionIdPrecedesOrEquals(xid, xmin))
                        continue;
 {
        bool            result = false;
        TransactionId xid;
-       volatile PGXACT *pgxact;
+       PGXACT     *pgxact;
 
        Assert(TransactionIdIsNormal(xmin));
        Assert(proc != NULL);
         * can't go backwards.  Also, make sure it's running in the same database,
         * so that the per-database xmin cannot go backwards.
         */
-       xid = pgxact->xmin;                     /* fetch just once */
+       xid = UINT32_ACCESS_ONCE(pgxact->xmin);
        if (proc->databaseId == MyDatabaseId &&
                TransactionIdIsNormal(xid) &&
                TransactionIdPrecedesOrEquals(xid, xmin))
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
                TransactionId xid;
 
                /* Fetch xid just once - see GetNewTransactionId */
-               xid = pgxact->xid;
+               xid = UINT32_ACCESS_ONCE(pgxact->xid);
 
                /*
                 * We don't need to store transactions that don't have a TransactionId
                for (index = 0; index < arrayP->numProcs; index++)
                {
                        int                     pgprocno = arrayP->pgprocnos[index];
-                       volatile PGPROC *proc = &allProcs[pgprocno];
-                       volatile PGXACT *pgxact = &allPgXact[pgprocno];
+                       PGPROC     *proc = &allProcs[pgprocno];
+                       PGXACT     *pgxact = &allPgXact[pgprocno];
                        int                     nxids;
 
                        /*
                        nxids = pgxact->nxids;
                        if (nxids > 0)
                        {
+                               /* barrier not really required, as XidGenLock is held, but ... */
+                               pg_read_barrier();      /* pairs with GetNewTransactionId */
+
                                memcpy(&xids[count], (void *) proc->subxids.xids,
                                           nxids * sizeof(TransactionId));
                                count += nxids;
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
                TransactionId xid;
 
                /* Fetch xid just once - see GetNewTransactionId */
-               xid = pgxact->xid;
+               xid = UINT32_ACCESS_ONCE(pgxact->xid);
 
                if (!TransactionIdIsNormal(xid))
                        continue;
                for (index = 0; index < arrayP->numProcs; index++)
                {
                        int                     pgprocno = arrayP->pgprocnos[index];
-                       volatile PGXACT *pgxact = &allPgXact[pgprocno];
+                       PGXACT     *pgxact = &allPgXact[pgprocno];
                        TransactionId xid;
 
                        /* Fetch xid just once - see GetNewTransactionId */
-                       xid = pgxact->xid;
+                       xid = UINT32_ACCESS_ONCE(pgxact->xid);
 
                        if (!TransactionIdIsNormal(xid))
                                continue;
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
 
                if (pgxact->delayChkpt)
                {
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
                VirtualTransactionId vxid;
 
                GET_VXID_FROM_PGPROC(vxid, *proc);
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
 
                if (pgxact->xid == xid)
                {
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
 
                if (proc == MyProc)
                        continue;
                if (allDbs || proc->databaseId == MyDatabaseId)
                {
                        /* Fetch xmin just once - might change on us */
-                       TransactionId pxmin = pgxact->xmin;
+                       TransactionId pxmin = UINT32_ACCESS_ONCE(pgxact->xmin);
 
                        if (excludeXmin0 && !TransactionIdIsValid(pxmin))
                                continue;
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
 
                /* Exclude prepared transactions */
                if (proc->pid == 0)
                        proc->databaseId == dbOid)
                {
                        /* Fetch xmin just once - can't change on us, but good coding */
-                       TransactionId pxmin = pgxact->xmin;
+                       TransactionId pxmin = UINT32_ACCESS_ONCE(pgxact->xmin);
 
                        /*
                         * We ignore an invalid pxmin because this means that backend has
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
                VirtualTransactionId procvxid;
 
                GET_VXID_FROM_PGPROC(procvxid, *proc);
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
-               volatile PGXACT *pgxact = &allPgXact[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
+               PGXACT     *pgxact = &allPgXact[pgprocno];
 
                /*
                 * Since we're not holding a lock, need to be prepared to deal with
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
 
                if (proc->pid == 0)
                        continue;                       /* do not count prepared xacts */
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
 
                if (proc->pid == 0)
                        continue;                       /* do not count prepared xacts */
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
 
                if (databaseid == InvalidOid || proc->databaseId == databaseid)
                {
        for (index = 0; index < arrayP->numProcs; index++)
        {
                int                     pgprocno = arrayP->pgprocnos[index];
-               volatile PGPROC *proc = &allProcs[pgprocno];
+               PGPROC     *proc = &allProcs[pgprocno];
 
                if (proc->pid == 0)
                        continue;                       /* do not count prepared xacts */
                for (index = 0; index < arrayP->numProcs; index++)
                {
                        int                     pgprocno = arrayP->pgprocnos[index];
-                       volatile PGPROC *proc = &allProcs[pgprocno];
-                       volatile PGXACT *pgxact = &allPgXact[pgprocno];
+                       PGPROC     *proc = &allProcs[pgprocno];
+                       PGXACT     *pgxact = &allPgXact[pgprocno];
 
                        if (proc->databaseId != databaseId)
                                continue;
 #define XidCacheRemove(i) \
        do { \
                MyProc->subxids.xids[i] = MyProc->subxids.xids[MyPgXact->nxids - 1]; \
+               pg_write_barrier(); \
                MyPgXact->nxids--; \
        } while (0)
 
         * possible this could be relaxed since we know this routine is only used
         * to abort subtransactions, but pending closer analysis we'd best be
         * conservative.
+        *
+        * Note that we do not have to be careful about memory ordering of our own
+        * reads wrt. GetNewTransactionId() here - only this process can modify
+        * relevant fields of MyProc/MyPgXact.  But we do have to be careful about
+        * our own writes being well ordered.
         */
        LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
 
 static void
 KnownAssignedXidsCompress(bool force)
 {
-       /* use volatile pointer to prevent code rearrangement */
-       volatile ProcArrayStruct *pArray = procArray;
+       ProcArrayStruct *pArray = procArray;
        int                     head,
                                tail;
        int                     compress_index;
 KnownAssignedXidsAdd(TransactionId from_xid, TransactionId to_xid,
                                         bool exclusive_lock)
 {
-       /* use volatile pointer to prevent code rearrangement */
-       volatile ProcArrayStruct *pArray = procArray;
+       ProcArrayStruct *pArray = procArray;
        TransactionId next_xid;
        int                     head,
                                tail;
 static bool
 KnownAssignedXidsSearch(TransactionId xid, bool remove)
 {
-       /* use volatile pointer to prevent code rearrangement */
-       volatile ProcArrayStruct *pArray = procArray;
+       ProcArrayStruct *pArray = procArray;
        int                     first,
                                last;
        int                     head;
 static void
 KnownAssignedXidsRemovePreceding(TransactionId removeXid)
 {
-       /* use volatile pointer to prevent code rearrangement */
-       volatile ProcArrayStruct *pArray = procArray;
+       ProcArrayStruct *pArray = procArray;
        int                     count = 0;
        int                     head,
                                tail,
 static void
 KnownAssignedXidsDisplay(int trace_level)
 {
-       /* use volatile pointer to prevent code rearrangement */
-       volatile ProcArrayStruct *pArray = procArray;
+       ProcArrayStruct *pArray = procArray;
        StringInfoData buf;
        int                     head,
                                tail,
 static void
 KnownAssignedXidsReset(void)
 {
-       /* use volatile pointer to prevent code rearrangement */
-       volatile ProcArrayStruct *pArray = procArray;
+       ProcArrayStruct *pArray = procArray;
 
        LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);