remove some STATUS_* symbols
I have found the collection of STATUS_* defines in c.h a bit curious.
There used to be a lot more even that have been removed over time.
Currently, STATUS_FOUND and STATUS_WAITING are only used in one group of
functions each, so perhaps it would make more sense to remove these from
the global namespace and make them a local concern.
Attached are two patches to remove these two symbols. STATUS_FOUND can
be replaced by a simple bool. STATUS_WAITING is replaced by a separate
enum.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachments:
0001-Remove-STATUS_FOUND.patchtext/plain; charset=UTF-8; name=0001-Remove-STATUS_FOUND.patch; x-mac-creator=0; x-mac-type=0Download
From f575da0fedc920003afb4655f3503cc91949cc55 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sun, 29 Dec 2019 09:09:20 +0100
Subject: [PATCH 1/4] Remove STATUS_FOUND
Replace the solitary use with a bool.
---
src/backend/storage/lmgr/lock.c | 24 +++++++++++-------------
src/backend/storage/lmgr/proc.c | 12 ++++--------
src/include/c.h | 1 -
src/include/storage/lock.h | 2 +-
4 files changed, 16 insertions(+), 23 deletions(-)
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 9089733ecc..e2c728a97d 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -746,7 +746,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
ResourceOwner owner;
uint32 hashcode;
LWLock *partitionLock;
- int status;
+ bool found_conflict;
bool log_lock = false;
if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
@@ -979,12 +979,12 @@ LockAcquireExtended(const LOCKTAG *locktag,
* (That's last because most complex check.)
*/
if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
- status = STATUS_FOUND;
+ found_conflict = true;
else
- status = LockCheckConflicts(lockMethodTable, lockmode,
+ found_conflict = LockCheckConflicts(lockMethodTable, lockmode,
lock, proclock);
- if (status == STATUS_OK)
+ if (!found_conflict)
{
/* No conflict with held or previously requested locks */
GrantLock(lock, proclock, lockmode);
@@ -992,8 +992,6 @@ LockAcquireExtended(const LOCKTAG *locktag,
}
else
{
- Assert(status == STATUS_FOUND);
-
/*
* We can't acquire the lock immediately. If caller specified no
* blocking, remove useless table entries and return
@@ -1330,7 +1328,7 @@ RemoveLocalLock(LOCALLOCK *locallock)
* LockCheckConflicts -- test whether requested lock conflicts
* with those already granted
*
- * Returns STATUS_FOUND if conflict, STATUS_OK if no conflict.
+ * Returns true if conflict, false if no conflict.
*
* NOTES:
* Here's what makes this complicated: one process's locks don't
@@ -1340,7 +1338,7 @@ RemoveLocalLock(LOCALLOCK *locallock)
* the same group. So, we must subtract off these locks when determining
* whether the requested new lock conflicts with those already held.
*/
-int
+bool
LockCheckConflicts(LockMethod lockMethodTable,
LOCKMODE lockmode,
LOCK *lock,
@@ -1367,7 +1365,7 @@ LockCheckConflicts(LockMethod lockMethodTable,
if (!(conflictMask & lock->grantMask))
{
PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);
- return STATUS_OK;
+ return false;
}
/*
@@ -1393,7 +1391,7 @@ LockCheckConflicts(LockMethod lockMethodTable,
if (totalConflictsRemaining == 0)
{
PROCLOCK_PRINT("LockCheckConflicts: resolved (simple)", proclock);
- return STATUS_OK;
+ return false;
}
/* If no group locking, it's definitely a conflict. */
@@ -1402,7 +1400,7 @@ LockCheckConflicts(LockMethod lockMethodTable,
Assert(proclock->tag.myProc == MyProc);
PROCLOCK_PRINT("LockCheckConflicts: conflicting (simple)",
proclock);
- return STATUS_FOUND;
+ return true;
}
/*
@@ -1439,7 +1437,7 @@ LockCheckConflicts(LockMethod lockMethodTable,
{
PROCLOCK_PRINT("LockCheckConflicts: resolved (group)",
proclock);
- return STATUS_OK;
+ return false;
}
}
otherproclock = (PROCLOCK *)
@@ -1449,7 +1447,7 @@ LockCheckConflicts(LockMethod lockMethodTable,
/* Nope, it's a real conflict. */
PROCLOCK_PRINT("LockCheckConflicts: conflicting (group)", proclock);
- return STATUS_FOUND;
+ return true;
}
/*
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index fff0628e58..dbb541757f 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1149,10 +1149,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
}
/* I must go before this waiter. Check special case. */
if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&
- LockCheckConflicts(lockMethodTable,
- lockmode,
- lock,
- proclock) == STATUS_OK)
+ !LockCheckConflicts(lockMethodTable, lockmode, lock,
+ proclock))
{
/* Skip the wait and just grant myself the lock. */
GrantLock(lock, proclock, lockmode);
@@ -1648,10 +1646,8 @@ ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
* (b) doesn't conflict with already-held locks.
*/
if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&
- LockCheckConflicts(lockMethodTable,
- lockmode,
- lock,
- proc->waitProcLock) == STATUS_OK)
+ !LockCheckConflicts(lockMethodTable, lockmode, lock,
+ proc->waitProcLock))
{
/* OK to waken */
GrantLock(lock, proc->waitProcLock, lockmode);
diff --git a/src/include/c.h b/src/include/c.h
index 00e41ac546..eddeb36ca1 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1120,7 +1120,6 @@ typedef union PGAlignedXLogBlock
#define STATUS_OK (0)
#define STATUS_ERROR (-1)
#define STATUS_EOF (-2)
-#define STATUS_FOUND (1)
#define STATUS_WAITING (2)
/*
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index e8b50fe094..7978fcf216 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -550,7 +550,7 @@ extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
LOCKMODE lockmode, int *countp);
extern void AtPrepare_Locks(void);
extern void PostPrepare_Locks(TransactionId xid);
-extern int LockCheckConflicts(LockMethod lockMethodTable,
+extern bool LockCheckConflicts(LockMethod lockMethodTable,
LOCKMODE lockmode,
LOCK *lock, PROCLOCK *proclock);
extern void GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode);
--
2.24.1
0002-Remove-STATUS_WAITING.patchtext/plain; charset=UTF-8; name=0002-Remove-STATUS_WAITING.patch; x-mac-creator=0; x-mac-type=0Download
From 049fa9519d14b3b01bffbd219ebbc8340987f90e Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sun, 29 Dec 2019 09:09:20 +0100
Subject: [PATCH 2/4] Remove STATUS_WAITING
Add a separate enum for use in the locking APIs, which were the only
user.
---
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 529976885f..f8582d2cbb 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 e2c728a97d..33c9f471aa 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -1763,7 +1763,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
@@ -1814,7 +1814,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.
@@ -1830,7 +1830,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);
@@ -1853,7 +1853,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 dbb541757f..cdd6c8893a 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;
@@ -1155,7 +1155,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;
@@ -1189,7 +1189,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
@@ -1198,7 +1198,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 */
@@ -1230,7 +1230,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
@@ -1296,11 +1296,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
@@ -1481,24 +1481,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
@@ -1523,7 +1523,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,
@@ -1562,7 +1562,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();
/*
@@ -1584,10 +1584,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;
@@ -1595,7 +1595,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;
@@ -1651,7 +1651,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
@@ -1731,7 +1731,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 eddeb36ca1..f4b34cf243 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1120,7 +1120,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 281e1db725..180c2259d3 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 */
@@ -317,8 +324,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.24.1
On Sun, Dec 29, 2019 at 11:33:34AM +0100, Peter Eisentraut wrote:
Attached are two patches to remove these two symbols. STATUS_FOUND can be
replaced by a simple bool. STATUS_WAITING is replaced by a separate enum.
Patch 0001 looks good to me, but I got to wonder why the check after
waitMask in LockAcquireExtended() is not done directly in
LockCheckConflicts().
Regarding patch 0002, I am not sure that the addition of
ProcWaitStatus brings much though in terms of code readability.
--
Michael
On 2020-01-06 07:31, Michael Paquier wrote:
On Sun, Dec 29, 2019 at 11:33:34AM +0100, Peter Eisentraut wrote:
Attached are two patches to remove these two symbols. STATUS_FOUND can be
replaced by a simple bool. STATUS_WAITING is replaced by a separate enum.Patch 0001 looks good to me, but I got to wonder why the check after
waitMask in LockAcquireExtended() is not done directly in
LockCheckConflicts().
You mean put he subsequent GrantLock() calls into LockCheckConflicts()?
That would technically save some duplicate code, but it seems weird,
because LockCheckConflicts() is notionally a read-only function that
shouldn't change state.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Thu, Jan 09, 2020 at 11:15:08AM +0100, Peter Eisentraut wrote:
You mean put he subsequent GrantLock() calls into LockCheckConflicts()? That
would technically save some duplicate code, but it seems weird, because
LockCheckConflicts() is notionally a read-only function that shouldn't
change state.
Nah. I was thinking about the first part of this "if" clause
LockCheckConflicts is part of here:
if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
status = STATUS_FOUND;
else
status = LockCheckConflicts(lockMethodTable, lockmode,
lock, proclock);
But now that I look at it closely it messes up heavily with
ProcSleep() ;)
--
Michael
On 2020-01-10 06:23, Michael Paquier wrote:
On Thu, Jan 09, 2020 at 11:15:08AM +0100, Peter Eisentraut wrote:
You mean put he subsequent GrantLock() calls into LockCheckConflicts()? That
would technically save some duplicate code, but it seems weird, because
LockCheckConflicts() is notionally a read-only function that shouldn't
change state.Nah. I was thinking about the first part of this "if" clause
LockCheckConflicts is part of here:
if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
status = STATUS_FOUND;
else
status = LockCheckConflicts(lockMethodTable, lockmode,
lock, proclock);But now that I look at it closely it messes up heavily with
ProcSleep() ;)
OK, pushed as it was then.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Sat, Jan 11, 2020 at 08:14:17AM +0100, Peter Eisentraut wrote:
OK, pushed as it was then.
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.
--
Michael
At Thu, 16 Jan 2020 14:50:01 +0900, Michael Paquier <michael@paquier.xyz> wrote in
On Sat, Jan 11, 2020 at 08:14:17AM +0100, Peter Eisentraut wrote:
OK, pushed as it was then.
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.
I feel the same about the second patch.
Although actually STATUS_WAITING is used only by ProcSleep and related
functions, likewise STATUS_EOF is seen only in auth.c/h. Other files,
pqcomm.c, crypt.c postmaster.c, hba.c, fe-auth.c , fe-connect.c,
fe-gssapi-common.c are using only STATUS_OK and ERROR. I haven't had a
close look but all of the usages would be equivalent to bool.
On the other hand many functions in fe-*.c and pqcomm.c returns
EOF(-1)/0 instead of STATUS_EOF(-2)/STATUS_OK(0).
We could reorganize the values and their usage but it doesn't seem to
be a big win..
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
On Thu, Jan 16, 2020 at 12:50 AM Michael Paquier <michael@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.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On 2020-01-16 13:56, Robert Haas wrote:
On Thu, Jan 16, 2020 at 12:50 AM Michael Paquier <michael@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
Attachments:
v2-0001-Remove-STATUS_WAITING.patchtext/plain; charset=UTF-8; name=v2-0001-Remove-STATUS_WAITING.patch; x-mac-creator=0; x-mac-type=0Download
From 477515ea4b112e860587640f255cbfcdfee1755c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@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
On Thu, Jun 11, 2020 at 03:55:59PM +0200, Peter Eisentraut wrote:
On 2020-01-16 13:56, Robert Haas wrote:
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.
I am still in a so-so state regarding this patch, but I find the
debugger argument a good one. And please don't consider me as a
blocker.
Add a separate enum for use in the locking APIs, which were the only
user.
+typedef enum +{ + PROC_WAIT_STATUS_OK, + PROC_WAIT_STATUS_WAITING, + PROC_WAIT_STATUS_ERROR, +} ProcWaitStatus;
ProcWaitStatus, and more particularly PROC_WAIT_STATUS_WAITING are
strange names (the latter refers to "wait" twice). What do you think
about renaming the enum to ProcStatus and the flags to PROC_STATUS_*?
--
Michael
On 2020-06-12 09:30, Michael Paquier wrote:
On Thu, Jun 11, 2020 at 03:55:59PM +0200, Peter Eisentraut wrote:
On 2020-01-16 13:56, Robert Haas wrote:
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.I am still in a so-so state regarding this patch, but I find the
debugger argument a good one. And please don't consider me as a
blocker.
Okay, I have committed it.
Add a separate enum for use in the locking APIs, which were the only
user.+typedef enum +{ + PROC_WAIT_STATUS_OK, + PROC_WAIT_STATUS_WAITING, + PROC_WAIT_STATUS_ERROR, +} ProcWaitStatus;ProcWaitStatus, and more particularly PROC_WAIT_STATUS_WAITING are
strange names (the latter refers to "wait" twice). What do you think
about renaming the enum to ProcStatus and the flags to PROC_STATUS_*?
I see your point, but I don't think that's better. That would just
invite someone else to use it for other process-related status things.
We typically name enum constants like the type followed by a suffix.
The fact that the suffix is similar to the prefix here is more of a
coincidence.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services