Commit e84c4290 authored by Tom Lane's avatar Tom Lane

Clean up lockmanager data structures some more, in preparation for planned

rewrite of deadlock checking.  Lock holder objects are now reachable from
the associated LOCK as well as from the owning PROC.  This makes it
practical to find all the processes holding a lock, as well as all those
waiting on the lock.  Also, clean up some of the grottier aspects of the
SHMQueue API, and cause the waitProcs list to be stored in the intuitive
direction instead of the nonintuitive one.  (Bet you didn't know that
the code followed the 'prev' link to get to the next waiting process,
instead of the 'next' link.  It doesn't do that anymore.)
parent 56f5f2bf
...@@ -8,32 +8,34 @@ ...@@ -8,32 +8,34 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.13 2000/01/26 05:56:58 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.14 2001/01/22 22:30:06 tgl Exp $
* *
* NOTES * NOTES
* *
* Package for managing doubly-linked lists in shared memory. * Package for managing doubly-linked lists in shared memory.
* The only tricky thing is that SHM_QUEUE will usually be a field * The only tricky thing is that SHM_QUEUE will usually be a field
* in a larger record. SHMQueueGetFirst has to return a pointer * in a larger record. SHMQueueNext has to return a pointer
* to the record itself instead of a pointer to the SHMQueue field * to the record itself instead of a pointer to the SHMQueue field
* of the record. It takes an extra pointer and does some extra * of the record. It takes an extra parameter and does some extra
* pointer arithmetic to do this correctly. * pointer arithmetic to do this correctly.
* *
* NOTE: These are set up so they can be turned into macros some day. * NOTE: These are set up so they can be turned into macros some day.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "storage/shmem.h" #include "storage/shmem.h"
/*#define SHMQUEUE_DEBUG*/ /*#define SHMQUEUE_DEBUG*/
#ifdef SHMQUEUE_DEBUG #ifdef SHMQUEUE_DEBUG
#define SHMQUEUE_DEBUG_DEL /* deletions */
#define SHMQUEUE_DEBUG_HD /* head inserts */
#define SHMQUEUE_DEBUG_TL /* tail inserts */
#define SHMQUEUE_DEBUG_ELOG NOTICE #define SHMQUEUE_DEBUG_ELOG NOTICE
#endif /* SHMQUEUE_DEBUG */
static void dumpQ(SHM_QUEUE *q, char *s);
#endif
/* /*
* ShmemQueueInit -- make the head of a new queue point * ShmemQueueInit -- make the head of a new queue point
...@@ -84,76 +86,23 @@ SHMQueueDelete(SHM_QUEUE *queue) ...@@ -84,76 +86,23 @@ SHMQueueDelete(SHM_QUEUE *queue)
Assert(SHM_PTR_VALID(nextElem)); Assert(SHM_PTR_VALID(nextElem));
Assert(SHM_PTR_VALID(prevElem)); Assert(SHM_PTR_VALID(prevElem));
#ifdef SHMQUEUE_DEBUG_DEL #ifdef SHMQUEUE_DEBUG
dumpQ(queue, "in SHMQueueDelete: begin"); dumpQ(queue, "in SHMQueueDelete: begin");
#endif /* SHMQUEUE_DEBUG_DEL */ #endif
prevElem->next = (queue)->next; prevElem->next = (queue)->next;
nextElem->prev = (queue)->prev; nextElem->prev = (queue)->prev;
#ifdef SHMQUEUE_DEBUG_DEL (queue)->prev = (queue)->next = INVALID_OFFSET;
dumpQ((SHM_QUEUE *) MAKE_PTR(queue->prev), "in SHMQueueDelete: end");
#endif /* SHMQUEUE_DEBUG_DEL */
}
#ifdef SHMQUEUE_DEBUG
void
dumpQ(SHM_QUEUE *q, char *s)
{
char elem[NAMEDATALEN];
char buf[1024];
SHM_QUEUE *start = q;
int count = 0;
sprintf(buf, "q prevs: %x", MAKE_OFFSET(q));
q = (SHM_QUEUE *) MAKE_PTR(q->prev);
while (q != start)
{
sprintf(elem, "--->%x", MAKE_OFFSET(q));
strcat(buf, elem);
q = (SHM_QUEUE *) MAKE_PTR(q->prev);
if (q->prev == MAKE_OFFSET(q))
break;
if (count++ > 40)
{
strcat(buf, "BAD PREV QUEUE!!");
break;
}
}
sprintf(elem, "--->%x", MAKE_OFFSET(q));
strcat(buf, elem);
elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
sprintf(buf, "q nexts: %x", MAKE_OFFSET(q));
count = 0;
q = (SHM_QUEUE *) MAKE_PTR(q->next);
while (q != start)
{
sprintf(elem, "--->%x", MAKE_OFFSET(q));
strcat(buf, elem);
q = (SHM_QUEUE *) MAKE_PTR(q->next);
if (q->next == MAKE_OFFSET(q))
break;
if (count++ > 10)
{
strcat(buf, "BAD NEXT QUEUE!!");
break;
}
}
sprintf(elem, "--->%x", MAKE_OFFSET(q));
strcat(buf, elem);
elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
} }
#endif /* SHMQUEUE_DEBUG */
/* /*
* SHMQueueInsertHD -- put elem in queue between the queue head * SHMQueueInsertBefore -- put elem in queue before the given queue
* and its "prev" element. * element. Inserting "before" the queue head puts the elem
* at the tail of the queue.
*/ */
#ifdef NOT_USED
void void
SHMQueueInsertHD(SHM_QUEUE *queue, SHM_QUEUE *elem) SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
{ {
SHM_QUEUE *prevPtr = (SHM_QUEUE *) MAKE_PTR((queue)->prev); SHM_QUEUE *prevPtr = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem); SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
...@@ -161,24 +110,28 @@ SHMQueueInsertHD(SHM_QUEUE *queue, SHM_QUEUE *elem) ...@@ -161,24 +110,28 @@ SHMQueueInsertHD(SHM_QUEUE *queue, SHM_QUEUE *elem)
Assert(SHM_PTR_VALID(queue)); Assert(SHM_PTR_VALID(queue));
Assert(SHM_PTR_VALID(elem)); Assert(SHM_PTR_VALID(elem));
#ifdef SHMQUEUE_DEBUG_HD #ifdef SHMQUEUE_DEBUG
dumpQ(queue, "in SHMQueueInsertHD: begin"); dumpQ(queue, "in SHMQueueInsertBefore: begin");
#endif /* SHMQUEUE_DEBUG_HD */ #endif
(elem)->next = prevPtr->next; (elem)->next = prevPtr->next;
(elem)->prev = queue->prev; (elem)->prev = queue->prev;
(queue)->prev = elemOffset; (queue)->prev = elemOffset;
prevPtr->next = elemOffset; prevPtr->next = elemOffset;
#ifdef SHMQUEUE_DEBUG_HD #ifdef SHMQUEUE_DEBUG
dumpQ(queue, "in SHMQueueInsertHD: end"); dumpQ(queue, "in SHMQueueInsertBefore: end");
#endif /* SHMQUEUE_DEBUG_HD */
}
#endif #endif
}
/*
* SHMQueueInsertAfter -- put elem in queue after the given queue
* element. Inserting "after" the queue head puts the elem
* at the head of the queue.
*/
#ifdef NOT_USED
void void
SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem) SHMQueueInsertAfter(SHM_QUEUE *queue, SHM_QUEUE *elem)
{ {
SHM_QUEUE *nextPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next); SHM_QUEUE *nextPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem); SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
...@@ -186,58 +139,55 @@ SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem) ...@@ -186,58 +139,55 @@ SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem)
Assert(SHM_PTR_VALID(queue)); Assert(SHM_PTR_VALID(queue));
Assert(SHM_PTR_VALID(elem)); Assert(SHM_PTR_VALID(elem));
#ifdef SHMQUEUE_DEBUG_TL #ifdef SHMQUEUE_DEBUG
dumpQ(queue, "in SHMQueueInsertTL: begin"); dumpQ(queue, "in SHMQueueInsertAfter: begin");
#endif /* SHMQUEUE_DEBUG_TL */ #endif
(elem)->prev = nextPtr->prev; (elem)->prev = nextPtr->prev;
(elem)->next = queue->next; (elem)->next = queue->next;
(queue)->next = elemOffset; (queue)->next = elemOffset;
nextPtr->prev = elemOffset; nextPtr->prev = elemOffset;
#ifdef SHMQUEUE_DEBUG_TL #ifdef SHMQUEUE_DEBUG
dumpQ(queue, "in SHMQueueInsertTL: end"); dumpQ(queue, "in SHMQueueInsertAfter: end");
#endif /* SHMQUEUE_DEBUG_TL */ #endif
} }
#endif /* NOT_USED */
/* /*--------------------
* SHMQueueFirst -- Get the first element from a queue * SHMQueueNext -- Get the next element from a queue
* *
* First element is queue->next. If SHMQueue is part of * To start the iteration, pass the queue head as both queue and curElem.
* Returns NULL if no more elements.
*
* Next element is at curElem->next. If SHMQueue is part of
* a larger structure, we want to return a pointer to the * a larger structure, we want to return a pointer to the
* whole structure rather than a pointer to its SHMQueue field. * whole structure rather than a pointer to its SHMQueue field.
* I.E. struct { * I.E. struct {
* int stuff; * int stuff;
* SHMQueue elem; * SHMQueue elem;
* } ELEMType; * } ELEMType;
* when this element is in a queue (queue->next) is struct.elem. * When this element is in a queue, (prevElem->next) is struct.elem.
* nextQueue allows us to calculate the offset of the SHMQueue * We subtract linkOffset to get the correct start address of the structure.
* field in the structure.
*
* call to SHMQueueFirst should take these parameters:
* *
* &(queueHead),&firstElem,&(firstElem->next) * calls to SHMQueueNext should take these parameters:
* *
* Note that firstElem may well be uninitialized. if firstElem * &(queueHead), &(queueHead), offsetof(ELEMType, elem)
* is initially K, &(firstElem->next) will be K+ the offset to * or
* next. * &(queueHead), &(curElem->elem), offsetof(ELEMType, elem)
*--------------------
*/ */
void Pointer
SHMQueueFirst(SHM_QUEUE *queue, Pointer *nextPtrPtr, SHM_QUEUE *nextQueue) SHMQueueNext(SHM_QUEUE *queue, SHM_QUEUE *curElem, Size linkOffset)
{ {
SHM_QUEUE *elemPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next); SHM_QUEUE *elemPtr = (SHM_QUEUE *) MAKE_PTR((curElem)->next);
Assert(SHM_PTR_VALID(queue)); Assert(SHM_PTR_VALID(curElem));
*nextPtrPtr = (Pointer) (((unsigned long) *nextPtrPtr) +
((unsigned long) elemPtr) - ((unsigned long) nextQueue)); if (elemPtr == queue) /* back to the queue head? */
return NULL;
/*
* nextPtrPtr a ptr to a structure linked in the queue nextQueue is return (Pointer) (((char *) elemPtr) - linkOffset);
* the SHMQueue field of the structure nextPtrPtr - nextQueue is 0
* minus the offset of the queue field n the record elemPtr +
* (*nextPtrPtr - nexQueue) is the start of the structure containing
* elemPtr.
*/
} }
/* /*
...@@ -255,3 +205,55 @@ SHMQueueEmpty(SHM_QUEUE *queue) ...@@ -255,3 +205,55 @@ SHMQueueEmpty(SHM_QUEUE *queue)
} }
return FALSE; return FALSE;
} }
#ifdef SHMQUEUE_DEBUG
static void
dumpQ(SHM_QUEUE *q, char *s)
{
char elem[NAMEDATALEN];
char buf[1024];
SHM_QUEUE *start = q;
int count = 0;
sprintf(buf, "q prevs: %lx", MAKE_OFFSET(q));
q = (SHM_QUEUE *) MAKE_PTR(q->prev);
while (q != start)
{
sprintf(elem, "--->%lx", MAKE_OFFSET(q));
strcat(buf, elem);
q = (SHM_QUEUE *) MAKE_PTR(q->prev);
if (q->prev == MAKE_OFFSET(q))
break;
if (count++ > 40)
{
strcat(buf, "BAD PREV QUEUE!!");
break;
}
}
sprintf(elem, "--->%lx", MAKE_OFFSET(q));
strcat(buf, elem);
elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
sprintf(buf, "q nexts: %lx", MAKE_OFFSET(q));
count = 0;
q = (SHM_QUEUE *) MAKE_PTR(q->next);
while (q != start)
{
sprintf(elem, "--->%lx", MAKE_OFFSET(q));
strcat(buf, elem);
q = (SHM_QUEUE *) MAKE_PTR(q->next);
if (q->next == MAKE_OFFSET(q))
break;
if (count++ > 10)
{
strcat(buf, "BAD NEXT QUEUE!!");
break;
}
}
sprintf(elem, "--->%lx", MAKE_OFFSET(q));
strcat(buf, elem);
elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
}
#endif /* SHMQUEUE_DEBUG */
This diff is collapsed.
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.94 2001/01/16 20:59:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.95 2001/01/22 22:30:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
* This is so that we can support more backends. (system-wide semaphore * This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95 * sets run out pretty fast.) -ay 4/95
* *
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.94 2001/01/16 20:59:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.95 2001/01/22 22:30:06 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -228,9 +228,6 @@ InitProcess(void) ...@@ -228,9 +228,6 @@ InitProcess(void)
SpinRelease(ProcStructLock); SpinRelease(ProcStructLock);
elog(FATAL, "cannot create new proc: out of memory"); elog(FATAL, "cannot create new proc: out of memory");
} }
/* this cannot be initialized until after the buffer pool */
SHMQueueInit(&(MyProc->holderQueue));
} }
/* /*
...@@ -259,10 +256,15 @@ InitProcess(void) ...@@ -259,10 +256,15 @@ InitProcess(void)
MyProc->sem.semNum = -1; MyProc->sem.semNum = -1;
} }
SHMQueueElemInit(&(MyProc->links));
MyProc->errType = NO_ERROR;
MyProc->pid = MyProcPid; MyProc->pid = MyProcPid;
MyProc->databaseId = MyDatabaseId; MyProc->databaseId = MyDatabaseId;
MyProc->xid = InvalidTransactionId; MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId; MyProc->xmin = InvalidTransactionId;
MyProc->waitLock = NULL;
MyProc->waitHolder = NULL;
SHMQueueInit(&(MyProc->procHolders));
/* ---------------------- /* ----------------------
* Release the lock. * Release the lock.
...@@ -282,9 +284,6 @@ InitProcess(void) ...@@ -282,9 +284,6 @@ InitProcess(void)
(location != MAKE_OFFSET(MyProc))) (location != MAKE_OFFSET(MyProc)))
elog(STOP, "InitProcess: ShmemPID table broken"); elog(STOP, "InitProcess: ShmemPID table broken");
MyProc->errType = NO_ERROR;
SHMQueueElemInit(&(MyProc->links));
on_shmem_exit(ProcKill, 0); on_shmem_exit(ProcKill, 0);
} }
...@@ -342,7 +341,6 @@ RemoveFromWaitQueue(PROC *proc) ...@@ -342,7 +341,6 @@ RemoveFromWaitQueue(PROC *proc)
waitLock->waitMask &= ~(1 << lockmode); waitLock->waitMask &= ~(1 << lockmode);
/* Clean up the proc's own state */ /* Clean up the proc's own state */
SHMQueueElemInit(&(proc->links));
proc->waitLock = NULL; proc->waitLock = NULL;
proc->waitHolder = NULL; proc->waitHolder = NULL;
...@@ -451,6 +449,7 @@ ProcRemove(int pid) ...@@ -451,6 +449,7 @@ ProcRemove(int pid)
ProcFreeSem(proc->sem.semId, proc->sem.semNum); ProcFreeSem(proc->sem.semId, proc->sem.semNum);
/* Add PROC struct to freelist so space can be recycled in future */
proc->links.next = ProcGlobal->freeProcs; proc->links.next = ProcGlobal->freeProcs;
ProcGlobal->freeProcs = MAKE_OFFSET(proc); ProcGlobal->freeProcs = MAKE_OFFSET(proc);
...@@ -565,12 +564,7 @@ ProcSleep(LOCKMETHODCTL *lockctl, ...@@ -565,12 +564,7 @@ ProcSleep(LOCKMETHODCTL *lockctl,
bigtime_t time_interval; bigtime_t time_interval;
#endif #endif
MyProc->waitLock = lock; proc = (PROC *) MAKE_PTR(waitQueue->links.next);
MyProc->waitHolder = holder;
MyProc->waitLockMode = lockmode;
/* We assume the caller set up MyProc->heldLocks */
proc = (PROC *) MAKE_PTR(waitQueue->links.prev);
/* if we don't conflict with any waiter - be first in queue */ /* if we don't conflict with any waiter - be first in queue */
if (!(lockctl->conflictTab[lockmode] & waitMask)) if (!(lockctl->conflictTab[lockmode] & waitMask))
...@@ -593,7 +587,7 @@ ProcSleep(LOCKMETHODCTL *lockctl, ...@@ -593,7 +587,7 @@ ProcSleep(LOCKMETHODCTL *lockctl,
{ {
/* Yes, report deadlock failure */ /* Yes, report deadlock failure */
MyProc->errType = STATUS_ERROR; MyProc->errType = STATUS_ERROR;
goto rt; return STATUS_ERROR;
} }
/* I must go after him in queue - so continue loop */ /* I must go after him in queue - so continue loop */
} }
...@@ -624,20 +618,25 @@ ProcSleep(LOCKMETHODCTL *lockctl, ...@@ -624,20 +618,25 @@ ProcSleep(LOCKMETHODCTL *lockctl,
(aheadGranted[procWaitMode])++; (aheadGranted[procWaitMode])++;
if (aheadGranted[procWaitMode] == lock->requested[procWaitMode]) if (aheadGranted[procWaitMode] == lock->requested[procWaitMode])
waitMask &= ~(1 << procWaitMode); waitMask &= ~(1 << procWaitMode);
proc = (PROC *) MAKE_PTR(proc->links.prev); proc = (PROC *) MAKE_PTR(proc->links.next);
} }
ins:; ins:;
/* ------------------- /* -------------------
* Insert self into queue, ahead of the given proc. * Insert self into queue, ahead of the given proc (or at tail of queue).
* These operations are atomic (because of the spinlock).
* ------------------- * -------------------
*/ */
SHMQueueInsertTL(&(proc->links), &(MyProc->links)); SHMQueueInsertBefore(&(proc->links), &(MyProc->links));
waitQueue->size++; waitQueue->size++;
lock->waitMask |= myMask; lock->waitMask |= myMask;
/* Set up wait information in PROC object, too */
MyProc->waitLock = lock;
MyProc->waitHolder = holder;
MyProc->waitLockMode = lockmode;
/* We assume the caller set up MyProc->heldLocks */
MyProc->errType = NO_ERROR; /* initialize result for success */ MyProc->errType = NO_ERROR; /* initialize result for success */
/* mark that we are waiting for a lock */ /* mark that we are waiting for a lock */
...@@ -723,11 +722,10 @@ ins:; ...@@ -723,11 +722,10 @@ ins:;
*/ */
SpinAcquire(spinlock); SpinAcquire(spinlock);
rt:; /*
* We don't have to do anything else, because the awaker did all the
MyProc->waitLock = NULL; * necessary update of the lock table and MyProc.
MyProc->waitHolder = NULL; */
return MyProc->errType; return MyProc->errType;
} }
...@@ -745,18 +743,24 @@ ProcWakeup(PROC *proc, int errType) ...@@ -745,18 +743,24 @@ ProcWakeup(PROC *proc, int errType)
/* assume that spinlock has been acquired */ /* assume that spinlock has been acquired */
/* Proc should be sleeping ... */
if (proc->links.prev == INVALID_OFFSET || if (proc->links.prev == INVALID_OFFSET ||
proc->links.next == INVALID_OFFSET) proc->links.next == INVALID_OFFSET)
return (PROC *) NULL; return (PROC *) NULL;
retProc = (PROC *) MAKE_PTR(proc->links.prev); /* Save next process before we zap the list link */
retProc = (PROC *) MAKE_PTR(proc->links.next);
/* Remove process from wait queue */
SHMQueueDelete(&(proc->links)); SHMQueueDelete(&(proc->links));
SHMQueueElemInit(&(proc->links));
(proc->waitLock->waitProcs.size)--; (proc->waitLock->waitProcs.size)--;
/* Clean up process' state and pass it the ok/fail signal */
proc->waitLock = NULL;
proc->waitHolder = NULL;
proc->errType = errType; proc->errType = errType;
/* And awaken it */
IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum); IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum);
return retProc; return retProc;
...@@ -780,7 +784,7 @@ ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock) ...@@ -780,7 +784,7 @@ ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock)
if (!queue_size) if (!queue_size)
return STATUS_NOT_FOUND; return STATUS_NOT_FOUND;
proc = (PROC *) MAKE_PTR(queue->links.prev); proc = (PROC *) MAKE_PTR(queue->links.next);
while (queue_size-- > 0) while (queue_size-- > 0)
{ {
...@@ -820,12 +824,13 @@ ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock) ...@@ -820,12 +824,13 @@ ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock)
/* /*
* ProcWakeup removes proc from the lock's waiting process queue * ProcWakeup removes proc from the lock's waiting process queue
* and returns the next proc in chain; don't use prev link. * and returns the next proc in chain; don't use proc's next-link,
* because it's been cleared.
*/ */
continue; continue;
nextProc: nextProc:
proc = (PROC *) MAKE_PTR(proc->links.prev); proc = (PROC *) MAKE_PTR(proc->links.next);
} }
Assert(queue->size >= 0); Assert(queue->size >= 0);
...@@ -848,12 +853,6 @@ nextProc: ...@@ -848,12 +853,6 @@ nextProc:
} }
} }
void
ProcAddLock(SHM_QUEUE *elem)
{
SHMQueueInsertTL(&MyProc->holderQueue, elem);
}
/* -------------------- /* --------------------
* We only get to this routine if we got SIGALRM after DeadlockTimeout * We only get to this routine if we got SIGALRM after DeadlockTimeout
* while waiting for a lock to be released by some other process. Look * while waiting for a lock to be released by some other process. Look
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: lock.h,v 1.41 2001/01/16 06:11:34 tgl Exp $ * $Id: lock.h,v 1.42 2001/01/22 22:30:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
/* originally in procq.h */ /* originally in procq.h */
typedef struct PROC_QUEUE typedef struct PROC_QUEUE
{ {
SHM_QUEUE links; SHM_QUEUE links; /* head of list of PROC objects */
int size; int size; /* number of entries in list */
} PROC_QUEUE; } PROC_QUEUE;
/* struct proc is declared in storage/proc.h, but must forward-reference it */ /* struct proc is declared in storage/proc.h, but must forward-reference it */
...@@ -59,7 +59,7 @@ typedef int LOCKMASK; ...@@ -59,7 +59,7 @@ typedef int LOCKMASK;
typedef int LOCKMODE; typedef int LOCKMODE;
typedef int LOCKMETHOD; typedef int LOCKMETHOD;
/* MAX_LOCKMODES cannot be larger than the bits in LOCKMASK */ /* MAX_LOCKMODES cannot be larger than the # of bits in LOCKMASK */
#define MAX_LOCKMODES 8 #define MAX_LOCKMODES 8
/* /*
...@@ -152,6 +152,7 @@ typedef struct LOCKTAG ...@@ -152,6 +152,7 @@ typedef struct LOCKTAG
* tag -- uniquely identifies the object being locked * tag -- uniquely identifies the object being locked
* grantMask -- bitmask for all lock types currently granted on this object. * grantMask -- bitmask for all lock types currently granted on this object.
* waitMask -- bitmask for all lock types currently awaited on this object. * waitMask -- bitmask for all lock types currently awaited on this object.
* lockHolders -- list of HOLDER objects for this lock.
* waitProcs -- queue of processes waiting for this lock. * waitProcs -- queue of processes waiting for this lock.
* requested -- count of each lock type currently requested on the lock * requested -- count of each lock type currently requested on the lock
* (includes requests already granted!!). * (includes requests already granted!!).
...@@ -167,6 +168,7 @@ typedef struct LOCK ...@@ -167,6 +168,7 @@ typedef struct LOCK
/* data */ /* data */
int grantMask; /* bitmask for lock types already granted */ int grantMask; /* bitmask for lock types already granted */
int waitMask; /* bitmask for lock types awaited */ int waitMask; /* bitmask for lock types awaited */
SHM_QUEUE lockHolders; /* list of HOLDER objects assoc. with lock */
PROC_QUEUE waitProcs; /* list of PROC objects waiting on lock */ PROC_QUEUE waitProcs; /* list of PROC objects waiting on lock */
int requested[MAX_LOCKMODES]; /* counts of requested locks */ int requested[MAX_LOCKMODES]; /* counts of requested locks */
int nRequested; /* total of requested[] array */ int nRequested; /* total of requested[] array */
...@@ -189,8 +191,8 @@ typedef struct LOCK ...@@ -189,8 +191,8 @@ typedef struct LOCK
* holder hashtable. A HOLDERTAG value uniquely identifies a lock holder. * holder hashtable. A HOLDERTAG value uniquely identifies a lock holder.
* *
* There are two possible kinds of holder tags: a transaction (identified * There are two possible kinds of holder tags: a transaction (identified
* both by the PID of the backend running it, and the xact's own ID) and * both by the PROC of the backend running it, and the xact's own ID) and
* a session (identified by backend PID, with xid = InvalidTransactionId). * a session (identified by backend PROC, with xid = InvalidTransactionId).
* *
* Currently, session holders are used for user locks and for cross-xact * Currently, session holders are used for user locks and for cross-xact
* locks obtained for VACUUM. We assume that a session lock never conflicts * locks obtained for VACUUM. We assume that a session lock never conflicts
...@@ -201,11 +203,17 @@ typedef struct LOCK ...@@ -201,11 +203,17 @@ typedef struct LOCK
* zero holding[], for any lock that the process is currently waiting on. * zero holding[], for any lock that the process is currently waiting on.
* Otherwise, holder objects whose counts have gone to zero are recycled * Otherwise, holder objects whose counts have gone to zero are recycled
* as soon as convenient. * as soon as convenient.
*
* Each HOLDER object is linked into lists for both the associated LOCK object
* and the owning PROC object. Note that the HOLDER is entered into these
* lists as soon as it is created, even if no lock has yet been granted.
* A PROC that is waiting for a lock to be granted will also be linked into
* the lock's waitProcs queue.
*/ */
typedef struct HOLDERTAG typedef struct HOLDERTAG
{ {
SHMEM_OFFSET lock; /* link to per-lockable-object information */ SHMEM_OFFSET lock; /* link to per-lockable-object information */
int pid; /* PID of backend */ SHMEM_OFFSET proc; /* link to PROC of owning backend */
TransactionId xid; /* xact ID, or InvalidTransactionId */ TransactionId xid; /* xact ID, or InvalidTransactionId */
} HOLDERTAG; } HOLDERTAG;
...@@ -217,7 +225,8 @@ typedef struct HOLDER ...@@ -217,7 +225,8 @@ typedef struct HOLDER
/* data */ /* data */
int holding[MAX_LOCKMODES]; /* count of locks currently held */ int holding[MAX_LOCKMODES]; /* count of locks currently held */
int nHolding; /* total of holding[] array */ int nHolding; /* total of holding[] array */
SHM_QUEUE queue; /* list link for process' list of holders */ SHM_QUEUE lockLink; /* list link for lock's list of holders */
SHM_QUEUE procLink; /* list link for process's list of holders */
} HOLDER; } HOLDER;
#define SHMEM_HOLDERTAB_KEYSIZE sizeof(HOLDERTAG) #define SHMEM_HOLDERTAB_KEYSIZE sizeof(HOLDERTAG)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: proc.h,v 1.36 2001/01/16 20:59:34 tgl Exp $ * $Id: proc.h,v 1.37 2001/01/22 22:30:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,9 +27,8 @@ typedef struct ...@@ -27,9 +27,8 @@ typedef struct
} SEMA; } SEMA;
/* /*
* Each backend has a PROC struct in shared memory. There is also a list * Each backend has a PROC struct in shared memory. There is also a list of
* of currently-unused PROC structs that will be reallocated to new backends * currently-unused PROC structs that will be reallocated to new backends.
* (a fairly pointless optimization, but it's there anyway).
* *
* links: list link for any list the PROC is in. When waiting for a lock, * links: list link for any list the PROC is in. When waiting for a lock,
* the PROC is linked into that lock's waitProcs queue. A recycled PROC * the PROC is linked into that lock's waitProcs queue. A recycled PROC
...@@ -37,7 +36,7 @@ typedef struct ...@@ -37,7 +36,7 @@ typedef struct
*/ */
struct proc struct proc
{ {
/* proc->links MUST BE THE FIRST ELEMENT OF STRUCT (see ProcWakeup()) */ /* proc->links MUST BE FIRST IN STRUCT (see ProcSleep,ProcWakeup,etc) */
SHM_QUEUE links; /* list link if process is in a list */ SHM_QUEUE links; /* list link if process is in a list */
...@@ -53,7 +52,8 @@ struct proc ...@@ -53,7 +52,8 @@ struct proc
XLogRecPtr logRec; XLogRecPtr logRec;
/* Info about lock the process is currently waiting for, if any */ /* Info about lock the process is currently waiting for, if any. */
/* waitLock and waitHolder are NULL if not currently waiting. */
LOCK *waitLock; /* Lock object we're sleeping on ... */ LOCK *waitLock; /* Lock object we're sleeping on ... */
HOLDER *waitHolder; /* Per-holder info for awaited lock */ HOLDER *waitHolder; /* Per-holder info for awaited lock */
LOCKMODE waitLockMode; /* type of lock we're waiting for */ LOCKMODE waitLockMode; /* type of lock we're waiting for */
...@@ -64,7 +64,7 @@ struct proc ...@@ -64,7 +64,7 @@ struct proc
Oid databaseId; /* OID of database this backend is using */ Oid databaseId; /* OID of database this backend is using */
short sLocks[MAX_SPINS]; /* Spin lock stats */ short sLocks[MAX_SPINS]; /* Spin lock stats */
SHM_QUEUE holderQueue; /* list of HOLDER objects for locks held or SHM_QUEUE procHolders; /* list of HOLDER objects for locks held or
* awaited by this backend */ * awaited by this backend */
}; };
...@@ -138,7 +138,6 @@ extern int ProcSleep(LOCKMETHODCTL *lockctl, LOCKMODE lockmode, ...@@ -138,7 +138,6 @@ extern int ProcSleep(LOCKMETHODCTL *lockctl, LOCKMODE lockmode,
LOCK *lock, HOLDER *holder); LOCK *lock, HOLDER *holder);
extern PROC *ProcWakeup(PROC *proc, int errType); extern PROC *ProcWakeup(PROC *proc, int errType);
extern int ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock); extern int ProcLockWakeup(LOCKMETHOD lockmethod, LOCK *lock);
extern void ProcAddLock(SHM_QUEUE *elem);
extern void ProcReleaseSpins(PROC *proc); extern void ProcReleaseSpins(PROC *proc);
extern bool LockWaitCancel(void); extern bool LockWaitCancel(void);
extern void HandleDeadLock(SIGNAL_ARGS); extern void HandleDeadLock(SIGNAL_ARGS);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: shmem.h,v 1.24 2000/11/28 23:27:57 tgl Exp $ * $Id: shmem.h,v 1.25 2001/01/22 22:30:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -100,9 +100,9 @@ typedef struct ...@@ -100,9 +100,9 @@ typedef struct
extern void SHMQueueInit(SHM_QUEUE *queue); extern void SHMQueueInit(SHM_QUEUE *queue);
extern void SHMQueueElemInit(SHM_QUEUE *queue); extern void SHMQueueElemInit(SHM_QUEUE *queue);
extern void SHMQueueDelete(SHM_QUEUE *queue); extern void SHMQueueDelete(SHM_QUEUE *queue);
extern void SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem); extern void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem);
extern void SHMQueueFirst(SHM_QUEUE *queue, Pointer *nextPtrPtr, extern Pointer SHMQueueNext(SHM_QUEUE *queue, SHM_QUEUE *curElem,
SHM_QUEUE *nextQueue); Size linkOffset);
extern bool SHMQueueEmpty(SHM_QUEUE *queue); extern bool SHMQueueEmpty(SHM_QUEUE *queue);
#endif /* SHMEM_H */ #endif /* SHMEM_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment