On 2020-01-16 13:56, Robert Haas wrote:
On Thu, Jan 16, 2020 at 12:50 AM Michael Paquier <mich...@paquier.xyz> wrote:
Thanks, that looks fine.  I am still not sure whether the second patch
adding an enum via ProcWaitStatus improves the code readability
though, so my take would be to discard it for now.  Perhaps others
think differently, I don't know.

IMHO, custom enums for each particular case would be a big improvement
over supposedly-generic STATUS codes. It makes it clearer which values
are possible in each code path, and it comes out nicer in the
debugger, too.

Given this feedback, I would like to re-propose the original patch, attached again here.

After this, the use of the remaining STATUS_* symbols will be contained to the frontend and backend libpq code, so it'll be more coherent.

--
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 477515ea4b112e860587640f255cbfcdfee1755c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Sun, 29 Dec 2019 09:09:20 +0100
Subject: [PATCH v2 1/4] Remove STATUS_WAITING

Add a separate enum for use in the locking APIs, which were the only
user.

Discussion: 
https://www.postgresql.org/message-id/flat/a6f91ead-0ce4-2a34-062b-7ab9813ea308%402ndquadrant.com
---
 src/backend/access/transam/twophase.c |  2 +-
 src/backend/storage/lmgr/lock.c       |  8 ++---
 src/backend/storage/lmgr/proc.c       | 46 +++++++++++++--------------
 src/include/c.h                       |  1 -
 src/include/storage/proc.h            | 13 ++++++--
 5 files changed, 38 insertions(+), 32 deletions(-)

diff --git a/src/backend/access/transam/twophase.c 
b/src/backend/access/transam/twophase.c
index e1904877fa..54fb6cc047 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -460,7 +460,7 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId 
xid, const char *gid,
        MemSet(proc, 0, sizeof(PGPROC));
        proc->pgprocno = gxact->pgprocno;
        SHMQueueElemInit(&(proc->links));
-       proc->waitStatus = STATUS_OK;
+       proc->waitStatus = PROC_WAIT_STATUS_OK;
        /* We set up the gxact's VXID as InvalidBackendId/XID */
        proc->lxid = (LocalTransactionId) xid;
        pgxact->xid = xid;
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 7fecb38162..95989ce79b 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -1856,7 +1856,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
         */
        PG_TRY();
        {
-               if (ProcSleep(locallock, lockMethodTable) != STATUS_OK)
+               if (ProcSleep(locallock, lockMethodTable) != 
PROC_WAIT_STATUS_OK)
                {
                        /*
                         * We failed as a result of a deadlock, see 
CheckDeadLock(). Quit
@@ -1907,7 +1907,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
 /*
  * Remove a proc from the wait-queue it is on (caller must know it is on one).
  * This is only used when the proc has failed to get the lock, so we set its
- * waitStatus to STATUS_ERROR.
+ * waitStatus to PROC_WAIT_STATUS_ERROR.
  *
  * Appropriate partition lock must be held by caller.  Also, caller is
  * responsible for signaling the proc if needed.
@@ -1923,7 +1923,7 @@ RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode)
        LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);
 
        /* Make sure proc is waiting */
-       Assert(proc->waitStatus == STATUS_WAITING);
+       Assert(proc->waitStatus == PROC_WAIT_STATUS_WAITING);
        Assert(proc->links.next != NULL);
        Assert(waitLock);
        Assert(waitLock->waitProcs.size > 0);
@@ -1946,7 +1946,7 @@ RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode)
        /* Clean up the proc's own state, and pass it the ok/fail signal */
        proc->waitLock = NULL;
        proc->waitProcLock = NULL;
-       proc->waitStatus = STATUS_ERROR;
+       proc->waitStatus = PROC_WAIT_STATUS_ERROR;
 
        /*
         * Delete the proclock immediately if it represents no already-held 
locks.
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index f5eef6fa4e..e57fcd2538 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -383,7 +383,7 @@ InitProcess(void)
         * initialized by InitProcGlobal.
         */
        SHMQueueElemInit(&(MyProc->links));
-       MyProc->waitStatus = STATUS_OK;
+       MyProc->waitStatus = PROC_WAIT_STATUS_OK;
        MyProc->lxid = InvalidLocalTransactionId;
        MyProc->fpVXIDLock = false;
        MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
@@ -567,7 +567,7 @@ InitAuxiliaryProcess(void)
         * initialized by InitProcGlobal.
         */
        SHMQueueElemInit(&(MyProc->links));
-       MyProc->waitStatus = STATUS_OK;
+       MyProc->waitStatus = PROC_WAIT_STATUS_OK;
        MyProc->lxid = InvalidLocalTransactionId;
        MyProc->fpVXIDLock = false;
        MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
@@ -755,7 +755,7 @@ LockErrorCleanup(void)
                 * did grant us the lock, we'd better remember it in our local 
lock
                 * table.
                 */
-               if (MyProc->waitStatus == STATUS_OK)
+               if (MyProc->waitStatus == PROC_WAIT_STATUS_OK)
                        GrantAwaitedLock();
        }
 
@@ -1051,14 +1051,14 @@ ProcQueueInit(PROC_QUEUE *queue)
  * The lock table's partition lock must be held at entry, and will be held
  * at exit.
  *
- * Result: STATUS_OK if we acquired the lock, STATUS_ERROR if not (deadlock).
+ * Result: PROC_WAIT_STATUS_OK if we acquired the lock, PROC_WAIT_STATUS_ERROR 
if not (deadlock).
  *
  * ASSUME: that no one will fiddle with the queue until after
  *             we release the partition lock.
  *
  * NOTES: The process queue is now a priority queue for locking.
  */
-int
+ProcWaitStatus
 ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 {
        LOCKMODE        lockmode = locallock->tag.mode;
@@ -1070,7 +1070,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
        LOCKMASK        myHeldLocks = MyProc->heldLocks;
        bool            early_deadlock = false;
        bool            allow_autovacuum_cancel = true;
-       int                     myWaitStatus;
+       ProcWaitStatus myWaitStatus;
        PGPROC     *proc;
        PGPROC     *leader = MyProc->lockGroupLeader;
        int                     i;
@@ -1161,7 +1161,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
                                        /* Skip the wait and just grant myself 
the lock. */
                                        GrantLock(lock, proclock, lockmode);
                                        GrantAwaitedLock();
-                                       return STATUS_OK;
+                                       return PROC_WAIT_STATUS_OK;
                                }
                                /* Break out of loop to put myself before him */
                                break;
@@ -1195,7 +1195,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
        MyProc->waitProcLock = proclock;
        MyProc->waitLockMode = lockmode;
 
-       MyProc->waitStatus = STATUS_WAITING;
+       MyProc->waitStatus = PROC_WAIT_STATUS_WAITING;
 
        /*
         * If we detected deadlock, give up without waiting.  This must agree 
with
@@ -1204,7 +1204,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
        if (early_deadlock)
        {
                RemoveFromWaitQueue(MyProc, hashcode);
-               return STATUS_ERROR;
+               return PROC_WAIT_STATUS_ERROR;
        }
 
        /* mark that we are waiting for a lock */
@@ -1236,7 +1236,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
        /*
         * Set timer so we can wake up after awhile and check for a deadlock. 
If a
         * deadlock is detected, the handler sets MyProc->waitStatus =
-        * STATUS_ERROR, allowing us to know that we must report failure rather
+        * PROC_WAIT_STATUS_ERROR, allowing us to know that we must report 
failure rather
         * than success.
         *
         * By delaying the check until we've waited for a bit, we can avoid
@@ -1302,11 +1302,11 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
                }
 
                /*
-                * waitStatus could change from STATUS_WAITING to something else
+                * waitStatus could change from PROC_WAIT_STATUS_WAITING to 
something else
                 * asynchronously.  Read it just once per loop to prevent 
surprising
                 * behavior (such as missing log messages).
                 */
-               myWaitStatus = *((volatile int *) &MyProc->waitStatus);
+               myWaitStatus = *((volatile ProcWaitStatus *) 
&MyProc->waitStatus);
 
                /*
                 * If we are not deadlocked, but are waiting on an 
autovacuum-induced
@@ -1487,24 +1487,24 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
                                                                                
           lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
                        }
 
-                       if (myWaitStatus == STATUS_WAITING)
+                       if (myWaitStatus == PROC_WAIT_STATUS_WAITING)
                                ereport(LOG,
                                                (errmsg("process %d still 
waiting for %s on %s after %ld.%03d ms",
                                                                MyProcPid, 
modename, buf.data, msecs, usecs),
                                                 (errdetail_log_plural("Process 
holding the lock: %s. Wait queue: %s.",
                                                                                
           "Processes holding the lock: %s. Wait queue: %s.",
                                                                                
           lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
-                       else if (myWaitStatus == STATUS_OK)
+                       else if (myWaitStatus == PROC_WAIT_STATUS_OK)
                                ereport(LOG,
                                                (errmsg("process %d acquired %s 
on %s after %ld.%03d ms",
                                                                MyProcPid, 
modename, buf.data, msecs, usecs)));
                        else
                        {
-                               Assert(myWaitStatus == STATUS_ERROR);
+                               Assert(myWaitStatus == PROC_WAIT_STATUS_ERROR);
 
                                /*
                                 * Currently, the deadlock checker always kicks 
its own
-                                * process, which means that we'll only see 
STATUS_ERROR when
+                                * process, which means that we'll only see 
PROC_WAIT_STATUS_ERROR when
                                 * deadlock_state == DS_HARD_DEADLOCK, and 
there's no need to
                                 * print redundant messages.  But for 
completeness and
                                 * future-proofing, print a message if it looks 
like someone
@@ -1529,7 +1529,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
                        pfree(lock_holders_sbuf.data);
                        pfree(lock_waiters_sbuf.data);
                }
-       } while (myWaitStatus == STATUS_WAITING);
+       } while (myWaitStatus == PROC_WAIT_STATUS_WAITING);
 
        /*
         * Disable the timers, if they are still running.  As in 
LockErrorCleanup,
@@ -1568,7 +1568,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
        /*
         * If we got the lock, be sure to remember it in the locallock table.
         */
-       if (MyProc->waitStatus == STATUS_OK)
+       if (MyProc->waitStatus == PROC_WAIT_STATUS_OK)
                GrantAwaitedLock();
 
        /*
@@ -1590,10 +1590,10 @@ ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable)
  * XXX: presently, this code is only used for the "success" case, and only
  * works correctly for that case.  To clean up in failure case, would need
  * to twiddle the lock's request counts too --- see RemoveFromWaitQueue.
- * Hence, in practice the waitStatus parameter must be STATUS_OK.
+ * Hence, in practice the waitStatus parameter must be PROC_WAIT_STATUS_OK.
  */
 PGPROC *
-ProcWakeup(PGPROC *proc, int waitStatus)
+ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus)
 {
        PGPROC     *retProc;
 
@@ -1601,7 +1601,7 @@ ProcWakeup(PGPROC *proc, int waitStatus)
        if (proc->links.prev == NULL ||
                proc->links.next == NULL)
                return NULL;
-       Assert(proc->waitStatus == STATUS_WAITING);
+       Assert(proc->waitStatus == PROC_WAIT_STATUS_WAITING);
 
        /* Save next process before we zap the list link */
        retProc = (PGPROC *) proc->links.next;
@@ -1657,7 +1657,7 @@ ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
                {
                        /* OK to waken */
                        GrantLock(lock, proc->waitProcLock, lockmode);
-                       proc = ProcWakeup(proc, STATUS_OK);
+                       proc = ProcWakeup(proc, PROC_WAIT_STATUS_OK);
 
                        /*
                         * ProcWakeup removes proc from the lock's waiting 
process queue
@@ -1737,7 +1737,7 @@ CheckDeadLock(void)
                 * preserve the flexibility to kill some other transaction than 
the
                 * one detecting the deadlock.)
                 *
-                * RemoveFromWaitQueue sets MyProc->waitStatus to STATUS_ERROR, 
so
+                * RemoveFromWaitQueue sets MyProc->waitStatus to 
PROC_WAIT_STATUS_ERROR, so
                 * ProcSleep will report an error after we return from the 
signal
                 * handler.
                 */
diff --git a/src/include/c.h b/src/include/c.h
index d72b23afe4..a904b49a37 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1133,7 +1133,6 @@ typedef union PGAlignedXLogBlock
 #define STATUS_OK                              (0)
 #define STATUS_ERROR                   (-1)
 #define STATUS_EOF                             (-2)
-#define STATUS_WAITING                 (2)
 
 /*
  * gettext support
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 1ee9000b2b..b20e2ad4f6 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -76,6 +76,13 @@ struct XidCache
  */
 #define INVALID_PGPROCNO               PG_INT32_MAX
 
+typedef enum
+{
+       PROC_WAIT_STATUS_OK,
+       PROC_WAIT_STATUS_WAITING,
+       PROC_WAIT_STATUS_ERROR,
+} ProcWaitStatus;
+
 /*
  * Each backend has a PGPROC struct in shared memory.  There is also a list of
  * currently-unused PGPROC structs that will be reallocated to new backends.
@@ -99,7 +106,7 @@ struct PGPROC
        PGPROC    **procgloballist; /* procglobal list that owns this PGPROC */
 
        PGSemaphore sem;                        /* ONE semaphore to sleep on */
-       int                     waitStatus;             /* STATUS_WAITING, 
STATUS_OK or STATUS_ERROR */
+       ProcWaitStatus waitStatus;
 
        Latch           procLatch;              /* generic latch for process */
 
@@ -315,8 +322,8 @@ extern bool HaveNFreeProcs(int n);
 extern void ProcReleaseLocks(bool isCommit);
 
 extern void ProcQueueInit(PROC_QUEUE *queue);
-extern int     ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable);
-extern PGPROC *ProcWakeup(PGPROC *proc, int waitStatus);
+extern ProcWaitStatus ProcSleep(LOCALLOCK *locallock, LockMethod 
lockMethodTable);
+extern PGPROC *ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus);
 extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock);
 extern void CheckDeadLockAlert(void);
 extern bool IsWaitingForLock(void);
-- 
2.27.0

Reply via email to