mirror of
https://github.com/postgres/postgres.git
synced 2025-06-08 22:02:03 +03:00
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
This commit is contained in:
parent
42aa1f0ab3
commit
a513f1dfbf
@ -460,7 +460,7 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
|
|||||||
MemSet(proc, 0, sizeof(PGPROC));
|
MemSet(proc, 0, sizeof(PGPROC));
|
||||||
proc->pgprocno = gxact->pgprocno;
|
proc->pgprocno = gxact->pgprocno;
|
||||||
SHMQueueElemInit(&(proc->links));
|
SHMQueueElemInit(&(proc->links));
|
||||||
proc->waitStatus = STATUS_OK;
|
proc->waitStatus = PROC_WAIT_STATUS_OK;
|
||||||
/* We set up the gxact's VXID as InvalidBackendId/XID */
|
/* We set up the gxact's VXID as InvalidBackendId/XID */
|
||||||
proc->lxid = (LocalTransactionId) xid;
|
proc->lxid = (LocalTransactionId) xid;
|
||||||
pgxact->xid = xid;
|
pgxact->xid = xid;
|
||||||
|
@ -1856,7 +1856,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
|
|||||||
*/
|
*/
|
||||||
PG_TRY();
|
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
|
* 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).
|
* 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
|
* 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
|
* Appropriate partition lock must be held by caller. Also, caller is
|
||||||
* responsible for signaling the proc if needed.
|
* responsible for signaling the proc if needed.
|
||||||
@ -1923,7 +1923,7 @@ RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode)
|
|||||||
LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);
|
LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);
|
||||||
|
|
||||||
/* Make sure proc is waiting */
|
/* Make sure proc is waiting */
|
||||||
Assert(proc->waitStatus == STATUS_WAITING);
|
Assert(proc->waitStatus == PROC_WAIT_STATUS_WAITING);
|
||||||
Assert(proc->links.next != NULL);
|
Assert(proc->links.next != NULL);
|
||||||
Assert(waitLock);
|
Assert(waitLock);
|
||||||
Assert(waitLock->waitProcs.size > 0);
|
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 */
|
/* Clean up the proc's own state, and pass it the ok/fail signal */
|
||||||
proc->waitLock = NULL;
|
proc->waitLock = NULL;
|
||||||
proc->waitProcLock = 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.
|
* Delete the proclock immediately if it represents no already-held locks.
|
||||||
|
@ -383,7 +383,7 @@ InitProcess(void)
|
|||||||
* initialized by InitProcGlobal.
|
* initialized by InitProcGlobal.
|
||||||
*/
|
*/
|
||||||
SHMQueueElemInit(&(MyProc->links));
|
SHMQueueElemInit(&(MyProc->links));
|
||||||
MyProc->waitStatus = STATUS_OK;
|
MyProc->waitStatus = PROC_WAIT_STATUS_OK;
|
||||||
MyProc->lxid = InvalidLocalTransactionId;
|
MyProc->lxid = InvalidLocalTransactionId;
|
||||||
MyProc->fpVXIDLock = false;
|
MyProc->fpVXIDLock = false;
|
||||||
MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
|
MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
|
||||||
@ -567,7 +567,7 @@ InitAuxiliaryProcess(void)
|
|||||||
* initialized by InitProcGlobal.
|
* initialized by InitProcGlobal.
|
||||||
*/
|
*/
|
||||||
SHMQueueElemInit(&(MyProc->links));
|
SHMQueueElemInit(&(MyProc->links));
|
||||||
MyProc->waitStatus = STATUS_OK;
|
MyProc->waitStatus = PROC_WAIT_STATUS_OK;
|
||||||
MyProc->lxid = InvalidLocalTransactionId;
|
MyProc->lxid = InvalidLocalTransactionId;
|
||||||
MyProc->fpVXIDLock = false;
|
MyProc->fpVXIDLock = false;
|
||||||
MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
|
MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
|
||||||
@ -755,7 +755,7 @@ LockErrorCleanup(void)
|
|||||||
* did grant us the lock, we'd better remember it in our local lock
|
* did grant us the lock, we'd better remember it in our local lock
|
||||||
* table.
|
* table.
|
||||||
*/
|
*/
|
||||||
if (MyProc->waitStatus == STATUS_OK)
|
if (MyProc->waitStatus == PROC_WAIT_STATUS_OK)
|
||||||
GrantAwaitedLock();
|
GrantAwaitedLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1051,14 +1051,14 @@ ProcQueueInit(PROC_QUEUE *queue)
|
|||||||
* The lock table's partition lock must be held at entry, and will be held
|
* The lock table's partition lock must be held at entry, and will be held
|
||||||
* at exit.
|
* 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
|
* ASSUME: that no one will fiddle with the queue until after
|
||||||
* we release the partition lock.
|
* we release the partition lock.
|
||||||
*
|
*
|
||||||
* NOTES: The process queue is now a priority queue for locking.
|
* NOTES: The process queue is now a priority queue for locking.
|
||||||
*/
|
*/
|
||||||
int
|
ProcWaitStatus
|
||||||
ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
||||||
{
|
{
|
||||||
LOCKMODE lockmode = locallock->tag.mode;
|
LOCKMODE lockmode = locallock->tag.mode;
|
||||||
@ -1070,7 +1070,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
|||||||
LOCKMASK myHeldLocks = MyProc->heldLocks;
|
LOCKMASK myHeldLocks = MyProc->heldLocks;
|
||||||
bool early_deadlock = false;
|
bool early_deadlock = false;
|
||||||
bool allow_autovacuum_cancel = true;
|
bool allow_autovacuum_cancel = true;
|
||||||
int myWaitStatus;
|
ProcWaitStatus myWaitStatus;
|
||||||
PGPROC *proc;
|
PGPROC *proc;
|
||||||
PGPROC *leader = MyProc->lockGroupLeader;
|
PGPROC *leader = MyProc->lockGroupLeader;
|
||||||
int i;
|
int i;
|
||||||
@ -1161,7 +1161,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
|||||||
/* Skip the wait and just grant myself the lock. */
|
/* Skip the wait and just grant myself the lock. */
|
||||||
GrantLock(lock, proclock, lockmode);
|
GrantLock(lock, proclock, lockmode);
|
||||||
GrantAwaitedLock();
|
GrantAwaitedLock();
|
||||||
return STATUS_OK;
|
return PROC_WAIT_STATUS_OK;
|
||||||
}
|
}
|
||||||
/* Break out of loop to put myself before him */
|
/* Break out of loop to put myself before him */
|
||||||
break;
|
break;
|
||||||
@ -1195,7 +1195,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
|||||||
MyProc->waitProcLock = proclock;
|
MyProc->waitProcLock = proclock;
|
||||||
MyProc->waitLockMode = lockmode;
|
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
|
* If we detected deadlock, give up without waiting. This must agree with
|
||||||
@ -1204,7 +1204,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
|||||||
if (early_deadlock)
|
if (early_deadlock)
|
||||||
{
|
{
|
||||||
RemoveFromWaitQueue(MyProc, hashcode);
|
RemoveFromWaitQueue(MyProc, hashcode);
|
||||||
return STATUS_ERROR;
|
return PROC_WAIT_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mark that we are waiting for a lock */
|
/* 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
|
* Set timer so we can wake up after awhile and check for a deadlock. If a
|
||||||
* deadlock is detected, the handler sets MyProc->waitStatus =
|
* 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.
|
* than success.
|
||||||
*
|
*
|
||||||
* By delaying the check until we've waited for a bit, we can avoid
|
* 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
|
* asynchronously. Read it just once per loop to prevent surprising
|
||||||
* behavior (such as missing log messages).
|
* 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
|
* 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))));
|
lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myWaitStatus == STATUS_WAITING)
|
if (myWaitStatus == PROC_WAIT_STATUS_WAITING)
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("process %d still waiting for %s on %s after %ld.%03d ms",
|
(errmsg("process %d still waiting for %s on %s after %ld.%03d ms",
|
||||||
MyProcPid, modename, buf.data, msecs, usecs),
|
MyProcPid, modename, buf.data, msecs, usecs),
|
||||||
(errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.",
|
(errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.",
|
||||||
"Processes holding the lock: %s. Wait queue: %s.",
|
"Processes holding the lock: %s. Wait queue: %s.",
|
||||||
lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
|
lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data))));
|
||||||
else if (myWaitStatus == STATUS_OK)
|
else if (myWaitStatus == PROC_WAIT_STATUS_OK)
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("process %d acquired %s on %s after %ld.%03d ms",
|
(errmsg("process %d acquired %s on %s after %ld.%03d ms",
|
||||||
MyProcPid, modename, buf.data, msecs, usecs)));
|
MyProcPid, modename, buf.data, msecs, usecs)));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Assert(myWaitStatus == STATUS_ERROR);
|
Assert(myWaitStatus == PROC_WAIT_STATUS_ERROR);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Currently, the deadlock checker always kicks its own
|
* 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
|
* deadlock_state == DS_HARD_DEADLOCK, and there's no need to
|
||||||
* print redundant messages. But for completeness and
|
* print redundant messages. But for completeness and
|
||||||
* future-proofing, print a message if it looks like someone
|
* 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_holders_sbuf.data);
|
||||||
pfree(lock_waiters_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,
|
* 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 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();
|
GrantAwaitedLock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1590,10 +1590,10 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
|||||||
* XXX: presently, this code is only used for the "success" case, and only
|
* 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
|
* works correctly for that case. To clean up in failure case, would need
|
||||||
* to twiddle the lock's request counts too --- see RemoveFromWaitQueue.
|
* 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 *
|
PGPROC *
|
||||||
ProcWakeup(PGPROC *proc, int waitStatus)
|
ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus)
|
||||||
{
|
{
|
||||||
PGPROC *retProc;
|
PGPROC *retProc;
|
||||||
|
|
||||||
@ -1601,7 +1601,7 @@ ProcWakeup(PGPROC *proc, int waitStatus)
|
|||||||
if (proc->links.prev == NULL ||
|
if (proc->links.prev == NULL ||
|
||||||
proc->links.next == NULL)
|
proc->links.next == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
Assert(proc->waitStatus == STATUS_WAITING);
|
Assert(proc->waitStatus == PROC_WAIT_STATUS_WAITING);
|
||||||
|
|
||||||
/* Save next process before we zap the list link */
|
/* Save next process before we zap the list link */
|
||||||
retProc = (PGPROC *) proc->links.next;
|
retProc = (PGPROC *) proc->links.next;
|
||||||
@ -1657,7 +1657,7 @@ ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
|
|||||||
{
|
{
|
||||||
/* OK to waken */
|
/* OK to waken */
|
||||||
GrantLock(lock, proc->waitProcLock, lockmode);
|
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
|
* 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
|
* preserve the flexibility to kill some other transaction than the
|
||||||
* one detecting the deadlock.)
|
* 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
|
* ProcSleep will report an error after we return from the signal
|
||||||
* handler.
|
* handler.
|
||||||
*/
|
*/
|
||||||
|
@ -1133,7 +1133,6 @@ typedef union PGAlignedXLogBlock
|
|||||||
#define STATUS_OK (0)
|
#define STATUS_OK (0)
|
||||||
#define STATUS_ERROR (-1)
|
#define STATUS_ERROR (-1)
|
||||||
#define STATUS_EOF (-2)
|
#define STATUS_EOF (-2)
|
||||||
#define STATUS_WAITING (2)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gettext support
|
* gettext support
|
||||||
|
@ -76,6 +76,13 @@ struct XidCache
|
|||||||
*/
|
*/
|
||||||
#define INVALID_PGPROCNO PG_INT32_MAX
|
#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
|
* 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.
|
* 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 */
|
PGPROC **procgloballist; /* procglobal list that owns this PGPROC */
|
||||||
|
|
||||||
PGSemaphore sem; /* ONE semaphore to sleep on */
|
PGSemaphore sem; /* ONE semaphore to sleep on */
|
||||||
int waitStatus; /* STATUS_WAITING, STATUS_OK or STATUS_ERROR */
|
ProcWaitStatus waitStatus;
|
||||||
|
|
||||||
Latch procLatch; /* generic latch for process */
|
Latch procLatch; /* generic latch for process */
|
||||||
|
|
||||||
@ -315,8 +322,8 @@ extern bool HaveNFreeProcs(int n);
|
|||||||
extern void ProcReleaseLocks(bool isCommit);
|
extern void ProcReleaseLocks(bool isCommit);
|
||||||
|
|
||||||
extern void ProcQueueInit(PROC_QUEUE *queue);
|
extern void ProcQueueInit(PROC_QUEUE *queue);
|
||||||
extern int ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable);
|
extern ProcWaitStatus ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable);
|
||||||
extern PGPROC *ProcWakeup(PGPROC *proc, int waitStatus);
|
extern PGPROC *ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus);
|
||||||
extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock);
|
extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock);
|
||||||
extern void CheckDeadLockAlert(void);
|
extern void CheckDeadLockAlert(void);
|
||||||
extern bool IsWaitingForLock(void);
|
extern bool IsWaitingForLock(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user