Commit 64e6c608 authored by Tom Lane's avatar Tom Lane

Rename fields of lock and lockholder structures to something a tad less

confusing, and clean up documentation.
parent 2dbc457e
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.4 2000/12/22 00:51:54 tgl Exp $ $Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.5 2001/01/16 06:11:34 tgl Exp $
There are two fundamental lock structures: the per-lockable-object LOCK There are two fundamental lock structures: the per-lockable-object LOCK
struct, and the per-lock-holder HOLDER struct. A LOCK object exists struct, and the per-lock-holder HOLDER struct. A LOCK object exists
...@@ -44,51 +44,52 @@ tag - ...@@ -44,51 +44,52 @@ tag -
only a single table (see Gray's paper on 2 phase locking if only a single table (see Gray's paper on 2 phase locking if
you are puzzled about how multi-level lock tables work). you are puzzled about how multi-level lock tables work).
mask - grantMask -
This field indicates what types of locks are currently held on the This bitmask indicates what types of locks are currently held on the
given lockable object. It is used (against the lock table's conflict given lockable object. It is used (against the lock table's conflict
table) to determine if the new lock request will conflict with existing table) to determine if a new lock request will conflict with existing
lock types held. Conficts are determined by bitwise AND operations lock types held. Conficts are determined by bitwise AND operations
between the mask and the conflict table entry for the given lock type between the grantMask and the conflict table entry for the requested
to be set. The current representation is that each bit (1 through 5) lock type. Bit i of grantMask is 1 if and only if granted[i] > 0.
is set when that lock type (WRITE, READ, WRITE INTENT, READ INTENT, EXTEND)
has been acquired for the lock. waitMask -
This bitmask shows the types of locks being waited for. Bit i of waitMask
is 1 if and only if requested[i] > granted[i].
waitProcs - waitProcs -
This is a shared memory queue of all process structures corresponding to This is a shared memory queue of all process structures corresponding to
a backend that is waiting (sleeping) until another backend releases this a backend that is waiting (sleeping) until another backend releases this
lock. The process structure holds the information needed to determine lock. The process structure holds the information needed to determine
if it should be woken up when this lock is released. If, for example, if it should be woken up when this lock is released.
we are releasing a read lock and the process is sleeping trying to acquire
a read lock then there is no point in waking it since the lock being
released isn't what caused it to sleep in the first place. There will
be more on this below (when I get to releasing locks and waking sleeping
process routines).
nHolding - nRequested -
Keeps a count of how many times this lock has been attempted to be Keeps a count of how many times this lock has been attempted to be
acquired. The count includes attempts by processes which were put acquired. The count includes attempts by processes which were put
to sleep due to conflicts. It also counts the same backend twice to sleep due to conflicts. It also counts the same backend twice
if, for example, a backend process first acquires a read and then if, for example, a backend process first acquires a read and then
acquires a write. acquires a write, or acquires a read lock twice.
holders - requested -
Keeps a count of how many locks of each type have been attempted. Only Keeps a count of how many locks of each type have been attempted. Only
elements 1 through MAX_LOCK_TYPES are used as they correspond to the lock elements 1 through MAX_LOCKMODES-1 are used as they correspond to the lock
type defined constants (WRITE through EXTEND). Summing the values of type defined constants. Summing the values of requested[] should come out
holders should come out equal to nHolding. equal to nRequested.
nActive - nGranted -
Keeps a count of how many times this lock has been succesfully acquired. Keeps count of how many times this lock has been successfully acquired.
This count does not include attempts that are waiting due to conflicts, This count does not include attempts that are waiting due to conflicts,
but can count the same backend twice (e.g. a read then a write -- since but can count the same backend twice (e.g. a read then a write -- since
its the same transaction this won't cause a conflict) its the same transaction this won't cause a conflict).
granted -
Keeps count of how many locks of each type are currently held. Once again
only elements 1 through MAX_LOCKMODES-1 are used (0 is not). Also, like
requested, summing the values of granted should total to the value
of nGranted.
activeHolders - We should always have 0 <= nGranted <= nRequested, and
Keeps a count of how locks of each type are currently held. Once again 0 <= granted[i] <= requested[i] for each i. If the request counts go to
only elements 1 through MAX_LOCK_TYPES are used (0 is not). Also, like zero, the lock object is no longer needed and can be freed.
holders, summing the values of activeHolders should total to the value
of nActive.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
...@@ -116,14 +117,12 @@ tag - ...@@ -116,14 +117,12 @@ tag -
are always session locks, and we also use session locks for multi- are always session locks, and we also use session locks for multi-
transaction operations like VACUUM. transaction operations like VACUUM.
holders - holding -
The number of successfully acquired locks of each type for this holder. The number of successfully acquired locks of each type for this holder.
(CAUTION: the semantics are not the same as the LOCK's holder[], which This should be <= the corresponding granted[] value of the lock object!
counts both acquired and pending requests. Probably a different name
should be used...)
nHolding - nHolding -
Sum of the holders[] array. Sum of the holding[] array.
queue - queue -
List link for shared memory queue of all the HOLDER objects for the List link for shared memory queue of all the HOLDER objects for the
......
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.92 2001/01/14 05:08:16 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.93 2001/01/16 06:11:34 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.92 2001/01/14 05:08:16 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.93 2001/01/16 06:11:34 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -230,7 +230,7 @@ InitProcess(void) ...@@ -230,7 +230,7 @@ InitProcess(void)
} }
/* this cannot be initialized until after the buffer pool */ /* this cannot be initialized until after the buffer pool */
SHMQueueInit(&(MyProc->lockQueue)); SHMQueueInit(&(MyProc->holderQueue));
} }
/* /*
...@@ -311,8 +311,8 @@ ZeroProcSemaphore(PROC *proc) ...@@ -311,8 +311,8 @@ ZeroProcSemaphore(PROC *proc)
* Locktable lock must be held by caller. * Locktable lock must be held by caller.
* *
* NB: this does not remove the process' holder object, nor the lock object, * NB: this does not remove the process' holder object, nor the lock object,
* even though their holder counts might now have gone to zero. That will * even though their counts might now have gone to zero. That will happen
* happen during a subsequent LockReleaseAll call, which we expect will happen * during a subsequent LockReleaseAll call, which we expect will happen
* during transaction cleanup. (Removal of a proc from its wait queue by * during transaction cleanup. (Removal of a proc from its wait queue by
* this routine can only happen if we are aborting the transaction.) * this routine can only happen if we are aborting the transaction.)
*/ */
...@@ -331,14 +331,14 @@ RemoveFromWaitQueue(PROC *proc) ...@@ -331,14 +331,14 @@ RemoveFromWaitQueue(PROC *proc)
SHMQueueDelete(&(proc->links)); SHMQueueDelete(&(proc->links));
waitLock->waitProcs.size--; waitLock->waitProcs.size--;
/* Undo increments of holder counts by waiting process */ /* Undo increments of request counts by waiting process */
Assert(waitLock->nHolding > 0); Assert(waitLock->nRequested > 0);
Assert(waitLock->nHolding > proc->waitLock->nActive); Assert(waitLock->nRequested > proc->waitLock->nGranted);
waitLock->nHolding--; waitLock->nRequested--;
Assert(waitLock->holders[lockmode] > 0); Assert(waitLock->requested[lockmode] > 0);
waitLock->holders[lockmode]--; waitLock->requested[lockmode]--;
/* don't forget to clear waitMask bit if appropriate */ /* don't forget to clear waitMask bit if appropriate */
if (waitLock->activeHolders[lockmode] == waitLock->holders[lockmode]) if (waitLock->granted[lockmode] == waitLock->requested[lockmode])
waitLock->waitMask &= ~(1 << lockmode); waitLock->waitMask &= ~(1 << lockmode);
/* Clean up the proc's own state */ /* Clean up the proc's own state */
...@@ -546,7 +546,7 @@ ProcSleep(LOCKMETHODCTL *lockctl, ...@@ -546,7 +546,7 @@ ProcSleep(LOCKMETHODCTL *lockctl,
int waitMask = lock->waitMask; int waitMask = lock->waitMask;
PROC *proc; PROC *proc;
int i; int i;
int aheadHolders[MAX_LOCKMODES]; int aheadGranted[MAX_LOCKMODES];
bool selfConflict = (lockctl->conflictTab[lockmode] & myMask), bool selfConflict = (lockctl->conflictTab[lockmode] & myMask),
prevSame = false; prevSame = false;
#ifndef __BEOS__ #ifndef __BEOS__
...@@ -559,7 +559,7 @@ ProcSleep(LOCKMETHODCTL *lockctl, ...@@ -559,7 +559,7 @@ ProcSleep(LOCKMETHODCTL *lockctl,
MyProc->waitLock = lock; MyProc->waitLock = lock;
MyProc->waitHolder = holder; MyProc->waitHolder = holder;
MyProc->waitLockMode = lockmode; MyProc->waitLockMode = lockmode;
/* We assume the caller set up MyProc->holdLock */ /* We assume the caller set up MyProc->heldLocks */
proc = (PROC *) MAKE_PTR(waitQueue->links.prev); proc = (PROC *) MAKE_PTR(waitQueue->links.prev);
...@@ -567,57 +567,61 @@ ProcSleep(LOCKMETHODCTL *lockctl, ...@@ -567,57 +567,61 @@ ProcSleep(LOCKMETHODCTL *lockctl,
if (!(lockctl->conflictTab[lockmode] & waitMask)) if (!(lockctl->conflictTab[lockmode] & waitMask))
goto ins; goto ins;
/* otherwise, determine where we should go into the queue */
for (i = 1; i < MAX_LOCKMODES; i++) for (i = 1; i < MAX_LOCKMODES; i++)
aheadHolders[i] = lock->activeHolders[i]; aheadGranted[i] = lock->granted[i];
(aheadHolders[lockmode])++; (aheadGranted[lockmode])++;
for (i = 0; i < waitQueue->size; i++) for (i = 0; i < waitQueue->size; i++)
{ {
/* am I waiting for him ? */ LOCKMODE procWaitMode = proc->waitLockMode;
if (lockctl->conflictTab[lockmode] & proc->holdLock)
/* must I wait for him ? */
if (lockctl->conflictTab[lockmode] & proc->heldLocks)
{ {
/* is he waiting for me ? */ /* is he waiting for me ? */
if (lockctl->conflictTab[proc->waitLockMode] & MyProc->holdLock) if (lockctl->conflictTab[procWaitMode] & MyProc->heldLocks)
{ {
/* Yes, report deadlock failure */ /* Yes, report deadlock failure */
MyProc->errType = STATUS_ERROR; MyProc->errType = STATUS_ERROR;
goto rt; goto rt;
} }
/* being waiting for him - go past */ /* I must go after him in queue - so continue loop */
} }
/* if he waits for me */ /* if he waits for me, go before him in queue */
else if (lockctl->conflictTab[proc->waitLockMode] & MyProc->holdLock) else if (lockctl->conflictTab[procWaitMode] & MyProc->heldLocks)
break; break;
/* if conflicting locks requested */ /* if conflicting locks requested */
else if (lockctl->conflictTab[proc->waitLockMode] & myMask) else if (lockctl->conflictTab[procWaitMode] & myMask)
{ {
/* /*
* If I request non self-conflicting lock and there are others * If I request non self-conflicting lock and there are others
* requesting the same lock just before me - stay here. * requesting the same lock just before this guy - stop here.
*/ */
if (!selfConflict && prevSame) if (!selfConflict && prevSame)
break; break;
} }
/* /*
* Last attempt to don't move any more: if we don't conflict with * Last attempt to not move any further to the back of the queue:
* rest waiters in queue. * if we don't conflict with remaining waiters, stop here.
*/ */
else if (!(lockctl->conflictTab[lockmode] & waitMask)) else if (!(lockctl->conflictTab[lockmode] & waitMask))
break; break;
prevSame = (proc->waitLockMode == lockmode); /* Move past this guy, and update state accordingly */
(aheadHolders[proc->waitLockMode])++; prevSame = (procWaitMode == lockmode);
if (aheadHolders[proc->waitLockMode] == lock->holders[proc->waitLockMode]) (aheadGranted[procWaitMode])++;
waitMask &= ~(1 << proc->waitLockMode); if (aheadGranted[procWaitMode] == lock->requested[procWaitMode])
waitMask &= ~(1 << procWaitMode);
proc = (PROC *) MAKE_PTR(proc->links.prev); proc = (PROC *) MAKE_PTR(proc->links.prev);
} }
ins:; ins:;
/* ------------------- /* -------------------
* Insert self into queue. These operations are atomic (because * Insert self into queue, ahead of the given proc.
* of the spinlock). * These operations are atomic (because of the spinlock).
* ------------------- * -------------------
*/ */
SHMQueueInsertTL(&(proc->links), &(MyProc->links)); SHMQueueInsertTL(&(proc->links), &(MyProc->links));
...@@ -838,7 +842,7 @@ nextProc: ...@@ -838,7 +842,7 @@ nextProc:
void void
ProcAddLock(SHM_QUEUE *elem) ProcAddLock(SHM_QUEUE *elem)
{ {
SHMQueueInsertTL(&MyProc->lockQueue, elem); SHMQueueInsertTL(&MyProc->holderQueue, elem);
} }
/* -------------------- /* --------------------
......
...@@ -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.40 2000/12/22 00:51:54 tgl Exp $ * $Id: lock.h,v 1.41 2001/01/16 06:11:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -150,26 +150,28 @@ typedef struct LOCKTAG ...@@ -150,26 +150,28 @@ typedef struct LOCKTAG
* Per-locked-object lock information: * Per-locked-object lock information:
* *
* tag -- uniquely identifies the object being locked * tag -- uniquely identifies the object being locked
* mask -- union of the conflict masks of all lock types * grantMask -- bitmask for all lock types currently granted on this object.
* currently held on this object. * waitMask -- bitmask for all lock types currently awaited on this object.
* waitProcs -- queue of processes waiting for this lock * waitProcs -- queue of processes waiting for this lock.
* holders -- count of each lock type currently held on the * requested -- count of each lock type currently requested on the lock
* lock. * (includes requests already granted!!).
* nHolding -- total locks of all types. * nRequested -- total requested locks of all types.
* granted -- count of each lock type currently granted on the lock.
* nGranted -- total granted locks of all types.
*/ */
typedef struct LOCK typedef struct LOCK
{ {
/* hash key */ /* hash key */
LOCKTAG tag; LOCKTAG tag; /* unique identifier of lockable object */
/* data */ /* data */
int mask; int grantMask; /* bitmask for lock types already granted */
int waitMask; int waitMask; /* bitmask for lock types awaited */
PROC_QUEUE waitProcs; PROC_QUEUE waitProcs; /* list of PROC objects waiting on lock */
int holders[MAX_LOCKMODES]; int requested[MAX_LOCKMODES]; /* counts of requested locks */
int nHolding; int nRequested; /* total of requested[] array */
int activeHolders[MAX_LOCKMODES]; int granted[MAX_LOCKMODES]; /* counts of granted locks */
int nActive; int nGranted; /* total of granted[] array */
} LOCK; } LOCK;
#define SHMEM_LOCKTAB_KEYSIZE sizeof(LOCKTAG) #define SHMEM_LOCKTAB_KEYSIZE sizeof(LOCKTAG)
...@@ -193,6 +195,12 @@ typedef struct LOCK ...@@ -193,6 +195,12 @@ typedef struct LOCK
* 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
* with per-transaction locks obtained by the same backend. * with per-transaction locks obtained by the same backend.
*
* The holding[] array counts the granted locks (of each type) represented
* by this holder. Note that there will be a holder object, possibly with
* zero holding[], for any lock that the process is currently waiting on.
* Otherwise, holder objects whose counts have gone to zero are recycled
* as soon as convenient.
*/ */
typedef struct HOLDERTAG typedef struct HOLDERTAG
{ {
...@@ -204,12 +212,12 @@ typedef struct HOLDERTAG ...@@ -204,12 +212,12 @@ typedef struct HOLDERTAG
typedef struct HOLDER typedef struct HOLDER
{ {
/* tag */ /* tag */
HOLDERTAG tag; HOLDERTAG tag; /* unique identifier of holder object */
/* data */ /* data */
int holders[MAX_LOCKMODES]; int holding[MAX_LOCKMODES]; /* count of locks currently held */
int nHolding; int nHolding; /* total of holding[] array */
SHM_QUEUE queue; SHM_QUEUE queue; /* list link for process' list of holders */
} HOLDER; } HOLDER;
#define SHMEM_HOLDERTAB_KEYSIZE sizeof(HOLDERTAG) #define SHMEM_HOLDERTAB_KEYSIZE sizeof(HOLDERTAG)
...@@ -241,7 +249,7 @@ extern bool LockReleaseAll(LOCKMETHOD lockmethod, PROC *proc, ...@@ -241,7 +249,7 @@ extern bool LockReleaseAll(LOCKMETHOD lockmethod, PROC *proc,
bool allxids, TransactionId xid); bool allxids, TransactionId xid);
extern int LockResolveConflicts(LOCKMETHOD lockmethod, LOCKMODE lockmode, extern int LockResolveConflicts(LOCKMETHOD lockmethod, LOCKMODE lockmode,
LOCK *lock, HOLDER *holder, PROC *proc, LOCK *lock, HOLDER *holder, PROC *proc,
int *myHolders); int *myHolding);
extern void GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode); extern void GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode);
extern int LockShmemSize(int maxBackends); extern int LockShmemSize(int maxBackends);
extern bool DeadLockCheck(PROC *thisProc, LOCK *findlock); extern bool DeadLockCheck(PROC *thisProc, LOCK *findlock);
......
...@@ -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.34 2001/01/14 05:08:16 tgl Exp $ * $Id: proc.h,v 1.35 2001/01/16 06:11:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,13 +27,20 @@ typedef struct ...@@ -27,13 +27,20 @@ typedef struct
} SEMA; } SEMA;
/* /*
* Each backend has: * Each backend has a PROC struct in shared memory. There is also a list
* of 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,
* the PROC is linked into that lock's waitProcs queue. A recycled PROC
* is linked into ProcGlobal's freeProcs list.
*/ */
struct proc struct proc
{ {
/* proc->links MUST BE THE FIRST ELEMENT OF STRUCT (see ProcWakeup()) */ /* proc->links MUST BE THE FIRST ELEMENT OF STRUCT (see ProcWakeup()) */
SHM_QUEUE links; /* proc can be waiting for one event(lock) */ SHM_QUEUE links; /* list link if process is in a list */
SEMA sem; /* ONE semaphore to sleep on */ SEMA sem; /* ONE semaphore to sleep on */
int errType; /* error code tells why we woke up */ int errType; /* error code tells why we woke up */
...@@ -48,16 +55,17 @@ struct proc ...@@ -48,16 +55,17 @@ struct proc
/* Info about lock the process is currently waiting for, if any */ /* Info about lock the process is currently waiting for, if any */
LOCK *waitLock; /* Lock object we're sleeping on ... */ LOCK *waitLock; /* Lock object we're sleeping on ... */
HOLDER *waitHolder; /* Per-holder info for our 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 */
LOCKMASK holdLock; /* bitmask for lock types already held */ LOCKMASK heldLocks; /* bitmask for lock types already held on
* this lock object by this backend */
int pid; /* This backend's process id */ int pid; /* This backend's process id */
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 lockQueue; /* locks associated with current SHM_QUEUE holderQueue; /* list of HOLDER objects for locks held or
* transaction */ * awaited by this backend */
}; };
/* NOTE: "typedef struct proc PROC" appears in storage/lock.h. */ /* NOTE: "typedef struct proc PROC" appears in storage/lock.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