Use dlists instead of SHM_QUEUE for predicate locking
authorAndres Freund <andres@anarazel.de>
Fri, 20 Jan 2023 02:50:01 +0000 (18:50 -0800)
committerAndres Freund <andres@anarazel.de>
Fri, 20 Jan 2023 02:55:51 +0000 (18:55 -0800)
Part of a series to remove SHM_QUEUE. ilist.h style lists are more widely used
and have an easier to use interface.

Reviewed-by: Thomas Munro <thomas.munro@gmail.com> (in an older version)
Discussion: https://postgr.es/m/20221120055930.t6kl3tyivzhlrzu2@awork3.anarazel.de
Discussion: https://postgr.es/m/20200211042229.msv23badgqljrdg2@alap3.anarazel.de

src/backend/storage/lmgr/predicate.c
src/include/storage/predicate_internals.h

index 327adef5d3ca02ea11c9a2e766076daaebeca463..11decb74b2af5a6a0d4054c1ed395005b3d9d624 100644 (file)
 #define NPREDICATELOCKTARGETENTS() \
    mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
 
-#define SxactIsOnFinishedList(sxact) (!SHMQueueIsDetached(&((sxact)->finishedLink)))
+#define SxactIsOnFinishedList(sxact) (!dlist_node_is_detached(&(sxact)->finishedLink))
 
 /*
  * Note that a sxact is marked "prepared" once it has passed
@@ -392,7 +392,7 @@ static RWConflictPoolHeader RWConflictPool;
 static HTAB *SerializableXidHash;
 static HTAB *PredicateLockTargetHash;
 static HTAB *PredicateLockHash;
-static SHM_QUEUE *FinishedSerializableTransactions;
+static dlist_head *FinishedSerializableTransactions;
 
 /*
  * Tag for a dummy entry in PredicateLockTargetHash. By temporarily removing
@@ -430,8 +430,6 @@ static SERIALIZABLEXACT *SavedSerializableXact = InvalidSerializableXact;
 
 static SERIALIZABLEXACT *CreatePredXact(void);
 static void ReleasePredXact(SERIALIZABLEXACT *sxact);
-static SERIALIZABLEXACT *FirstPredXact(void);
-static SERIALIZABLEXACT *NextPredXact(SERIALIZABLEXACT *sxact);
 
 static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer);
 static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer);
@@ -579,69 +577,24 @@ SerializationNeededForWrite(Relation relation)
 static SERIALIZABLEXACT *
 CreatePredXact(void)
 {
-   PredXactListElement ptle;
+   SERIALIZABLEXACT *sxact;
 
-   ptle = (PredXactListElement)
-       SHMQueueNext(&PredXact->availableList,
-                    &PredXact->availableList,
-                    offsetof(PredXactListElementData, link));
-   if (!ptle)
+   if (dlist_is_empty(&PredXact->availableList))
        return NULL;
 
-   SHMQueueDelete(&ptle->link);
-   SHMQueueInsertBefore(&PredXact->activeList, &ptle->link);
-   return &ptle->sxact;
+   sxact = dlist_container(SERIALIZABLEXACT, xactLink,
+                           dlist_pop_head_node(&PredXact->availableList));
+   dlist_push_tail(&PredXact->activeList, &sxact->xactLink);
+   return sxact;
 }
 
 static void
 ReleasePredXact(SERIALIZABLEXACT *sxact)
 {
-   PredXactListElement ptle;
-
    Assert(ShmemAddrIsValid(sxact));
 
-   ptle = (PredXactListElement)
-       (((char *) sxact)
-        - offsetof(PredXactListElementData, sxact)
-        + offsetof(PredXactListElementData, link));
-   SHMQueueDelete(&ptle->link);
-   SHMQueueInsertBefore(&PredXact->availableList, &ptle->link);
-}
-
-static SERIALIZABLEXACT *
-FirstPredXact(void)
-{
-   PredXactListElement ptle;
-
-   ptle = (PredXactListElement)
-       SHMQueueNext(&PredXact->activeList,
-                    &PredXact->activeList,
-                    offsetof(PredXactListElementData, link));
-   if (!ptle)
-       return NULL;
-
-   return &ptle->sxact;
-}
-
-static SERIALIZABLEXACT *
-NextPredXact(SERIALIZABLEXACT *sxact)
-{
-   PredXactListElement ptle;
-
-   Assert(ShmemAddrIsValid(sxact));
-
-   ptle = (PredXactListElement)
-       (((char *) sxact)
-        - offsetof(PredXactListElementData, sxact)
-        + offsetof(PredXactListElementData, link));
-   ptle = (PredXactListElement)
-       SHMQueueNext(&PredXact->activeList,
-                    &ptle->link,
-                    offsetof(PredXactListElementData, link));
-   if (!ptle)
-       return NULL;
-
-   return &ptle->sxact;
+   dlist_delete(&sxact->xactLink);
+   dlist_push_tail(&PredXact->availableList, &sxact->xactLink);
 }
 
 /*------------------------------------------------------------------------*/
@@ -652,30 +605,30 @@ NextPredXact(SERIALIZABLEXACT *sxact)
 static bool
 RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
 {
-   RWConflict  conflict;
+   dlist_iter  iter;
 
    Assert(reader != writer);
 
    /* Check the ends of the purported conflict first. */
    if (SxactIsDoomed(reader)
        || SxactIsDoomed(writer)
-       || SHMQueueEmpty(&reader->outConflicts)
-       || SHMQueueEmpty(&writer->inConflicts))
+       || dlist_is_empty(&reader->outConflicts)
+       || dlist_is_empty(&writer->inConflicts))
        return false;
 
-   /* A conflict is possible; walk the list to find out. */
-   conflict = (RWConflict)
-       SHMQueueNext(&reader->outConflicts,
-                    &reader->outConflicts,
-                    offsetof(RWConflictData, outLink));
-   while (conflict)
+   /*
+    * A conflict is possible; walk the list to find out.
+    *
+    * The unconstify is needed as we have no const version of
+    * dlist_foreach().
+    */
+   dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
    {
+       RWConflict  conflict =
+       dlist_container(RWConflictData, outLink, iter.cur);
+
        if (conflict->sxactIn == writer)
            return true;
-       conflict = (RWConflict)
-           SHMQueueNext(&reader->outConflicts,
-                        &conflict->outLink,
-                        offsetof(RWConflictData, outLink));
    }
 
    /* No conflict found. */
@@ -690,22 +643,19 @@ SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
    Assert(reader != writer);
    Assert(!RWConflictExists(reader, writer));
 
-   conflict = (RWConflict)
-       SHMQueueNext(&RWConflictPool->availableList,
-                    &RWConflictPool->availableList,
-                    offsetof(RWConflictData, outLink));
-   if (!conflict)
+   if (dlist_is_empty(&RWConflictPool->availableList))
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("not enough elements in RWConflictPool to record a read/write conflict"),
                 errhint("You might need to run fewer transactions at a time or increase max_connections.")));
 
-   SHMQueueDelete(&conflict->outLink);
+   conflict = dlist_head_element(RWConflictData, outLink, &RWConflictPool->availableList);
+   dlist_delete(&conflict->outLink);
 
    conflict->sxactOut = reader;
    conflict->sxactIn = writer;
-   SHMQueueInsertBefore(&reader->outConflicts, &conflict->outLink);
-   SHMQueueInsertBefore(&writer->inConflicts, &conflict->inLink);
+   dlist_push_tail(&reader->outConflicts, &conflict->outLink);
+   dlist_push_tail(&writer->inConflicts, &conflict->inLink);
 }
 
 static void
@@ -718,39 +668,33 @@ SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact,
    Assert(SxactIsReadOnly(roXact));
    Assert(!SxactIsReadOnly(activeXact));
 
-   conflict = (RWConflict)
-       SHMQueueNext(&RWConflictPool->availableList,
-                    &RWConflictPool->availableList,
-                    offsetof(RWConflictData, outLink));
-   if (!conflict)
+   if (dlist_is_empty(&RWConflictPool->availableList))
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("not enough elements in RWConflictPool to record a potential read/write conflict"),
                 errhint("You might need to run fewer transactions at a time or increase max_connections.")));
 
-   SHMQueueDelete(&conflict->outLink);
+   conflict = dlist_head_element(RWConflictData, outLink, &RWConflictPool->availableList);
+   dlist_delete(&conflict->outLink);
 
    conflict->sxactOut = activeXact;
    conflict->sxactIn = roXact;
-   SHMQueueInsertBefore(&activeXact->possibleUnsafeConflicts,
-                        &conflict->outLink);
-   SHMQueueInsertBefore(&roXact->possibleUnsafeConflicts,
-                        &conflict->inLink);
+   dlist_push_tail(&activeXact->possibleUnsafeConflicts, &conflict->outLink);
+   dlist_push_tail(&roXact->possibleUnsafeConflicts, &conflict->inLink);
 }
 
 static void
 ReleaseRWConflict(RWConflict conflict)
 {
-   SHMQueueDelete(&conflict->inLink);
-   SHMQueueDelete(&conflict->outLink);
-   SHMQueueInsertBefore(&RWConflictPool->availableList, &conflict->outLink);
+   dlist_delete(&conflict->inLink);
+   dlist_delete(&conflict->outLink);
+   dlist_push_tail(&RWConflictPool->availableList, &conflict->outLink);
 }
 
 static void
 FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
 {
-   RWConflict  conflict,
-               nextConflict;
+   dlist_mutable_iter iter;
 
    Assert(SxactIsReadOnly(sxact));
    Assert(!SxactIsROSafe(sxact));
@@ -761,23 +705,15 @@ FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
     * We know this isn't a safe snapshot, so we can stop looking for other
     * potential conflicts.
     */
-   conflict = (RWConflict)
-       SHMQueueNext(&sxact->possibleUnsafeConflicts,
-                    &sxact->possibleUnsafeConflicts,
-                    offsetof(RWConflictData, inLink));
-   while (conflict)
+   dlist_foreach_modify(iter, &sxact->possibleUnsafeConflicts)
    {
-       nextConflict = (RWConflict)
-           SHMQueueNext(&sxact->possibleUnsafeConflicts,
-                        &conflict->inLink,
-                        offsetof(RWConflictData, inLink));
+       RWConflict  conflict =
+       dlist_container(RWConflictData, inLink, iter.cur);
 
        Assert(!SxactIsReadOnly(conflict->sxactOut));
        Assert(sxact == conflict->sxactIn);
 
        ReleaseRWConflict(conflict);
-
-       conflict = nextConflict;
    }
 }
 
@@ -1242,8 +1178,8 @@ InitPredicateLocks(void)
    {
        int         i;
 
-       SHMQueueInit(&PredXact->availableList);
-       SHMQueueInit(&PredXact->activeList);
+       dlist_init(&PredXact->availableList);
+       dlist_init(&PredXact->activeList);
        PredXact->SxactGlobalXmin = InvalidTransactionId;
        PredXact->SxactGlobalXminCount = 0;
        PredXact->WritableSxactCount = 0;
@@ -1251,27 +1187,26 @@ InitPredicateLocks(void)
        PredXact->CanPartialClearThrough = 0;
        PredXact->HavePartialClearedThrough = 0;
        requestSize = mul_size((Size) max_table_size,
-                              PredXactListElementDataSize);
+                              sizeof(SERIALIZABLEXACT));
        PredXact->element = ShmemAlloc(requestSize);
        /* Add all elements to available list, clean. */
        memset(PredXact->element, 0, requestSize);
        for (i = 0; i < max_table_size; i++)
        {
-           LWLockInitialize(&PredXact->element[i].sxact.perXactPredicateListLock,
+           LWLockInitialize(&PredXact->element[i].perXactPredicateListLock,
                             LWTRANCHE_PER_XACT_PREDICATE_LIST);
-           SHMQueueInsertBefore(&(PredXact->availableList),
-                                &(PredXact->element[i].link));
+           dlist_push_tail(&PredXact->availableList, &PredXact->element[i].xactLink);
        }
        PredXact->OldCommittedSxact = CreatePredXact();
        SetInvalidVirtualTransactionId(PredXact->OldCommittedSxact->vxid);
        PredXact->OldCommittedSxact->prepareSeqNo = 0;
        PredXact->OldCommittedSxact->commitSeqNo = 0;
        PredXact->OldCommittedSxact->SeqNo.lastCommitBeforeSnapshot = 0;
-       SHMQueueInit(&PredXact->OldCommittedSxact->outConflicts);
-       SHMQueueInit(&PredXact->OldCommittedSxact->inConflicts);
-       SHMQueueInit(&PredXact->OldCommittedSxact->predicateLocks);
-       SHMQueueInit(&PredXact->OldCommittedSxact->finishedLink);
-       SHMQueueInit(&PredXact->OldCommittedSxact->possibleUnsafeConflicts);
+       dlist_init(&PredXact->OldCommittedSxact->outConflicts);
+       dlist_init(&PredXact->OldCommittedSxact->inConflicts);
+       dlist_init(&PredXact->OldCommittedSxact->predicateLocks);
+       dlist_node_init(&PredXact->OldCommittedSxact->finishedLink);
+       dlist_init(&PredXact->OldCommittedSxact->possibleUnsafeConflicts);
        PredXact->OldCommittedSxact->topXid = InvalidTransactionId;
        PredXact->OldCommittedSxact->finishedBefore = InvalidTransactionId;
        PredXact->OldCommittedSxact->xmin = InvalidTransactionId;
@@ -1317,7 +1252,7 @@ InitPredicateLocks(void)
    {
        int         i;
 
-       SHMQueueInit(&RWConflictPool->availableList);
+       dlist_init(&RWConflictPool->availableList);
        requestSize = mul_size((Size) max_table_size,
                               RWConflictDataSize);
        RWConflictPool->element = ShmemAlloc(requestSize);
@@ -1325,8 +1260,8 @@ InitPredicateLocks(void)
        memset(RWConflictPool->element, 0, requestSize);
        for (i = 0; i < max_table_size; i++)
        {
-           SHMQueueInsertBefore(&(RWConflictPool->availableList),
-                                &(RWConflictPool->element[i].outLink));
+           dlist_push_tail(&RWConflictPool->availableList,
+                           &RWConflictPool->element[i].outLink);
        }
    }
 
@@ -1334,13 +1269,13 @@ InitPredicateLocks(void)
     * Create or attach to the header for the list of finished serializable
     * transactions.
     */
-   FinishedSerializableTransactions = (SHM_QUEUE *)
+   FinishedSerializableTransactions = (dlist_head *)
        ShmemInitStruct("FinishedSerializableTransactions",
-                       sizeof(SHM_QUEUE),
+                       sizeof(dlist_head),
                        &found);
    Assert(found == IsUnderPostmaster);
    if (!found)
-       SHMQueueInit(FinishedSerializableTransactions);
+       dlist_init(FinishedSerializableTransactions);
 
    /*
     * Initialize the SLRU storage for old committed serializable
@@ -1379,7 +1314,7 @@ PredicateLockShmemSize(void)
    max_table_size *= 10;
    size = add_size(size, PredXactListDataSize);
    size = add_size(size, mul_size((Size) max_table_size,
-                                  PredXactListElementDataSize));
+                                  sizeof(SERIALIZABLEXACT)));
 
    /* transaction xid table */
    size = add_size(size, hash_estimate_size(max_table_size,
@@ -1392,7 +1327,7 @@ PredicateLockShmemSize(void)
                                   RWConflictDataSize));
 
    /* Head for list of finished serializable transactions. */
-   size = add_size(size, sizeof(SHM_QUEUE));
+   size = add_size(size, sizeof(dlist_head));
 
    /* Shared memory structures for SLRU tracking of old committed xids. */
    size = add_size(size, sizeof(SerialControlData));
@@ -1515,7 +1450,7 @@ SummarizeOldestCommittedSxact(void)
     * that case, we have nothing to do here. The caller will find one of the
     * slots released by the other backend when it retries.
     */
-   if (SHMQueueEmpty(FinishedSerializableTransactions))
+   if (dlist_is_empty(FinishedSerializableTransactions))
    {
        LWLockRelease(SerializableFinishedListLock);
        return;
@@ -1525,11 +1460,9 @@ SummarizeOldestCommittedSxact(void)
     * Grab the first sxact off the finished list -- this will be the earliest
     * commit.  Remove it from the list.
     */
-   sxact = (SERIALIZABLEXACT *)
-       SHMQueueNext(FinishedSerializableTransactions,
-                    FinishedSerializableTransactions,
-                    offsetof(SERIALIZABLEXACT, finishedLink));
-   SHMQueueDelete(&(sxact->finishedLink));
+   sxact = dlist_head_element(SERIALIZABLEXACT, finishedLink,
+                              FinishedSerializableTransactions);
+   dlist_delete_thoroughly(&sxact->finishedLink);
 
    /* Add to SLRU summary information. */
    if (TransactionIdIsValid(sxact->topXid) && !SxactIsReadOnly(sxact))
@@ -1583,7 +1516,7 @@ GetSafeSnapshot(Snapshot origSnapshot)
         * them marked us as conflicted.
         */
        MySerializableXact->flags |= SXACT_FLAG_DEFERRABLE_WAITING;
-       while (!(SHMQueueEmpty(&MySerializableXact->possibleUnsafeConflicts) ||
+       while (!(dlist_is_empty(&MySerializableXact->possibleUnsafeConflicts) ||
                 SxactIsROUnsafe(MySerializableXact)))
        {
            LWLockRelease(SerializableXactHashLock);
@@ -1629,13 +1562,16 @@ int
 GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
 {
    int         num_written = 0;
-   SERIALIZABLEXACT *sxact;
+   dlist_iter  iter;
+   SERIALIZABLEXACT *sxact = NULL;
 
    LWLockAcquire(SerializableXactHashLock, LW_SHARED);
 
    /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
-   for (sxact = FirstPredXact(); sxact != NULL; sxact = NextPredXact(sxact))
+   dlist_foreach(iter, &PredXact->activeList)
    {
+       sxact = dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
+
        if (sxact->pid == blocked_pid)
            break;
    }
@@ -1643,21 +1579,13 @@ GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
    /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
    if (sxact != NULL && SxactIsDeferrableWaiting(sxact))
    {
-       RWConflict  possibleUnsafeConflict;
-
        /* Traverse the list of possible unsafe conflicts collecting PIDs. */
-       possibleUnsafeConflict = (RWConflict)
-           SHMQueueNext(&sxact->possibleUnsafeConflicts,
-                        &sxact->possibleUnsafeConflicts,
-                        offsetof(RWConflictData, inLink));
-
-       while (possibleUnsafeConflict != NULL && num_written < output_size)
+       dlist_foreach(iter, &sxact->possibleUnsafeConflicts)
        {
+           RWConflict  possibleUnsafeConflict =
+           dlist_container(RWConflictData, inLink, iter.cur);
+
            output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
-           possibleUnsafeConflict = (RWConflict)
-               SHMQueueNext(&sxact->possibleUnsafeConflicts,
-                            &possibleUnsafeConflict->inLink,
-                            offsetof(RWConflictData, inLink));
        }
    }
 
@@ -1870,19 +1798,21 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
    sxact->SeqNo.lastCommitBeforeSnapshot = PredXact->LastSxactCommitSeqNo;
    sxact->prepareSeqNo = InvalidSerCommitSeqNo;
    sxact->commitSeqNo = InvalidSerCommitSeqNo;
-   SHMQueueInit(&(sxact->outConflicts));
-   SHMQueueInit(&(sxact->inConflicts));
-   SHMQueueInit(&(sxact->possibleUnsafeConflicts));
+   dlist_init(&(sxact->outConflicts));
+   dlist_init(&(sxact->inConflicts));
+   dlist_init(&(sxact->possibleUnsafeConflicts));
    sxact->topXid = GetTopTransactionIdIfAny();
    sxact->finishedBefore = InvalidTransactionId;
    sxact->xmin = snapshot->xmin;
    sxact->pid = MyProcPid;
    sxact->pgprocno = MyProc->pgprocno;
-   SHMQueueInit(&(sxact->predicateLocks));
-   SHMQueueElemInit(&(sxact->finishedLink));
+   dlist_init(&sxact->predicateLocks);
+   dlist_node_init(&sxact->finishedLink);
    sxact->flags = 0;
    if (XactReadOnly)
    {
+       dlist_iter  iter;
+
        sxact->flags |= SXACT_FLAG_READ_ONLY;
 
        /*
@@ -1891,10 +1821,10 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
         * transactions then this snapshot can be deemed safe (and we can run
         * without tracking predicate locks).
         */
-       for (othersxact = FirstPredXact();
-            othersxact != NULL;
-            othersxact = NextPredXact(othersxact))
+       dlist_foreach(iter, &PredXact->activeList)
        {
+           othersxact = dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
+
            if (!SxactIsCommitted(othersxact)
                && !SxactIsDoomed(othersxact)
                && !SxactIsReadOnly(othersxact))
@@ -2171,7 +2101,7 @@ RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
    Assert(LWLockHeldByMe(SerializablePredicateListLock));
 
    /* Can't remove it until no locks at this target. */
-   if (!SHMQueueEmpty(&target->predicateLocks))
+   if (!dlist_is_empty(&target->predicateLocks))
        return;
 
    /* Actually remove the target. */
@@ -2199,28 +2129,20 @@ DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
 {
    SERIALIZABLEXACT *sxact;
    PREDICATELOCK *predlock;
+   dlist_mutable_iter iter;
 
    LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
    sxact = MySerializableXact;
    if (IsInParallelMode())
        LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
-   predlock = (PREDICATELOCK *)
-       SHMQueueNext(&(sxact->predicateLocks),
-                    &(sxact->predicateLocks),
-                    offsetof(PREDICATELOCK, xactLink));
-   while (predlock)
+
+   dlist_foreach_modify(iter, &sxact->predicateLocks)
    {
-       SHM_QUEUE  *predlocksxactlink;
-       PREDICATELOCK *nextpredlock;
        PREDICATELOCKTAG oldlocktag;
        PREDICATELOCKTARGET *oldtarget;
        PREDICATELOCKTARGETTAG oldtargettag;
 
-       predlocksxactlink = &(predlock->xactLink);
-       nextpredlock = (PREDICATELOCK *)
-           SHMQueueNext(&(sxact->predicateLocks),
-                        predlocksxactlink,
-                        offsetof(PREDICATELOCK, xactLink));
+       predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
 
        oldlocktag = predlock->tag;
        Assert(oldlocktag.myXact == sxact);
@@ -2238,8 +2160,8 @@ DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
 
            LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
-           SHMQueueDelete(predlocksxactlink);
-           SHMQueueDelete(&(predlock->targetLink));
+           dlist_delete(&predlock->xactLink);
+           dlist_delete(&predlock->targetLink);
            rmpredlock = hash_search_with_hash_value
                (PredicateLockHash,
                 &oldlocktag,
@@ -2254,8 +2176,6 @@ DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
 
            DecrementParentLocks(&oldtargettag);
        }
-
-       predlock = nextpredlock;
    }
    if (IsInParallelMode())
        LWLockRelease(&sxact->perXactPredicateListLock);
@@ -2472,7 +2392,7 @@ CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag,
                 errmsg("out of shared memory"),
                 errhint("You might need to increase max_pred_locks_per_transaction.")));
    if (!found)
-       SHMQueueInit(&(target->predicateLocks));
+       dlist_init(&target->predicateLocks);
 
    /* We've got the sxact and target, make sure they're joined. */
    locktag.myTarget = target;
@@ -2489,9 +2409,8 @@ CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag,
 
    if (!found)
    {
-       SHMQueueInsertBefore(&(target->predicateLocks), &(lock->targetLink));
-       SHMQueueInsertBefore(&(sxact->predicateLocks),
-                            &(lock->xactLink));
+       dlist_push_tail(&target->predicateLocks, &lock->targetLink);
+       dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
        lock->commitSeqNo = InvalidSerCommitSeqNo;
    }
 
@@ -2663,30 +2582,22 @@ PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot,
 static void
 DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash)
 {
-   PREDICATELOCK *predlock;
-   SHM_QUEUE  *predlocktargetlink;
-   PREDICATELOCK *nextpredlock;
-   bool        found;
+   dlist_mutable_iter iter;
 
    Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
                                LW_EXCLUSIVE));
    Assert(LWLockHeldByMe(PredicateLockHashPartitionLock(targettaghash)));
 
-   predlock = (PREDICATELOCK *)
-       SHMQueueNext(&(target->predicateLocks),
-                    &(target->predicateLocks),
-                    offsetof(PREDICATELOCK, targetLink));
    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
-   while (predlock)
+
+   dlist_foreach_modify(iter, &target->predicateLocks)
    {
-       predlocktargetlink = &(predlock->targetLink);
-       nextpredlock = (PREDICATELOCK *)
-           SHMQueueNext(&(target->predicateLocks),
-                        predlocktargetlink,
-                        offsetof(PREDICATELOCK, targetLink));
+       PREDICATELOCK *predlock =
+       dlist_container(PREDICATELOCK, targetLink, iter.cur);
+       bool        found;
 
-       SHMQueueDelete(&(predlock->xactLink));
-       SHMQueueDelete(&(predlock->targetLink));
+       dlist_delete(&(predlock->xactLink));
+       dlist_delete(&(predlock->targetLink));
 
        hash_search_with_hash_value
            (PredicateLockHash,
@@ -2695,8 +2606,6 @@ DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash)
                                                     targettaghash),
             HASH_REMOVE, &found);
        Assert(found);
-
-       predlock = nextpredlock;
    }
    LWLockRelease(SerializableXactHashLock);
 
@@ -2795,8 +2704,8 @@ TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
    if (oldtarget)
    {
        PREDICATELOCKTARGET *newtarget;
-       PREDICATELOCK *oldpredlock;
        PREDICATELOCKTAG newpredlocktag;
+       dlist_mutable_iter iter;
 
        newtarget = hash_search_with_hash_value(PredicateLockTargetHash,
                                                &newtargettag,
@@ -2812,7 +2721,7 @@ TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
 
        /* If we created a new entry, initialize it */
        if (!found)
-           SHMQueueInit(&(newtarget->predicateLocks));
+           dlist_init(&newtarget->predicateLocks);
 
        newpredlocktag.myTarget = newtarget;
 
@@ -2820,29 +2729,21 @@ TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
         * Loop through all the locks on the old target, replacing them with
         * locks on the new target.
         */
-       oldpredlock = (PREDICATELOCK *)
-           SHMQueueNext(&(oldtarget->predicateLocks),
-                        &(oldtarget->predicateLocks),
-                        offsetof(PREDICATELOCK, targetLink));
        LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
-       while (oldpredlock)
+
+       dlist_foreach_modify(iter, &oldtarget->predicateLocks)
        {
-           SHM_QUEUE  *predlocktargetlink;
-           PREDICATELOCK *nextpredlock;
+           PREDICATELOCK *oldpredlock =
+           dlist_container(PREDICATELOCK, targetLink, iter.cur);
            PREDICATELOCK *newpredlock;
            SerCommitSeqNo oldCommitSeqNo = oldpredlock->commitSeqNo;
 
-           predlocktargetlink = &(oldpredlock->targetLink);
-           nextpredlock = (PREDICATELOCK *)
-               SHMQueueNext(&(oldtarget->predicateLocks),
-                            predlocktargetlink,
-                            offsetof(PREDICATELOCK, targetLink));
            newpredlocktag.myXact = oldpredlock->tag.myXact;
 
            if (removeOld)
            {
-               SHMQueueDelete(&(oldpredlock->xactLink));
-               SHMQueueDelete(&(oldpredlock->targetLink));
+               dlist_delete(&(oldpredlock->xactLink));
+               dlist_delete(&(oldpredlock->targetLink));
 
                hash_search_with_hash_value
                    (PredicateLockHash,
@@ -2870,10 +2771,10 @@ TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
            }
            if (!found)
            {
-               SHMQueueInsertBefore(&(newtarget->predicateLocks),
-                                    &(newpredlock->targetLink));
-               SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
-                                    &(newpredlock->xactLink));
+               dlist_push_tail(&(newtarget->predicateLocks),
+                               &(newpredlock->targetLink));
+               dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
+                               &(newpredlock->xactLink));
                newpredlock->commitSeqNo = oldCommitSeqNo;
            }
            else
@@ -2885,14 +2786,12 @@ TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
            Assert(newpredlock->commitSeqNo != 0);
            Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
                   || (newpredlock->tag.myXact == OldCommittedSxact));
-
-           oldpredlock = nextpredlock;
        }
        LWLockRelease(SerializableXactHashLock);
 
        if (removeOld)
        {
-           Assert(SHMQueueEmpty(&oldtarget->predicateLocks));
+           Assert(dlist_is_empty(&oldtarget->predicateLocks));
            RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
        }
    }
@@ -3012,7 +2911,7 @@ DropAllPredicateLocksFromTable(Relation relation, bool transfer)
 
    while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
    {
-       PREDICATELOCK *oldpredlock;
+       dlist_mutable_iter iter;
 
        /*
         * Check whether this is a target which needs attention.
@@ -3047,29 +2946,21 @@ DropAllPredicateLocksFromTable(Relation relation, bool transfer)
                                                     heaptargettaghash,
                                                     HASH_ENTER, &found);
            if (!found)
-               SHMQueueInit(&heaptarget->predicateLocks);
+               dlist_init(&heaptarget->predicateLocks);
        }
 
        /*
         * Loop through all the locks on the old target, replacing them with
         * locks on the new target.
         */
-       oldpredlock = (PREDICATELOCK *)
-           SHMQueueNext(&(oldtarget->predicateLocks),
-                        &(oldtarget->predicateLocks),
-                        offsetof(PREDICATELOCK, targetLink));
-       while (oldpredlock)
+       dlist_foreach_modify(iter, &oldtarget->predicateLocks)
        {
-           PREDICATELOCK *nextpredlock;
+           PREDICATELOCK *oldpredlock =
+           dlist_container(PREDICATELOCK, targetLink, iter.cur);
            PREDICATELOCK *newpredlock;
            SerCommitSeqNo oldCommitSeqNo;
            SERIALIZABLEXACT *oldXact;
 
-           nextpredlock = (PREDICATELOCK *)
-               SHMQueueNext(&(oldtarget->predicateLocks),
-                            &(oldpredlock->targetLink),
-                            offsetof(PREDICATELOCK, targetLink));
-
            /*
             * Remove the old lock first. This avoids the chance of running
             * out of lock structure entries for the hash table.
@@ -3077,7 +2968,7 @@ DropAllPredicateLocksFromTable(Relation relation, bool transfer)
            oldCommitSeqNo = oldpredlock->commitSeqNo;
            oldXact = oldpredlock->tag.myXact;
 
-           SHMQueueDelete(&(oldpredlock->xactLink));
+           dlist_delete(&(oldpredlock->xactLink));
 
            /*
             * No need for retail delete from oldtarget list, we're removing
@@ -3103,10 +2994,10 @@ DropAllPredicateLocksFromTable(Relation relation, bool transfer)
                                                &found);
                if (!found)
                {
-                   SHMQueueInsertBefore(&(heaptarget->predicateLocks),
-                                        &(newpredlock->targetLink));
-                   SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
-                                        &(newpredlock->xactLink));
+                   dlist_push_tail(&(heaptarget->predicateLocks),
+                                   &(newpredlock->targetLink));
+                   dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
+                                   &(newpredlock->xactLink));
                    newpredlock->commitSeqNo = oldCommitSeqNo;
                }
                else
@@ -3119,8 +3010,6 @@ DropAllPredicateLocksFromTable(Relation relation, bool transfer)
                Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
                       || (newpredlock->tag.myXact == OldCommittedSxact));
            }
-
-           oldpredlock = nextpredlock;
        }
 
        hash_search(PredicateLockTargetHash, &oldtarget->tag, HASH_REMOVE,
@@ -3275,15 +3164,18 @@ PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
 static void
 SetNewSxactGlobalXmin(void)
 {
-   SERIALIZABLEXACT *sxact;
+   dlist_iter  iter;
 
    Assert(LWLockHeldByMe(SerializableXactHashLock));
 
    PredXact->SxactGlobalXmin = InvalidTransactionId;
    PredXact->SxactGlobalXminCount = 0;
 
-   for (sxact = FirstPredXact(); sxact != NULL; sxact = NextPredXact(sxact))
+   dlist_foreach(iter, &PredXact->activeList)
    {
+       SERIALIZABLEXACT *sxact =
+       dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
+
        if (!SxactIsRolledBack(sxact)
            && !SxactIsCommitted(sxact)
            && sxact != OldCommittedSxact)
@@ -3334,10 +3226,8 @@ void
 ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
 {
    bool        needToClear;
-   RWConflict  conflict,
-               nextConflict,
-               possibleUnsafeConflict;
    SERIALIZABLEXACT *roXact;
+   dlist_mutable_iter iter;
 
    /*
     * We can't trust XactReadOnly here, because a transaction which started
@@ -3525,23 +3415,15 @@ ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
         * make us unsafe. Note that we use 'inLink' for the iteration as
         * opposed to 'outLink' for the r/w xacts.
         */
-       possibleUnsafeConflict = (RWConflict)
-           SHMQueueNext(&MySerializableXact->possibleUnsafeConflicts,
-                        &MySerializableXact->possibleUnsafeConflicts,
-                        offsetof(RWConflictData, inLink));
-       while (possibleUnsafeConflict)
+       dlist_foreach_modify(iter, &MySerializableXact->possibleUnsafeConflicts)
        {
-           nextConflict = (RWConflict)
-               SHMQueueNext(&MySerializableXact->possibleUnsafeConflicts,
-                            &possibleUnsafeConflict->inLink,
-                            offsetof(RWConflictData, inLink));
+           RWConflict  possibleUnsafeConflict =
+           dlist_container(RWConflictData, inLink, iter.cur);
 
            Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
            Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);
 
            ReleaseRWConflict(possibleUnsafeConflict);
-
-           possibleUnsafeConflict = nextConflict;
        }
    }
 
@@ -3564,16 +3446,10 @@ ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
     * back clear them all.  Set SXACT_FLAG_CONFLICT_OUT if any point to
     * previously committed transactions.
     */
-   conflict = (RWConflict)
-       SHMQueueNext(&MySerializableXact->outConflicts,
-                    &MySerializableXact->outConflicts,
-                    offsetof(RWConflictData, outLink));
-   while (conflict)
+   dlist_foreach_modify(iter, &MySerializableXact->outConflicts)
    {
-       nextConflict = (RWConflict)
-           SHMQueueNext(&MySerializableXact->outConflicts,
-                        &conflict->outLink,
-                        offsetof(RWConflictData, outLink));
+       RWConflict  conflict =
+       dlist_container(RWConflictData, outLink, iter.cur);
 
        if (isCommit
            && !SxactIsReadOnly(MySerializableXact)
@@ -3589,31 +3465,21 @@ ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
            || SxactIsCommitted(conflict->sxactIn)
            || (conflict->sxactIn->SeqNo.lastCommitBeforeSnapshot >= PredXact->LastSxactCommitSeqNo))
            ReleaseRWConflict(conflict);
-
-       conflict = nextConflict;
    }
 
    /*
     * Release all inConflicts from committed and read-only transactions. If
     * we're rolling back, clear them all.
     */
-   conflict = (RWConflict)
-       SHMQueueNext(&MySerializableXact->inConflicts,
-                    &MySerializableXact->inConflicts,
-                    offsetof(RWConflictData, inLink));
-   while (conflict)
+   dlist_foreach_modify(iter, &MySerializableXact->inConflicts)
    {
-       nextConflict = (RWConflict)
-           SHMQueueNext(&MySerializableXact->inConflicts,
-                        &conflict->inLink,
-                        offsetof(RWConflictData, inLink));
+       RWConflict  conflict =
+       dlist_container(RWConflictData, inLink, iter.cur);
 
        if (!isCommit
            || SxactIsCommitted(conflict->sxactOut)
            || SxactIsReadOnly(conflict->sxactOut))
            ReleaseRWConflict(conflict);
-
-       conflict = nextConflict;
    }
 
    if (!topLevelIsDeclaredReadOnly)
@@ -3624,16 +3490,10 @@ ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
         * conflict out. If any are waiting DEFERRABLE transactions, wake them
         * up if they are known safe or known unsafe.
         */
-       possibleUnsafeConflict = (RWConflict)
-           SHMQueueNext(&MySerializableXact->possibleUnsafeConflicts,
-                        &MySerializableXact->possibleUnsafeConflicts,
-                        offsetof(RWConflictData, outLink));
-       while (possibleUnsafeConflict)
+       dlist_foreach_modify(iter, &MySerializableXact->possibleUnsafeConflicts)
        {
-           nextConflict = (RWConflict)
-               SHMQueueNext(&MySerializableXact->possibleUnsafeConflicts,
-                            &possibleUnsafeConflict->outLink,
-                            offsetof(RWConflictData, outLink));
+           RWConflict  possibleUnsafeConflict =
+           dlist_container(RWConflictData, outLink, iter.cur);
 
            roXact = possibleUnsafeConflict->sxactIn;
            Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
@@ -3661,7 +3521,7 @@ ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
                 * transaction can now safely release its predicate locks (but
                 * that transaction's backend has to do that itself).
                 */
-               if (SHMQueueEmpty(&roXact->possibleUnsafeConflicts))
+               if (dlist_is_empty(&roXact->possibleUnsafeConflicts))
                    roXact->flags |= SXACT_FLAG_RO_SAFE;
            }
 
@@ -3672,8 +3532,6 @@ ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
            if (SxactIsDeferrableWaiting(roXact) &&
                (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
                ProcSendSignal(roXact->pgprocno);
-
-           possibleUnsafeConflict = nextConflict;
        }
    }
 
@@ -3701,8 +3559,8 @@ ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
 
    /* Add this to the list of transactions to check for later cleanup. */
    if (isCommit)
-       SHMQueueInsertBefore(FinishedSerializableTransactions,
-                            &MySerializableXact->finishedLink);
+       dlist_push_tail(FinishedSerializableTransactions,
+                       &MySerializableXact->finishedLink);
 
    /*
     * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
@@ -3744,27 +3602,19 @@ ReleasePredicateLocksLocal(void)
 static void
 ClearOldPredicateLocks(void)
 {
-   SERIALIZABLEXACT *finishedSxact;
-   PREDICATELOCK *predlock;
+   dlist_mutable_iter iter;
 
    /*
     * Loop through finished transactions. They are in commit order, so we can
     * stop as soon as we find one that's still interesting.
     */
    LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
-   finishedSxact = (SERIALIZABLEXACT *)
-       SHMQueueNext(FinishedSerializableTransactions,
-                    FinishedSerializableTransactions,
-                    offsetof(SERIALIZABLEXACT, finishedLink));
    LWLockAcquire(SerializableXactHashLock, LW_SHARED);
-   while (finishedSxact)
+   dlist_foreach_modify(iter, FinishedSerializableTransactions)
    {
-       SERIALIZABLEXACT *nextSxact;
+       SERIALIZABLEXACT *finishedSxact =
+       dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
 
-       nextSxact = (SERIALIZABLEXACT *)
-           SHMQueueNext(FinishedSerializableTransactions,
-                        &(finishedSxact->finishedLink),
-                        offsetof(SERIALIZABLEXACT, finishedLink));
        if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)
            || TransactionIdPrecedesOrEquals(finishedSxact->finishedBefore,
                                             PredXact->SxactGlobalXmin))
@@ -3774,7 +3624,7 @@ ClearOldPredicateLocks(void)
             * took its snapshot. It's no longer interesting.
             */
            LWLockRelease(SerializableXactHashLock);
-           SHMQueueDelete(&(finishedSxact->finishedLink));
+           dlist_delete_thoroughly(&finishedSxact->finishedLink);
            ReleaseOneSerializableXact(finishedSxact, false, false);
            LWLockAcquire(SerializableXactHashLock, LW_SHARED);
        }
@@ -3791,7 +3641,7 @@ ClearOldPredicateLocks(void)
            if (SxactIsReadOnly(finishedSxact))
            {
                /* A read-only transaction can be removed entirely */
-               SHMQueueDelete(&(finishedSxact->finishedLink));
+               dlist_delete_thoroughly(&(finishedSxact->finishedLink));
                ReleaseOneSerializableXact(finishedSxact, false, false);
            }
            else
@@ -3812,7 +3662,6 @@ ClearOldPredicateLocks(void)
            /* Still interesting. */
            break;
        }
-       finishedSxact = nextSxact;
    }
    LWLockRelease(SerializableXactHashLock);
 
@@ -3820,20 +3669,12 @@ ClearOldPredicateLocks(void)
     * Loop through predicate locks on dummy transaction for summarized data.
     */
    LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
-   predlock = (PREDICATELOCK *)
-       SHMQueueNext(&OldCommittedSxact->predicateLocks,
-                    &OldCommittedSxact->predicateLocks,
-                    offsetof(PREDICATELOCK, xactLink));
-   while (predlock)
+   dlist_foreach_modify(iter, &OldCommittedSxact->predicateLocks)
    {
-       PREDICATELOCK *nextpredlock;
+       PREDICATELOCK *predlock =
+       dlist_container(PREDICATELOCK, xactLink, iter.cur);
        bool        canDoPartialCleanup;
 
-       nextpredlock = (PREDICATELOCK *)
-           SHMQueueNext(&OldCommittedSxact->predicateLocks,
-                        &predlock->xactLink,
-                        offsetof(PREDICATELOCK, xactLink));
-
        LWLockAcquire(SerializableXactHashLock, LW_SHARED);
        Assert(predlock->commitSeqNo != 0);
        Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
@@ -3860,8 +3701,8 @@ ClearOldPredicateLocks(void)
 
            LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
-           SHMQueueDelete(&(predlock->targetLink));
-           SHMQueueDelete(&(predlock->xactLink));
+           dlist_delete(&(predlock->targetLink));
+           dlist_delete(&(predlock->xactLink));
 
            hash_search_with_hash_value(PredicateLockHash, &tag,
                                        PredicateLockHashCodeFromTargetHashCode(&tag,
@@ -3871,8 +3712,6 @@ ClearOldPredicateLocks(void)
 
            LWLockRelease(partitionLock);
        }
-
-       predlock = nextpredlock;
    }
 
    LWLockRelease(SerializablePredicateListLock);
@@ -3902,10 +3741,8 @@ static void
 ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
                           bool summarize)
 {
-   PREDICATELOCK *predlock;
    SERIALIZABLEXIDTAG sxidtag;
-   RWConflict  conflict,
-               nextConflict;
+   dlist_mutable_iter iter;
 
    Assert(sxact != NULL);
    Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
@@ -3919,27 +3756,17 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
    LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
    if (IsInParallelMode())
        LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
-   predlock = (PREDICATELOCK *)
-       SHMQueueNext(&(sxact->predicateLocks),
-                    &(sxact->predicateLocks),
-                    offsetof(PREDICATELOCK, xactLink));
-   while (predlock)
+   dlist_foreach_modify(iter, &sxact->predicateLocks)
    {
-       PREDICATELOCK *nextpredlock;
+       PREDICATELOCK *predlock =
+       dlist_container(PREDICATELOCK, xactLink, iter.cur);
        PREDICATELOCKTAG tag;
-       SHM_QUEUE  *targetLink;
        PREDICATELOCKTARGET *target;
        PREDICATELOCKTARGETTAG targettag;
        uint32      targettaghash;
        LWLock     *partitionLock;
 
-       nextpredlock = (PREDICATELOCK *)
-           SHMQueueNext(&(sxact->predicateLocks),
-                        &(predlock->xactLink),
-                        offsetof(PREDICATELOCK, xactLink));
-
        tag = predlock->tag;
-       targetLink = &(predlock->targetLink);
        target = tag.myTarget;
        targettag = target->tag;
        targettaghash = PredicateLockTargetTagHashCode(&targettag);
@@ -3947,7 +3774,7 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
 
        LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
-       SHMQueueDelete(targetLink);
+       dlist_delete(&predlock->targetLink);
 
        hash_search_with_hash_value(PredicateLockHash, &tag,
                                    PredicateLockHashCodeFromTargetHashCode(&tag,
@@ -3977,10 +3804,10 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
            }
            else
            {
-               SHMQueueInsertBefore(&(target->predicateLocks),
-                                    &(predlock->targetLink));
-               SHMQueueInsertBefore(&(OldCommittedSxact->predicateLocks),
-                                    &(predlock->xactLink));
+               dlist_push_tail(&target->predicateLocks,
+                               &predlock->targetLink);
+               dlist_push_tail(&OldCommittedSxact->predicateLocks,
+                               &predlock->xactLink);
                predlock->commitSeqNo = sxact->commitSeqNo;
            }
        }
@@ -3988,15 +3815,13 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
            RemoveTargetIfNoLongerUsed(target, targettaghash);
 
        LWLockRelease(partitionLock);
-
-       predlock = nextpredlock;
    }
 
    /*
     * Rather than retail removal, just re-init the head after we've run
     * through the list.
     */
-   SHMQueueInit(&sxact->predicateLocks);
+   dlist_init(&sxact->predicateLocks);
 
    if (IsInParallelMode())
        LWLockRelease(&sxact->perXactPredicateListLock);
@@ -4008,38 +3833,26 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
    /* Release all outConflicts (unless 'partial' is true) */
    if (!partial)
    {
-       conflict = (RWConflict)
-           SHMQueueNext(&sxact->outConflicts,
-                        &sxact->outConflicts,
-                        offsetof(RWConflictData, outLink));
-       while (conflict)
+       dlist_foreach_modify(iter, &sxact->outConflicts)
        {
-           nextConflict = (RWConflict)
-               SHMQueueNext(&sxact->outConflicts,
-                            &conflict->outLink,
-                            offsetof(RWConflictData, outLink));
+           RWConflict  conflict =
+           dlist_container(RWConflictData, outLink, iter.cur);
+
            if (summarize)
                conflict->sxactIn->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
            ReleaseRWConflict(conflict);
-           conflict = nextConflict;
        }
    }
 
    /* Release all inConflicts. */
-   conflict = (RWConflict)
-       SHMQueueNext(&sxact->inConflicts,
-                    &sxact->inConflicts,
-                    offsetof(RWConflictData, inLink));
-   while (conflict)
+   dlist_foreach_modify(iter, &sxact->inConflicts)
    {
-       nextConflict = (RWConflict)
-           SHMQueueNext(&sxact->inConflicts,
-                        &conflict->inLink,
-                        offsetof(RWConflictData, inLink));
+       RWConflict  conflict =
+       dlist_container(RWConflictData, inLink, iter.cur);
+
        if (summarize)
            conflict->sxactOut->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
        ReleaseRWConflict(conflict);
-       conflict = nextConflict;
    }
 
    /* Finally, get rid of the xid and the record of the transaction itself. */
@@ -4165,7 +3978,7 @@ CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot s
                         errhint("The transaction might succeed if retried.")));
 
            if (SxactHasSummaryConflictIn(MySerializableXact)
-               || !SHMQueueEmpty(&MySerializableXact->inConflicts))
+               || !dlist_is_empty(&MySerializableXact->inConflicts))
                ereport(ERROR,
                        (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                         errmsg("could not serialize access due to read/write dependencies among transactions"),
@@ -4261,9 +4074,9 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
    uint32      targettaghash;
    LWLock     *partitionLock;
    PREDICATELOCKTARGET *target;
-   PREDICATELOCK *predlock;
    PREDICATELOCK *mypredlock = NULL;
    PREDICATELOCKTAG mypredlocktag;
+   dlist_mutable_iter iter;
 
    Assert(MySerializableXact != InvalidSerializableXact);
 
@@ -4288,24 +4101,14 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
     * Each lock for an overlapping transaction represents a conflict: a
     * rw-dependency in to this transaction.
     */
-   predlock = (PREDICATELOCK *)
-       SHMQueueNext(&(target->predicateLocks),
-                    &(target->predicateLocks),
-                    offsetof(PREDICATELOCK, targetLink));
    LWLockAcquire(SerializableXactHashLock, LW_SHARED);
-   while (predlock)
-   {
-       SHM_QUEUE  *predlocktargetlink;
-       PREDICATELOCK *nextpredlock;
-       SERIALIZABLEXACT *sxact;
 
-       predlocktargetlink = &(predlock->targetLink);
-       nextpredlock = (PREDICATELOCK *)
-           SHMQueueNext(&(target->predicateLocks),
-                        predlocktargetlink,
-                        offsetof(PREDICATELOCK, targetLink));
+   dlist_foreach_modify(iter, &target->predicateLocks)
+   {
+       PREDICATELOCK *predlock =
+       dlist_container(PREDICATELOCK, targetLink, iter.cur);
+       SERIALIZABLEXACT *sxact = predlock->tag.myXact;
 
-       sxact = predlock->tag.myXact;
        if (sxact == MySerializableXact)
        {
            /*
@@ -4350,8 +4153,6 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
            LWLockRelease(SerializableXactHashLock);
            LWLockAcquire(SerializableXactHashLock, LW_SHARED);
        }
-
-       predlock = nextpredlock;
    }
    LWLockRelease(SerializableXactHashLock);
    LWLockRelease(partitionLock);
@@ -4391,8 +4192,8 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
        {
            Assert(rmpredlock == mypredlock);
 
-           SHMQueueDelete(&(mypredlock->targetLink));
-           SHMQueueDelete(&(mypredlock->xactLink));
+           dlist_delete(&(mypredlock->targetLink));
+           dlist_delete(&(mypredlock->xactLink));
 
            rmpredlock = (PREDICATELOCK *)
                hash_search_with_hash_value(PredicateLockHash,
@@ -4562,7 +4363,7 @@ CheckTableForSerializableConflictIn(Relation relation)
 
    while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
    {
-       PREDICATELOCK *predlock;
+       dlist_mutable_iter iter;
 
        /*
         * Check whether this is a target which needs attention.
@@ -4575,26 +4376,16 @@ CheckTableForSerializableConflictIn(Relation relation)
        /*
         * Loop through locks for this target and flag conflicts.
         */
-       predlock = (PREDICATELOCK *)
-           SHMQueueNext(&(target->predicateLocks),
-                        &(target->predicateLocks),
-                        offsetof(PREDICATELOCK, targetLink));
-       while (predlock)
+       dlist_foreach_modify(iter, &target->predicateLocks)
        {
-           PREDICATELOCK *nextpredlock;
-
-           nextpredlock = (PREDICATELOCK *)
-               SHMQueueNext(&(target->predicateLocks),
-                            &(predlock->targetLink),
-                            offsetof(PREDICATELOCK, targetLink));
+           PREDICATELOCK *predlock =
+           dlist_container(PREDICATELOCK, targetLink, iter.cur);
 
            if (predlock->tag.myXact != MySerializableXact
                && !RWConflictExists(predlock->tag.myXact, MySerializableXact))
            {
                FlagRWConflict(predlock->tag.myXact, MySerializableXact);
            }
-
-           predlock = nextpredlock;
        }
    }
 
@@ -4652,7 +4443,6 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
                                        SERIALIZABLEXACT *writer)
 {
    bool        failure;
-   RWConflict  conflict;
 
    Assert(LWLockHeldByMe(SerializableXactHashLock));
 
@@ -4692,20 +4482,16 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
     * to abort.
     *------------------------------------------------------------------------
     */
-   if (!failure)
+   if (!failure && SxactHasSummaryConflictOut(writer))
+       failure = true;
+   else if (!failure)
    {
-       if (SxactHasSummaryConflictOut(writer))
-       {
-           failure = true;
-           conflict = NULL;
-       }
-       else
-           conflict = (RWConflict)
-               SHMQueueNext(&writer->outConflicts,
-                            &writer->outConflicts,
-                            offsetof(RWConflictData, outLink));
-       while (conflict)
+       dlist_iter  iter;
+
+       dlist_foreach(iter, &writer->outConflicts)
        {
+           RWConflict  conflict =
+           dlist_container(RWConflictData, outLink, iter.cur);
            SERIALIZABLEXACT *t2 = conflict->sxactIn;
 
            if (SxactIsPrepared(t2)
@@ -4719,10 +4505,6 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
                failure = true;
                break;
            }
-           conflict = (RWConflict)
-               SHMQueueNext(&writer->outConflicts,
-                            &conflict->outLink,
-                            offsetof(RWConflictData, outLink));
        }
    }
 
@@ -4744,30 +4526,31 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
        if (SxactHasSummaryConflictIn(reader))
        {
            failure = true;
-           conflict = NULL;
        }
        else
-           conflict = (RWConflict)
-               SHMQueueNext(&reader->inConflicts,
-                            &reader->inConflicts,
-                            offsetof(RWConflictData, inLink));
-       while (conflict)
        {
-           SERIALIZABLEXACT *t0 = conflict->sxactOut;
+           dlist_iter  iter;
 
-           if (!SxactIsDoomed(t0)
-               && (!SxactIsCommitted(t0)
-                   || t0->commitSeqNo >= writer->prepareSeqNo)
-               && (!SxactIsReadOnly(t0)
-                   || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
+           /*
+            * The unconstify is needed as we have no const version of
+            * dlist_foreach().
+            */
+           dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
            {
-               failure = true;
-               break;
+               const RWConflict conflict =
+               dlist_container(RWConflictData, inLink, iter.cur);
+               const SERIALIZABLEXACT *t0 = conflict->sxactOut;
+
+               if (!SxactIsDoomed(t0)
+                   && (!SxactIsCommitted(t0)
+                       || t0->commitSeqNo >= writer->prepareSeqNo)
+                   && (!SxactIsReadOnly(t0)
+                       || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
+               {
+                   failure = true;
+                   break;
+               }
            }
-           conflict = (RWConflict)
-               SHMQueueNext(&reader->inConflicts,
-                            &conflict->inLink,
-                            offsetof(RWConflictData, inLink));
        }
    }
 
@@ -4825,7 +4608,7 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
 void
 PreCommit_CheckForSerializationFailure(void)
 {
-   RWConflict  nearConflict;
+   dlist_iter  near_iter;
 
    if (MySerializableXact == InvalidSerializableXact)
        return;
@@ -4846,23 +4629,21 @@ PreCommit_CheckForSerializationFailure(void)
                 errhint("The transaction might succeed if retried.")));
    }
 
-   nearConflict = (RWConflict)
-       SHMQueueNext(&MySerializableXact->inConflicts,
-                    &MySerializableXact->inConflicts,
-                    offsetof(RWConflictData, inLink));
-   while (nearConflict)
+   dlist_foreach(near_iter, &MySerializableXact->inConflicts)
    {
+       RWConflict  nearConflict =
+       dlist_container(RWConflictData, inLink, near_iter.cur);
+
        if (!SxactIsCommitted(nearConflict->sxactOut)
            && !SxactIsDoomed(nearConflict->sxactOut))
        {
-           RWConflict  farConflict;
+           dlist_iter  far_iter;
 
-           farConflict = (RWConflict)
-               SHMQueueNext(&nearConflict->sxactOut->inConflicts,
-                            &nearConflict->sxactOut->inConflicts,
-                            offsetof(RWConflictData, inLink));
-           while (farConflict)
+           dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
            {
+               RWConflict  farConflict =
+               dlist_container(RWConflictData, inLink, far_iter.cur);
+
                if (farConflict->sxactOut == MySerializableXact
                    || (!SxactIsCommitted(farConflict->sxactOut)
                        && !SxactIsReadOnly(farConflict->sxactOut)
@@ -4886,17 +4667,8 @@ PreCommit_CheckForSerializationFailure(void)
                    nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
                    break;
                }
-               farConflict = (RWConflict)
-                   SHMQueueNext(&nearConflict->sxactOut->inConflicts,
-                                &farConflict->inLink,
-                                offsetof(RWConflictData, inLink));
            }
        }
-
-       nearConflict = (RWConflict)
-           SHMQueueNext(&MySerializableXact->inConflicts,
-                        &nearConflict->inLink,
-                        offsetof(RWConflictData, inLink));
    }
 
    MySerializableXact->prepareSeqNo = ++(PredXact->LastSxactCommitSeqNo);
@@ -4919,11 +4691,11 @@ PreCommit_CheckForSerializationFailure(void)
 void
 AtPrepare_PredicateLocks(void)
 {
-   PREDICATELOCK *predlock;
    SERIALIZABLEXACT *sxact;
    TwoPhasePredicateRecord record;
    TwoPhasePredicateXactRecord *xactRecord;
    TwoPhasePredicateLockRecord *lockRecord;
+   dlist_iter  iter;
 
    sxact = MySerializableXact;
    xactRecord = &(record.data.xactRecord);
@@ -4963,23 +4735,16 @@ AtPrepare_PredicateLocks(void)
     */
    Assert(!IsParallelWorker() && !ParallelContextActive());
 
-   predlock = (PREDICATELOCK *)
-       SHMQueueNext(&(sxact->predicateLocks),
-                    &(sxact->predicateLocks),
-                    offsetof(PREDICATELOCK, xactLink));
-
-   while (predlock != NULL)
+   dlist_foreach(iter, &sxact->predicateLocks)
    {
+       PREDICATELOCK *predlock =
+       dlist_container(PREDICATELOCK, xactLink, iter.cur);
+
        record.type = TWOPHASEPREDICATERECORD_LOCK;
        lockRecord->target = predlock->tag.myTarget->tag;
 
        RegisterTwoPhaseRecord(TWOPHASE_RM_PREDICATELOCK_ID, 0,
                               &record, sizeof(record));
-
-       predlock = (PREDICATELOCK *)
-           SHMQueueNext(&(sxact->predicateLocks),
-                        &(predlock->xactLink),
-                        offsetof(PREDICATELOCK, xactLink));
    }
 
    LWLockRelease(SerializablePredicateListLock);
@@ -5091,10 +4856,10 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
         * recovered xact started are still active, except possibly other
         * prepared xacts and we don't care whether those are RO_SAFE or not.
         */
-       SHMQueueInit(&(sxact->possibleUnsafeConflicts));
+       dlist_init(&(sxact->possibleUnsafeConflicts));
 
-       SHMQueueInit(&(sxact->predicateLocks));
-       SHMQueueElemInit(&(sxact->finishedLink));
+       dlist_init(&(sxact->predicateLocks));
+       dlist_node_init(&sxact->finishedLink);
 
        sxact->topXid = xid;
        sxact->xmin = xactRecord->xmin;
@@ -5112,8 +4877,8 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
         * we'll conservatively assume that it had both a conflict in and a
         * conflict out, and represent that with the summary conflict flags.
         */
-       SHMQueueInit(&(sxact->outConflicts));
-       SHMQueueInit(&(sxact->inConflicts));
+       dlist_init(&(sxact->outConflicts));
+       dlist_init(&(sxact->inConflicts));
        sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
        sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
 
index 9e42e1a72c573c46a0a024281c529bf32a8c4191..142a195d0e0f6e11efe1f3c757f6f698e24d31a2 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef PREDICATE_INTERNALS_H
 #define PREDICATE_INTERNALS_H
 
+#include "lib/ilist.h"
 #include "storage/lock.h"
 #include "storage/lwlock.h"
 
@@ -84,13 +85,14 @@ typedef struct SERIALIZABLEXACT
        SerCommitSeqNo lastCommitBeforeSnapshot;    /* when not committed or
                                                     * no conflict out */
    }           SeqNo;
-   SHM_QUEUE   outConflicts;   /* list of write transactions whose data we
+   dlist_head  outConflicts;   /* list of write transactions whose data we
                                 * couldn't read. */
-   SHM_QUEUE   inConflicts;    /* list of read transactions which couldn't
+   dlist_head  inConflicts;    /* list of read transactions which couldn't
                                 * see our write. */
-   SHM_QUEUE   predicateLocks; /* list of associated PREDICATELOCK objects */
-   SHM_QUEUE   finishedLink;   /* list link in
+   dlist_head  predicateLocks; /* list of associated PREDICATELOCK objects */
+   dlist_node  finishedLink;   /* list link in
                                 * FinishedSerializableTransactions */
+   dlist_node  xactLink;       /* PredXact->activeList/availableList */
 
    /*
     * perXactPredicateListLock is only used in parallel queries: it protects
@@ -103,7 +105,7 @@ typedef struct SERIALIZABLEXACT
     * for r/o transactions: list of concurrent r/w transactions that we could
     * potentially have conflicts with, and vice versa for r/w transactions
     */
-   SHM_QUEUE   possibleUnsafeConflicts;
+   dlist_head  possibleUnsafeConflicts;
 
    TransactionId topXid;       /* top level xid for the transaction, if one
                                 * exists; else invalid */
@@ -139,28 +141,10 @@ typedef struct SERIALIZABLEXACT
  */
 #define SXACT_FLAG_PARTIALLY_RELEASED  0x00000800
 
-/*
- * The following types are used to provide an ad hoc list for holding
- * SERIALIZABLEXACT objects.  An HTAB is overkill, since there is no need to
- * access these by key -- there are direct pointers to these objects where
- * needed.  If a shared memory list is created, these types can probably be
- * eliminated in favor of using the general solution.
- */
-typedef struct PredXactListElementData
-{
-   SHM_QUEUE   link;
-   SERIALIZABLEXACT sxact;
-}          PredXactListElementData;
-
-typedef struct PredXactListElementData *PredXactListElement;
-
-#define PredXactListElementDataSize \
-       ((Size)MAXALIGN(sizeof(PredXactListElementData)))
-
 typedef struct PredXactListData
 {
-   SHM_QUEUE   availableList;
-   SHM_QUEUE   activeList;
+   dlist_head  availableList;
+   dlist_head  activeList;
 
    /*
     * These global variables are maintained when registering and cleaning up
@@ -187,7 +171,7 @@ typedef struct PredXactListData
                                                 * seq no */
    SERIALIZABLEXACT *OldCommittedSxact;    /* shared copy of dummy sxact */
 
-   PredXactListElement element;
+   SERIALIZABLEXACT *element;
 }          PredXactListData;
 
 typedef struct PredXactListData *PredXactList;
@@ -208,8 +192,8 @@ typedef struct PredXactListData *PredXactList;
  */
 typedef struct RWConflictData
 {
-   SHM_QUEUE   outLink;        /* link for list of conflicts out from a sxact */
-   SHM_QUEUE   inLink;         /* link for list of conflicts in to a sxact */
+   dlist_node  outLink;        /* link for list of conflicts out from a sxact */
+   dlist_node  inLink;         /* link for list of conflicts in to a sxact */
    SERIALIZABLEXACT *sxactOut;
    SERIALIZABLEXACT *sxactIn;
 }          RWConflictData;
@@ -221,7 +205,7 @@ typedef struct RWConflictData *RWConflict;
 
 typedef struct RWConflictPoolHeaderData
 {
-   SHM_QUEUE   availableList;
+   dlist_head  availableList;
    RWConflict  element;
 }          RWConflictPoolHeaderData;
 
@@ -303,7 +287,7 @@ typedef struct PREDICATELOCKTARGET
    PREDICATELOCKTARGETTAG tag; /* unique identifier of lockable object */
 
    /* data */
-   SHM_QUEUE   predicateLocks; /* list of PREDICATELOCK objects assoc. with
+   dlist_head  predicateLocks; /* list of PREDICATELOCK objects assoc. with
                                 * predicate lock target */
 } PREDICATELOCKTARGET;
 
@@ -336,9 +320,9 @@ typedef struct PREDICATELOCK
    PREDICATELOCKTAG tag;       /* unique identifier of lock */
 
    /* data */
-   SHM_QUEUE   targetLink;     /* list link in PREDICATELOCKTARGET's list of
+   dlist_node  targetLink;     /* list link in PREDICATELOCKTARGET's list of
                                 * predicate locks */
-   SHM_QUEUE   xactLink;       /* list link in SERIALIZABLEXACT's list of
+   dlist_node  xactLink;       /* list link in SERIALIZABLEXACT's list of
                                 * predicate locks */
    SerCommitSeqNo commitSeqNo; /* only used for summarized predicate locks */
 } PREDICATELOCK;