|
|
|
@ -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.
|
|
|
|
|
*/
|
|
|
|
|