Complete TODO item:
* -HOLDER/HOLDERTAB rename to PROCLOCK/PROCLOCKTAG
This commit is contained in:
parent
97377048b4
commit
b75fcf9326
@ -1,4 +1,4 @@
|
|||||||
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.10 2002/04/15 23:46:13 momjian Exp $
|
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.11 2002/07/19 00:17:40 momjian Exp $
|
||||||
|
|
||||||
|
|
||||||
LOCKING OVERVIEW
|
LOCKING OVERVIEW
|
||||||
@ -7,38 +7,40 @@ Postgres uses three types of interprocess locks:
|
|||||||
|
|
||||||
* Spinlocks. These are intended for *very* short-term locks. If a lock
|
* Spinlocks. These are intended for *very* short-term locks. If a lock
|
||||||
is to be held more than a few dozen instructions, or across any sort of
|
is to be held more than a few dozen instructions, or across any sort of
|
||||||
kernel call (or even a call to a nontrivial subroutine), don't use a spinlock.
|
kernel call (or even a call to a nontrivial subroutine), don't use a
|
||||||
Spinlocks are primarily used as infrastructure for lightweight locks.
|
spinlock. Spinlocks are primarily used as infrastructure for lightweight
|
||||||
They are implemented using a hardware atomic-test-and-set instruction,
|
locks. They are implemented using a hardware atomic-test-and-set
|
||||||
if available. Waiting processes busy-loop until they can get the lock.
|
instruction, if available. Waiting processes busy-loop until they can
|
||||||
There is no provision for deadlock detection, automatic release on error,
|
get the lock. There is no provision for deadlock detection, automatic
|
||||||
or any other nicety. There is a timeout if the lock cannot be gotten after
|
release on error, or any other nicety. There is a timeout if the lock
|
||||||
a minute or so (which is approximately forever in comparison to the intended
|
cannot be gotten after a minute or so (which is approximately forever in
|
||||||
lock hold time, so this is certainly an error condition).
|
comparison to the intended lock hold time, so this is certainly an error
|
||||||
|
condition).
|
||||||
|
|
||||||
* Lightweight locks (LWLocks). These locks are typically used to interlock
|
* Lightweight locks (LWLocks). These locks are typically used to
|
||||||
access to datastructures in shared memory. LWLocks support both exclusive
|
interlock access to datastructures in shared memory. LWLocks support
|
||||||
and shared lock modes (for read/write and read-only access to a shared object).
|
both exclusive and shared lock modes (for read/write and read-only
|
||||||
There is no provision for deadlock detection, but the LWLock manager will
|
access to a shared object). There is no provision for deadlock
|
||||||
automatically release held LWLocks during elog() recovery, so it is safe to
|
detection, but the LWLock manager will automatically release held
|
||||||
raise an error while holding LWLocks. Obtaining or releasing an LWLock is
|
LWLocks during elog() recovery, so it is safe to raise an error while
|
||||||
quite fast (a few dozen instructions) when there is no contention for the
|
holding LWLocks. Obtaining or releasing an LWLock is quite fast (a few
|
||||||
lock. When a process has to wait for an LWLock, it blocks on a SysV semaphore
|
dozen instructions) when there is no contention for the lock. When a
|
||||||
so as to not consume CPU time. Waiting processes will be granted the lock
|
process has to wait for an LWLock, it blocks on a SysV semaphore so as
|
||||||
in arrival order. There is no timeout.
|
to not consume CPU time. Waiting processes will be granted the lock in
|
||||||
|
arrival order. There is no timeout.
|
||||||
|
|
||||||
* Regular locks (a/k/a heavyweight locks). The regular lock manager supports
|
* Regular locks (a/k/a heavyweight locks). The regular lock manager
|
||||||
a variety of lock modes with table-driven semantics, and it has full deadlock
|
supports a variety of lock modes with table-driven semantics, and it has
|
||||||
detection and automatic release at transaction end. Regular locks should be
|
full deadlock detection and automatic release at transaction end.
|
||||||
used for all user-driven lock requests.
|
Regular locks should be used for all user-driven lock requests.
|
||||||
|
|
||||||
Acquisition of either a spinlock or a lightweight lock causes query cancel
|
Acquisition of either a spinlock or a lightweight lock causes query
|
||||||
and die() interrupts to be held off until all such locks are released.
|
cancel and die() interrupts to be held off until all such locks are
|
||||||
No such restriction exists for regular locks, however. Also note that we
|
released. No such restriction exists for regular locks, however. Also
|
||||||
can accept query cancel and die() interrupts while waiting for a regular
|
note that we can accept query cancel and die() interrupts while waiting
|
||||||
lock, but we will not accept them while waiting for spinlocks or LW locks.
|
for a regular lock, but we will not accept them while waiting for
|
||||||
It is therefore not a good idea to use LW locks when the wait time might
|
spinlocks or LW locks. It is therefore not a good idea to use LW locks
|
||||||
exceed a few seconds.
|
when the wait time might exceed a few seconds.
|
||||||
|
|
||||||
The rest of this README file discusses the regular lock manager in detail.
|
The rest of this README file discusses the regular lock manager in detail.
|
||||||
|
|
||||||
@ -46,9 +48,9 @@ The rest of this README file discusses the regular lock manager in detail.
|
|||||||
LOCK DATA STRUCTURES
|
LOCK DATA STRUCTURES
|
||||||
|
|
||||||
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 PROCLOCK struct. A LOCK object exists
|
||||||
for each lockable object that currently has locks held or requested on it.
|
for each lockable object that currently has locks held or requested on it.
|
||||||
A HOLDER struct exists for each transaction that is holding or requesting
|
A PROCLOCK struct exists for each transaction that is holding or requesting
|
||||||
lock(s) on each LOCK object.
|
lock(s) on each LOCK object.
|
||||||
|
|
||||||
Lock methods describe the overall locking behavior. Currently there are
|
Lock methods describe the overall locking behavior. Currently there are
|
||||||
@ -102,9 +104,9 @@ waitMask -
|
|||||||
is 1 if and only if requested[i] > granted[i].
|
is 1 if and only if requested[i] > granted[i].
|
||||||
|
|
||||||
lockHolders -
|
lockHolders -
|
||||||
This is a shared memory queue of all the HOLDER structs associated with
|
This is a shared memory queue of all the PROCLOCK structs associated with
|
||||||
the lock object. Note that both granted and waiting HOLDERs are in this
|
the lock object. Note that both granted and waiting PROCLOCKs are in this
|
||||||
list (indeed, the same HOLDER might have some already-granted locks and
|
list (indeed, the same PROCLOCK might have some already-granted locks and
|
||||||
be waiting for more!).
|
be waiting for more!).
|
||||||
|
|
||||||
waitProcs -
|
waitProcs -
|
||||||
@ -144,22 +146,22 @@ zero, the lock object is no longer needed and can be freed.
|
|||||||
|
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
The lock manager's HOLDER objects contain:
|
The lock manager's PROCLOCK objects contain:
|
||||||
|
|
||||||
tag -
|
tag -
|
||||||
The key fields that are used for hashing entries in the shared memory
|
The key fields that are used for hashing entries in the shared memory
|
||||||
holder hash table. This is declared as a separate struct to ensure that
|
PROCLOCK hash table. This is declared as a separate struct to ensure that
|
||||||
we always zero out the correct number of bytes.
|
we always zero out the correct number of bytes.
|
||||||
|
|
||||||
tag.lock
|
tag.lock
|
||||||
SHMEM offset of the LOCK object this holder is for.
|
SHMEM offset of the LOCK object this PROCLOCK is for.
|
||||||
|
|
||||||
tag.proc
|
tag.proc
|
||||||
SHMEM offset of PROC of backend process that owns this holder.
|
SHMEM offset of PROC of backend process that owns this PROCLOCK.
|
||||||
|
|
||||||
tag.xid
|
tag.xid
|
||||||
XID of transaction this holder is for, or InvalidTransactionId
|
XID of transaction this PROCLOCK is for, or InvalidTransactionId
|
||||||
if the holder is for session-level locking.
|
if the PROCLOCK is for session-level locking.
|
||||||
|
|
||||||
Note that this structure will support multiple transactions running
|
Note that this structure will support multiple transactions running
|
||||||
concurrently in one backend, which may be handy if we someday decide
|
concurrently in one backend, which may be handy if we someday decide
|
||||||
@ -169,18 +171,18 @@ tag -
|
|||||||
transaction operations like VACUUM.
|
transaction operations like VACUUM.
|
||||||
|
|
||||||
holding -
|
holding -
|
||||||
The number of successfully acquired locks of each type for this holder.
|
The number of successfully acquired locks of each type for this PROCLOCK.
|
||||||
This should be <= the corresponding granted[] value of the lock object!
|
This should be <= the corresponding granted[] value of the lock object!
|
||||||
|
|
||||||
nHolding -
|
nHolding -
|
||||||
Sum of the holding[] array.
|
Sum of the holding[] array.
|
||||||
|
|
||||||
lockLink -
|
lockLink -
|
||||||
List link for shared memory queue of all the HOLDER objects for the
|
List link for shared memory queue of all the PROCLOCK objects for the
|
||||||
same LOCK.
|
same LOCK.
|
||||||
|
|
||||||
procLink -
|
procLink -
|
||||||
List link for shared memory queue of all the HOLDER objects for the
|
List link for shared memory queue of all the PROCLOCK objects for the
|
||||||
same backend.
|
same backend.
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
@ -193,47 +195,48 @@ fairly standard in essence, but there are many special considerations
|
|||||||
needed to deal with Postgres' generalized locking model.
|
needed to deal with Postgres' generalized locking model.
|
||||||
|
|
||||||
A key design consideration is that we want to make routine operations
|
A key design consideration is that we want to make routine operations
|
||||||
(lock grant and release) run quickly when there is no deadlock, and avoid
|
(lock grant and release) run quickly when there is no deadlock, and
|
||||||
the overhead of deadlock handling as much as possible. We do this using
|
avoid the overhead of deadlock handling as much as possible. We do this
|
||||||
an "optimistic waiting" approach: if a process cannot acquire the lock
|
using an "optimistic waiting" approach: if a process cannot acquire the
|
||||||
it wants immediately, it goes to sleep without any deadlock check. But
|
lock it wants immediately, it goes to sleep without any deadlock check.
|
||||||
it also sets a delay timer, with a delay of DeadlockTimeout milliseconds
|
But it also sets a delay timer, with a delay of DeadlockTimeout
|
||||||
(typically set to one second). If the delay expires before the process is
|
milliseconds (typically set to one second). If the delay expires before
|
||||||
granted the lock it wants, it runs the deadlock detection/breaking code.
|
the process is granted the lock it wants, it runs the deadlock
|
||||||
Normally this code will determine that there is no deadlock condition,
|
detection/breaking code. Normally this code will determine that there is
|
||||||
and then the process will go back to sleep and wait quietly until it is
|
no deadlock condition, and then the process will go back to sleep and
|
||||||
granted the lock. But if a deadlock condition does exist, it will be
|
wait quietly until it is granted the lock. But if a deadlock condition
|
||||||
resolved, usually by aborting the detecting process' transaction. In this
|
does exist, it will be resolved, usually by aborting the detecting
|
||||||
way, we avoid deadlock handling overhead whenever the wait time for a lock
|
process' transaction. In this way, we avoid deadlock handling overhead
|
||||||
is less than DeadlockTimeout, while not imposing an unreasonable delay of
|
whenever the wait time for a lock is less than DeadlockTimeout, while
|
||||||
detection when there is an error.
|
not imposing an unreasonable delay of detection when there is an error.
|
||||||
|
|
||||||
Lock acquisition (routines LockAcquire and ProcSleep) follows these rules:
|
Lock acquisition (routines LockAcquire and ProcSleep) follows these rules:
|
||||||
|
|
||||||
1. A lock request is granted immediately if it does not conflict with any
|
1. A lock request is granted immediately if it does not conflict with
|
||||||
existing or waiting lock request, or if the process already holds an
|
any existing or waiting lock request, or if the process already holds an
|
||||||
instance of the same lock type (eg, there's no penalty to acquire a read
|
instance of the same lock type (eg, there's no penalty to acquire a read
|
||||||
lock twice). Note that a process never conflicts with itself, eg one can
|
lock twice). Note that a process never conflicts with itself, eg one
|
||||||
obtain read lock when one already holds exclusive lock.
|
can obtain read lock when one already holds exclusive lock.
|
||||||
|
|
||||||
2. Otherwise the process joins the lock's wait queue. Normally it will be
|
2. Otherwise the process joins the lock's wait queue. Normally it will
|
||||||
added to the end of the queue, but there is an exception: if the process
|
be added to the end of the queue, but there is an exception: if the
|
||||||
already holds locks on this same lockable object that conflict with the
|
process already holds locks on this same lockable object that conflict
|
||||||
request of any pending waiter, then the process will be inserted in the
|
with the request of any pending waiter, then the process will be
|
||||||
wait queue just ahead of the first such waiter. (If we did not make this
|
inserted in the wait queue just ahead of the first such waiter. (If we
|
||||||
check, the deadlock detection code would adjust the queue order to resolve
|
did not make this check, the deadlock detection code would adjust the
|
||||||
the conflict, but it's relatively cheap to make the check in ProcSleep and
|
queue order to resolve the conflict, but it's relatively cheap to make
|
||||||
avoid a deadlock timeout delay in this case.) Note special case when
|
the check in ProcSleep and avoid a deadlock timeout delay in this case.)
|
||||||
inserting before the end of the queue: if the process's request does not
|
Note special case when inserting before the end of the queue: if the
|
||||||
conflict with any existing lock nor any waiting request before its insertion
|
process's request does not conflict with any existing lock nor any
|
||||||
point, then go ahead and grant the lock without waiting.
|
waiting request before its insertion point, then go ahead and grant the
|
||||||
|
lock without waiting.
|
||||||
|
|
||||||
When a lock is released, the lock release routine (ProcLockWakeup) scans
|
When a lock is released, the lock release routine (ProcLockWakeup) scans
|
||||||
the lock object's wait queue. Each waiter is awoken if (a) its request
|
the lock object's wait queue. Each waiter is awoken if (a) its request
|
||||||
does not conflict with already-granted locks, and (b) its request does
|
does not conflict with already-granted locks, and (b) its request does
|
||||||
not conflict with the requests of prior un-wakable waiters. Rule (b)
|
not conflict with the requests of prior un-wakable waiters. Rule (b)
|
||||||
ensures that conflicting requests are granted in order of arrival.
|
ensures that conflicting requests are granted in order of arrival. There
|
||||||
There are cases where a later waiter must be allowed to go in front of
|
are cases where a later waiter must be allowed to go in front of
|
||||||
conflicting earlier waiters to avoid deadlock, but it is not
|
conflicting earlier waiters to avoid deadlock, but it is not
|
||||||
ProcLockWakeup's responsibility to recognize these cases; instead, the
|
ProcLockWakeup's responsibility to recognize these cases; instead, the
|
||||||
deadlock detection code will re-order the wait queue when necessary.
|
deadlock detection code will re-order the wait queue when necessary.
|
||||||
@ -242,35 +245,36 @@ To perform deadlock checking, we use the standard method of viewing the
|
|||||||
various processes as nodes in a directed graph (the waits-for graph or
|
various processes as nodes in a directed graph (the waits-for graph or
|
||||||
WFG). There is a graph edge leading from process A to process B if A
|
WFG). There is a graph edge leading from process A to process B if A
|
||||||
waits for B, ie, A is waiting for some lock and B holds a conflicting
|
waits for B, ie, A is waiting for some lock and B holds a conflicting
|
||||||
lock. There is a deadlock condition if and only if the WFG contains
|
lock. There is a deadlock condition if and only if the WFG contains a
|
||||||
a cycle. We detect cycles by searching outward along waits-for edges
|
cycle. We detect cycles by searching outward along waits-for edges to
|
||||||
to see if we return to our starting point. There are three possible
|
see if we return to our starting point. There are three possible
|
||||||
outcomes:
|
outcomes:
|
||||||
|
|
||||||
1. All outgoing paths terminate at a running process (which has no
|
1. All outgoing paths terminate at a running process (which has no
|
||||||
outgoing edge).
|
outgoing edge).
|
||||||
|
|
||||||
2. A deadlock is detected by looping back to the start point. We resolve
|
2. A deadlock is detected by looping back to the start point. We
|
||||||
such a deadlock by canceling the start point's lock request and reporting
|
resolve such a deadlock by canceling the start point's lock request and
|
||||||
an error in that transaction, which normally leads to transaction abort
|
reporting an error in that transaction, which normally leads to
|
||||||
and release of that transaction's held locks. Note that it's sufficient
|
transaction abort and release of that transaction's held locks. Note
|
||||||
to cancel one request to remove the cycle; we don't need to kill all the
|
that it's sufficient to cancel one request to remove the cycle; we don't
|
||||||
transactions involved.
|
need to kill all the transactions involved.
|
||||||
|
|
||||||
3. Some path(s) loop back to a node other than the start point. This
|
3. Some path(s) loop back to a node other than the start point. This
|
||||||
indicates a deadlock, but one that does not involve our starting process.
|
indicates a deadlock, but one that does not involve our starting
|
||||||
We ignore this condition on the grounds that resolving such a deadlock
|
process. We ignore this condition on the grounds that resolving such a
|
||||||
is the responsibility of the processes involved --- killing our start-
|
deadlock is the responsibility of the processes involved --- killing our
|
||||||
point process would not resolve the deadlock. So, cases 1 and 3 both
|
start- point process would not resolve the deadlock. So, cases 1 and 3
|
||||||
report "no deadlock".
|
both report "no deadlock".
|
||||||
|
|
||||||
Postgres' situation is a little more complex than the standard discussion
|
Postgres' situation is a little more complex than the standard discussion
|
||||||
of deadlock detection, for two reasons:
|
of deadlock detection, for two reasons:
|
||||||
|
|
||||||
1. A process can be waiting for more than one other process, since there
|
1. A process can be waiting for more than one other process, since there
|
||||||
might be multiple holders of (non-conflicting) lock types that all conflict
|
might be multiple PROCLOCKs of (non-conflicting) lock types that all
|
||||||
with the waiter's request. This creates no real difficulty however; we
|
conflict with the waiter's request. This creates no real difficulty
|
||||||
simply need to be prepared to trace more than one outgoing edge.
|
however; we simply need to be prepared to trace more than one outgoing
|
||||||
|
edge.
|
||||||
|
|
||||||
2. If a process A is behind a process B in some lock's wait queue, and
|
2. If a process A is behind a process B in some lock's wait queue, and
|
||||||
their requested locks conflict, then we must say that A waits for B, since
|
their requested locks conflict, then we must say that A waits for B, since
|
||||||
@ -409,16 +413,18 @@ LockWaitCancel (abort a waiter due to outside factors) must run
|
|||||||
ProcLockWakeup, in case the canceled waiter was soft-blocking other
|
ProcLockWakeup, in case the canceled waiter was soft-blocking other
|
||||||
waiters.
|
waiters.
|
||||||
|
|
||||||
4. We can minimize excess rearrangement-trial work by being careful to scan
|
4. We can minimize excess rearrangement-trial work by being careful to
|
||||||
the wait queue from the front when looking for soft edges. For example,
|
scan the wait queue from the front when looking for soft edges. For
|
||||||
if we have queue order A,B,C and C has deadlock conflicts with both A and B,
|
example, if we have queue order A,B,C and C has deadlock conflicts with
|
||||||
we want to generate the "C before A" constraint first, rather than wasting
|
both A and B, we want to generate the "C before A" constraint first,
|
||||||
time with "C before B", which won't move C far enough up. So we look for
|
rather than wasting time with "C before B", which won't move C far
|
||||||
soft edges outgoing from C starting at the front of the wait queue.
|
enough up. So we look for soft edges outgoing from C starting at the
|
||||||
|
front of the wait queue.
|
||||||
|
|
||||||
5. The working data structures needed by the deadlock detection code can
|
5. The working data structures needed by the deadlock detection code can
|
||||||
be limited to numbers of entries computed from MaxBackends. Therefore,
|
be limited to numbers of entries computed from MaxBackends. Therefore,
|
||||||
we can allocate the worst-case space needed during backend startup.
|
we can allocate the worst-case space needed during backend startup. This
|
||||||
This seems a safer approach than trying to allocate workspace on the fly;
|
seems a safer approach than trying to allocate workspace on the fly; we
|
||||||
we don't want to risk having the deadlock detector run out of memory,
|
don't want to risk having the deadlock detector run out of memory, else
|
||||||
else we really have no guarantees at all that deadlock will be detected.
|
we really have no guarantees at all that deadlock will be detected.
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/deadlock.c,v 1.11 2002/07/18 23:06:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/deadlock.c,v 1.12 2002/07/19 00:17:40 momjian Exp $
|
||||||
*
|
*
|
||||||
* Interface:
|
* Interface:
|
||||||
*
|
*
|
||||||
@ -377,7 +377,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
|
|||||||
{
|
{
|
||||||
PGPROC *proc;
|
PGPROC *proc;
|
||||||
LOCK *lock;
|
LOCK *lock;
|
||||||
HOLDER *holder;
|
PROCLOCK *holder;
|
||||||
SHM_QUEUE *lockHolders;
|
SHM_QUEUE *lockHolders;
|
||||||
LOCKMETHODTABLE *lockMethodTable;
|
LOCKMETHODTABLE *lockMethodTable;
|
||||||
PROC_QUEUE *waitQueue;
|
PROC_QUEUE *waitQueue;
|
||||||
@ -427,8 +427,8 @@ FindLockCycleRecurse(PGPROC *checkProc,
|
|||||||
*/
|
*/
|
||||||
lockHolders = &(lock->lockHolders);
|
lockHolders = &(lock->lockHolders);
|
||||||
|
|
||||||
holder = (HOLDER *) SHMQueueNext(lockHolders, lockHolders,
|
holder = (PROCLOCK *) SHMQueueNext(lockHolders, lockHolders,
|
||||||
offsetof(HOLDER, lockLink));
|
offsetof(PROCLOCK, lockLink));
|
||||||
|
|
||||||
while (holder)
|
while (holder)
|
||||||
{
|
{
|
||||||
@ -451,8 +451,8 @@ FindLockCycleRecurse(PGPROC *checkProc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
holder = (HOLDER *) SHMQueueNext(lockHolders, &holder->lockLink,
|
holder = (PROCLOCK *) SHMQueueNext(lockHolders, &holder->lockLink,
|
||||||
offsetof(HOLDER, lockLink));
|
offsetof(PROCLOCK, lockLink));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.109 2002/07/18 23:06:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.110 2002/07/19 00:17:40 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Outside modules can create a lock table and acquire/release
|
* Outside modules can create a lock table and acquire/release
|
||||||
@ -48,7 +48,7 @@ int max_locks_per_xact; /* set by guc.c */
|
|||||||
|
|
||||||
|
|
||||||
static int WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
static int WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
||||||
LOCK *lock, HOLDER *holder);
|
LOCK *lock, PROCLOCK *holder);
|
||||||
static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc,
|
static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc,
|
||||||
int *myHolding);
|
int *myHolding);
|
||||||
|
|
||||||
@ -125,18 +125,18 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
|
|||||||
|
|
||||||
|
|
||||||
inline static void
|
inline static void
|
||||||
HOLDER_PRINT(const char *where, const HOLDER *holderP)
|
PROCLOCK_PRINT(const char *where, const PROCLOCK *holderP)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(((HOLDER_LOCKMETHOD(*holderP) == DEFAULT_LOCKMETHOD && Trace_locks)
|
(((PROCLOCK_LOCKMETHOD(*holderP) == DEFAULT_LOCKMETHOD && Trace_locks)
|
||||||
|| (HOLDER_LOCKMETHOD(*holderP) == USER_LOCKMETHOD && Trace_userlocks))
|
|| (PROCLOCK_LOCKMETHOD(*holderP) == USER_LOCKMETHOD && Trace_userlocks))
|
||||||
&& (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId >= (Oid) Trace_lock_oidmin))
|
&& (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId >= (Oid) Trace_lock_oidmin))
|
||||||
|| (Trace_lock_table && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId == Trace_lock_table))
|
|| (Trace_lock_table && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId == Trace_lock_table))
|
||||||
)
|
)
|
||||||
elog(LOG,
|
elog(LOG,
|
||||||
"%s: holder(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) hold(%d,%d,%d,%d,%d,%d,%d)=%d",
|
"%s: holder(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) hold(%d,%d,%d,%d,%d,%d,%d)=%d",
|
||||||
where, MAKE_OFFSET(holderP), holderP->tag.lock,
|
where, MAKE_OFFSET(holderP), holderP->tag.lock,
|
||||||
HOLDER_LOCKMETHOD(*(holderP)),
|
PROCLOCK_LOCKMETHOD(*(holderP)),
|
||||||
holderP->tag.proc, holderP->tag.xid,
|
holderP->tag.proc, holderP->tag.xid,
|
||||||
holderP->holding[1], holderP->holding[2], holderP->holding[3],
|
holderP->holding[1], holderP->holding[2], holderP->holding[3],
|
||||||
holderP->holding[4], holderP->holding[5], holderP->holding[6],
|
holderP->holding[4], holderP->holding[5], holderP->holding[6],
|
||||||
@ -146,7 +146,7 @@ HOLDER_PRINT(const char *where, const HOLDER *holderP)
|
|||||||
#else /* not LOCK_DEBUG */
|
#else /* not LOCK_DEBUG */
|
||||||
|
|
||||||
#define LOCK_PRINT(where, lock, type)
|
#define LOCK_PRINT(where, lock, type)
|
||||||
#define HOLDER_PRINT(where, holderP)
|
#define PROCLOCK_PRINT(where, holderP)
|
||||||
#endif /* not LOCK_DEBUG */
|
#endif /* not LOCK_DEBUG */
|
||||||
|
|
||||||
|
|
||||||
@ -316,11 +316,11 @@ LockMethodTableInit(char *tabName,
|
|||||||
Assert(lockMethodTable->lockHash->hash == tag_hash);
|
Assert(lockMethodTable->lockHash->hash == tag_hash);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocate a hash table for HOLDER structs. This is used to store
|
* allocate a hash table for PROCLOCK structs. This is used to store
|
||||||
* per-lock-holder information.
|
* per-lock-holder information.
|
||||||
*/
|
*/
|
||||||
info.keysize = sizeof(HOLDERTAG);
|
info.keysize = sizeof(PROCLOCKTAG);
|
||||||
info.entrysize = sizeof(HOLDER);
|
info.entrysize = sizeof(PROCLOCK);
|
||||||
info.hash = tag_hash;
|
info.hash = tag_hash;
|
||||||
hash_flags = (HASH_ELEM | HASH_FUNCTION);
|
hash_flags = (HASH_ELEM | HASH_FUNCTION);
|
||||||
|
|
||||||
@ -440,8 +440,8 @@ bool
|
|||||||
LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
||||||
TransactionId xid, LOCKMODE lockmode, bool dontWait)
|
TransactionId xid, LOCKMODE lockmode, bool dontWait)
|
||||||
{
|
{
|
||||||
HOLDER *holder;
|
PROCLOCK *holder;
|
||||||
HOLDERTAG holdertag;
|
PROCLOCKTAG holdertag;
|
||||||
HTAB *holderTable;
|
HTAB *holderTable;
|
||||||
bool found;
|
bool found;
|
||||||
LOCK *lock;
|
LOCK *lock;
|
||||||
@ -513,7 +513,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
/*
|
/*
|
||||||
* Create the hash key for the holder table.
|
* Create the hash key for the holder table.
|
||||||
*/
|
*/
|
||||||
MemSet(&holdertag, 0, sizeof(HOLDERTAG)); /* must clear padding,
|
MemSet(&holdertag, 0, sizeof(PROCLOCKTAG)); /* must clear padding,
|
||||||
* needed */
|
* needed */
|
||||||
holdertag.lock = MAKE_OFFSET(lock);
|
holdertag.lock = MAKE_OFFSET(lock);
|
||||||
holdertag.proc = MAKE_OFFSET(MyProc);
|
holdertag.proc = MAKE_OFFSET(MyProc);
|
||||||
@ -523,7 +523,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
* Find or create a holder entry with this tag
|
* Find or create a holder entry with this tag
|
||||||
*/
|
*/
|
||||||
holderTable = lockMethodTable->holderHash;
|
holderTable = lockMethodTable->holderHash;
|
||||||
holder = (HOLDER *) hash_search(holderTable,
|
holder = (PROCLOCK *) hash_search(holderTable,
|
||||||
(void *) &holdertag,
|
(void *) &holdertag,
|
||||||
HASH_ENTER, &found);
|
HASH_ENTER, &found);
|
||||||
if (!holder)
|
if (!holder)
|
||||||
@ -543,11 +543,11 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
/* Add holder to appropriate lists */
|
/* Add holder to appropriate lists */
|
||||||
SHMQueueInsertBefore(&lock->lockHolders, &holder->lockLink);
|
SHMQueueInsertBefore(&lock->lockHolders, &holder->lockLink);
|
||||||
SHMQueueInsertBefore(&MyProc->procHolders, &holder->procLink);
|
SHMQueueInsertBefore(&MyProc->procHolders, &holder->procLink);
|
||||||
HOLDER_PRINT("LockAcquire: new", holder);
|
PROCLOCK_PRINT("LockAcquire: new", holder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HOLDER_PRINT("LockAcquire: found", holder);
|
PROCLOCK_PRINT("LockAcquire: found", holder);
|
||||||
Assert((holder->nHolding >= 0) && (holder->holding[lockmode] >= 0));
|
Assert((holder->nHolding >= 0) && (holder->holding[lockmode] >= 0));
|
||||||
Assert(holder->nHolding <= lock->nGranted);
|
Assert(holder->nHolding <= lock->nGranted);
|
||||||
|
|
||||||
@ -600,7 +600,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
if (holder->holding[lockmode] > 0)
|
if (holder->holding[lockmode] > 0)
|
||||||
{
|
{
|
||||||
GrantLock(lock, holder, lockmode);
|
GrantLock(lock, holder, lockmode);
|
||||||
HOLDER_PRINT("LockAcquire: owning", holder);
|
PROCLOCK_PRINT("LockAcquire: owning", holder);
|
||||||
LWLockRelease(masterLock);
|
LWLockRelease(masterLock);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -613,7 +613,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
if (myHolding[lockmode] > 0)
|
if (myHolding[lockmode] > 0)
|
||||||
{
|
{
|
||||||
GrantLock(lock, holder, lockmode);
|
GrantLock(lock, holder, lockmode);
|
||||||
HOLDER_PRINT("LockAcquire: my other XID owning", holder);
|
PROCLOCK_PRINT("LockAcquire: my other XID owning", holder);
|
||||||
LWLockRelease(masterLock);
|
LWLockRelease(masterLock);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -650,14 +650,14 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
{
|
{
|
||||||
SHMQueueDelete(&holder->lockLink);
|
SHMQueueDelete(&holder->lockLink);
|
||||||
SHMQueueDelete(&holder->procLink);
|
SHMQueueDelete(&holder->procLink);
|
||||||
holder = (HOLDER *) hash_search(holderTable,
|
holder = (PROCLOCK *) hash_search(holderTable,
|
||||||
(void *) holder,
|
(void *) holder,
|
||||||
HASH_REMOVE, NULL);
|
HASH_REMOVE, NULL);
|
||||||
if (!holder)
|
if (!holder)
|
||||||
elog(WARNING, "LockAcquire: remove holder, table corrupted");
|
elog(WARNING, "LockAcquire: remove holder, table corrupted");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
HOLDER_PRINT("LockAcquire: NHOLDING", holder);
|
PROCLOCK_PRINT("LockAcquire: NHOLDING", holder);
|
||||||
lock->nRequested--;
|
lock->nRequested--;
|
||||||
lock->requested[lockmode]--;
|
lock->requested[lockmode]--;
|
||||||
LOCK_PRINT("LockAcquire: conditional lock failed", lock, lockmode);
|
LOCK_PRINT("LockAcquire: conditional lock failed", lock, lockmode);
|
||||||
@ -702,13 +702,13 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
*/
|
*/
|
||||||
if (!((holder->nHolding > 0) && (holder->holding[lockmode] > 0)))
|
if (!((holder->nHolding > 0) && (holder->holding[lockmode] > 0)))
|
||||||
{
|
{
|
||||||
HOLDER_PRINT("LockAcquire: INCONSISTENT", holder);
|
PROCLOCK_PRINT("LockAcquire: INCONSISTENT", holder);
|
||||||
LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
|
LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
|
||||||
/* Should we retry ? */
|
/* Should we retry ? */
|
||||||
LWLockRelease(masterLock);
|
LWLockRelease(masterLock);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
HOLDER_PRINT("LockAcquire: granted", holder);
|
PROCLOCK_PRINT("LockAcquire: granted", holder);
|
||||||
LOCK_PRINT("LockAcquire: granted", lock, lockmode);
|
LOCK_PRINT("LockAcquire: granted", lock, lockmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,7 +737,7 @@ int
|
|||||||
LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
||||||
LOCKMODE lockmode,
|
LOCKMODE lockmode,
|
||||||
LOCK *lock,
|
LOCK *lock,
|
||||||
HOLDER *holder,
|
PROCLOCK *holder,
|
||||||
PGPROC *proc,
|
PGPROC *proc,
|
||||||
int *myHolding) /* myHolding[] array or NULL */
|
int *myHolding) /* myHolding[] array or NULL */
|
||||||
{
|
{
|
||||||
@ -758,7 +758,7 @@ LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
*/
|
*/
|
||||||
if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
|
if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
|
||||||
{
|
{
|
||||||
HOLDER_PRINT("LockCheckConflicts: no conflict", holder);
|
PROCLOCK_PRINT("LockCheckConflicts: no conflict", holder);
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,11 +792,11 @@ LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
if (!(lockMethodTable->conflictTab[lockmode] & bitmask))
|
if (!(lockMethodTable->conflictTab[lockmode] & bitmask))
|
||||||
{
|
{
|
||||||
/* no conflict. OK to get the lock */
|
/* no conflict. OK to get the lock */
|
||||||
HOLDER_PRINT("LockCheckConflicts: resolved", holder);
|
PROCLOCK_PRINT("LockCheckConflicts: resolved", holder);
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
HOLDER_PRINT("LockCheckConflicts: conflicting", holder);
|
PROCLOCK_PRINT("LockCheckConflicts: conflicting", holder);
|
||||||
return STATUS_FOUND;
|
return STATUS_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,13 +814,13 @@ static void
|
|||||||
LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding)
|
LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding)
|
||||||
{
|
{
|
||||||
SHM_QUEUE *procHolders = &(proc->procHolders);
|
SHM_QUEUE *procHolders = &(proc->procHolders);
|
||||||
HOLDER *holder;
|
PROCLOCK *holder;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
MemSet(myHolding, 0, MAX_LOCKMODES * sizeof(int));
|
MemSet(myHolding, 0, MAX_LOCKMODES * sizeof(int));
|
||||||
|
|
||||||
holder = (HOLDER *) SHMQueueNext(procHolders, procHolders,
|
holder = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
|
||||||
offsetof(HOLDER, procLink));
|
offsetof(PROCLOCK, procLink));
|
||||||
|
|
||||||
while (holder)
|
while (holder)
|
||||||
{
|
{
|
||||||
@ -830,8 +830,8 @@ LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding)
|
|||||||
myHolding[i] += holder->holding[i];
|
myHolding[i] += holder->holding[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
holder = (HOLDER *) SHMQueueNext(procHolders, &holder->procLink,
|
holder = (PROCLOCK *) SHMQueueNext(procHolders, &holder->procLink,
|
||||||
offsetof(HOLDER, procLink));
|
offsetof(PROCLOCK, procLink));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,7 +843,7 @@ LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding)
|
|||||||
* and have its waitLock/waitHolder fields cleared. That's not done here.
|
* and have its waitLock/waitHolder fields cleared. That's not done here.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode)
|
GrantLock(LOCK *lock, PROCLOCK *holder, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
lock->nGranted++;
|
lock->nGranted++;
|
||||||
lock->granted[lockmode]++;
|
lock->granted[lockmode]++;
|
||||||
@ -868,7 +868,7 @@ GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode)
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
|
||||||
LOCK *lock, HOLDER *holder)
|
LOCK *lock, PROCLOCK *holder)
|
||||||
{
|
{
|
||||||
LOCKMETHODTABLE *lockMethodTable = LockMethodTable[lockmethod];
|
LOCKMETHODTABLE *lockMethodTable = LockMethodTable[lockmethod];
|
||||||
char *new_status,
|
char *new_status,
|
||||||
@ -984,8 +984,8 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
LOCK *lock;
|
LOCK *lock;
|
||||||
LWLockId masterLock;
|
LWLockId masterLock;
|
||||||
LOCKMETHODTABLE *lockMethodTable;
|
LOCKMETHODTABLE *lockMethodTable;
|
||||||
HOLDER *holder;
|
PROCLOCK *holder;
|
||||||
HOLDERTAG holdertag;
|
PROCLOCKTAG holdertag;
|
||||||
HTAB *holderTable;
|
HTAB *holderTable;
|
||||||
bool wakeupNeeded = false;
|
bool wakeupNeeded = false;
|
||||||
|
|
||||||
@ -1031,14 +1031,14 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
/*
|
/*
|
||||||
* Find the holder entry for this holder.
|
* Find the holder entry for this holder.
|
||||||
*/
|
*/
|
||||||
MemSet(&holdertag, 0, sizeof(HOLDERTAG)); /* must clear padding,
|
MemSet(&holdertag, 0, sizeof(PROCLOCKTAG)); /* must clear padding,
|
||||||
* needed */
|
* needed */
|
||||||
holdertag.lock = MAKE_OFFSET(lock);
|
holdertag.lock = MAKE_OFFSET(lock);
|
||||||
holdertag.proc = MAKE_OFFSET(MyProc);
|
holdertag.proc = MAKE_OFFSET(MyProc);
|
||||||
TransactionIdStore(xid, &holdertag.xid);
|
TransactionIdStore(xid, &holdertag.xid);
|
||||||
|
|
||||||
holderTable = lockMethodTable->holderHash;
|
holderTable = lockMethodTable->holderHash;
|
||||||
holder = (HOLDER *) hash_search(holderTable,
|
holder = (PROCLOCK *) hash_search(holderTable,
|
||||||
(void *) &holdertag,
|
(void *) &holdertag,
|
||||||
HASH_FIND_SAVE, NULL);
|
HASH_FIND_SAVE, NULL);
|
||||||
if (!holder)
|
if (!holder)
|
||||||
@ -1052,7 +1052,7 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
elog(WARNING, "LockRelease: holder table corrupted");
|
elog(WARNING, "LockRelease: holder table corrupted");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
HOLDER_PRINT("LockRelease: found", holder);
|
PROCLOCK_PRINT("LockRelease: found", holder);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that we are actually holding a lock of the type we want to
|
* Check that we are actually holding a lock of the type we want to
|
||||||
@ -1060,7 +1060,7 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
*/
|
*/
|
||||||
if (!(holder->holding[lockmode] > 0))
|
if (!(holder->holding[lockmode] > 0))
|
||||||
{
|
{
|
||||||
HOLDER_PRINT("LockRelease: WRONGTYPE", holder);
|
PROCLOCK_PRINT("LockRelease: WRONGTYPE", holder);
|
||||||
Assert(holder->holding[lockmode] >= 0);
|
Assert(holder->holding[lockmode] >= 0);
|
||||||
LWLockRelease(masterLock);
|
LWLockRelease(masterLock);
|
||||||
elog(WARNING, "LockRelease: you don't own a lock of type %s",
|
elog(WARNING, "LockRelease: you don't own a lock of type %s",
|
||||||
@ -1128,7 +1128,7 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
*/
|
*/
|
||||||
holder->holding[lockmode]--;
|
holder->holding[lockmode]--;
|
||||||
holder->nHolding--;
|
holder->nHolding--;
|
||||||
HOLDER_PRINT("LockRelease: updated", holder);
|
PROCLOCK_PRINT("LockRelease: updated", holder);
|
||||||
Assert((holder->nHolding >= 0) && (holder->holding[lockmode] >= 0));
|
Assert((holder->nHolding >= 0) && (holder->holding[lockmode] >= 0));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1137,10 +1137,10 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
|
|||||||
*/
|
*/
|
||||||
if (holder->nHolding == 0)
|
if (holder->nHolding == 0)
|
||||||
{
|
{
|
||||||
HOLDER_PRINT("LockRelease: deleting", holder);
|
PROCLOCK_PRINT("LockRelease: deleting", holder);
|
||||||
SHMQueueDelete(&holder->lockLink);
|
SHMQueueDelete(&holder->lockLink);
|
||||||
SHMQueueDelete(&holder->procLink);
|
SHMQueueDelete(&holder->procLink);
|
||||||
holder = (HOLDER *) hash_search(holderTable,
|
holder = (PROCLOCK *) hash_search(holderTable,
|
||||||
(void *) &holder,
|
(void *) &holder,
|
||||||
HASH_REMOVE_SAVED, NULL);
|
HASH_REMOVE_SAVED, NULL);
|
||||||
if (!holder)
|
if (!holder)
|
||||||
@ -1177,8 +1177,8 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
|
|||||||
bool allxids, TransactionId xid)
|
bool allxids, TransactionId xid)
|
||||||
{
|
{
|
||||||
SHM_QUEUE *procHolders = &(proc->procHolders);
|
SHM_QUEUE *procHolders = &(proc->procHolders);
|
||||||
HOLDER *holder;
|
PROCLOCK *holder;
|
||||||
HOLDER *nextHolder;
|
PROCLOCK *nextHolder;
|
||||||
LWLockId masterLock;
|
LWLockId masterLock;
|
||||||
LOCKMETHODTABLE *lockMethodTable;
|
LOCKMETHODTABLE *lockMethodTable;
|
||||||
int i,
|
int i,
|
||||||
@ -1204,16 +1204,16 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
|
|||||||
|
|
||||||
LWLockAcquire(masterLock, LW_EXCLUSIVE);
|
LWLockAcquire(masterLock, LW_EXCLUSIVE);
|
||||||
|
|
||||||
holder = (HOLDER *) SHMQueueNext(procHolders, procHolders,
|
holder = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
|
||||||
offsetof(HOLDER, procLink));
|
offsetof(PROCLOCK, procLink));
|
||||||
|
|
||||||
while (holder)
|
while (holder)
|
||||||
{
|
{
|
||||||
bool wakeupNeeded = false;
|
bool wakeupNeeded = false;
|
||||||
|
|
||||||
/* Get link first, since we may unlink/delete this holder */
|
/* Get link first, since we may unlink/delete this holder */
|
||||||
nextHolder = (HOLDER *) SHMQueueNext(procHolders, &holder->procLink,
|
nextHolder = (PROCLOCK *) SHMQueueNext(procHolders, &holder->procLink,
|
||||||
offsetof(HOLDER, procLink));
|
offsetof(PROCLOCK, procLink));
|
||||||
|
|
||||||
Assert(holder->tag.proc == MAKE_OFFSET(proc));
|
Assert(holder->tag.proc == MAKE_OFFSET(proc));
|
||||||
|
|
||||||
@ -1227,7 +1227,7 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
|
|||||||
if (!allxids && !TransactionIdEquals(xid, holder->tag.xid))
|
if (!allxids && !TransactionIdEquals(xid, holder->tag.xid))
|
||||||
goto next_item;
|
goto next_item;
|
||||||
|
|
||||||
HOLDER_PRINT("LockReleaseAll", holder);
|
PROCLOCK_PRINT("LockReleaseAll", holder);
|
||||||
LOCK_PRINT("LockReleaseAll", lock, 0);
|
LOCK_PRINT("LockReleaseAll", lock, 0);
|
||||||
Assert(lock->nRequested >= 0);
|
Assert(lock->nRequested >= 0);
|
||||||
Assert(lock->nGranted >= 0);
|
Assert(lock->nGranted >= 0);
|
||||||
@ -1281,7 +1281,7 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
|
|||||||
}
|
}
|
||||||
LOCK_PRINT("LockReleaseAll: updated", lock, 0);
|
LOCK_PRINT("LockReleaseAll: updated", lock, 0);
|
||||||
|
|
||||||
HOLDER_PRINT("LockReleaseAll: deleting", holder);
|
PROCLOCK_PRINT("LockReleaseAll: deleting", holder);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove the holder entry from the linked lists
|
* Remove the holder entry from the linked lists
|
||||||
@ -1292,7 +1292,7 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
|
|||||||
/*
|
/*
|
||||||
* remove the holder entry from the hashtable
|
* remove the holder entry from the hashtable
|
||||||
*/
|
*/
|
||||||
holder = (HOLDER *) hash_search(lockMethodTable->holderHash,
|
holder = (PROCLOCK *) hash_search(lockMethodTable->holderHash,
|
||||||
(void *) holder,
|
(void *) holder,
|
||||||
HASH_REMOVE,
|
HASH_REMOVE,
|
||||||
NULL);
|
NULL);
|
||||||
@ -1353,7 +1353,7 @@ LockShmemSize(int maxBackends)
|
|||||||
size += hash_estimate_size(max_table_size, sizeof(LOCK));
|
size += hash_estimate_size(max_table_size, sizeof(LOCK));
|
||||||
|
|
||||||
/* holderHash table */
|
/* holderHash table */
|
||||||
size += hash_estimate_size(max_table_size, sizeof(HOLDER));
|
size += hash_estimate_size(max_table_size, sizeof(PROCLOCK));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since the lockHash entry count above is only an estimate, add 10%
|
* Since the lockHash entry count above is only an estimate, add 10%
|
||||||
@ -1376,7 +1376,7 @@ DumpLocks(void)
|
|||||||
{
|
{
|
||||||
PGPROC *proc;
|
PGPROC *proc;
|
||||||
SHM_QUEUE *procHolders;
|
SHM_QUEUE *procHolders;
|
||||||
HOLDER *holder;
|
PROCLOCK *holder;
|
||||||
LOCK *lock;
|
LOCK *lock;
|
||||||
int lockmethod = DEFAULT_LOCKMETHOD;
|
int lockmethod = DEFAULT_LOCKMETHOD;
|
||||||
LOCKMETHODTABLE *lockMethodTable;
|
LOCKMETHODTABLE *lockMethodTable;
|
||||||
@ -1395,8 +1395,8 @@ DumpLocks(void)
|
|||||||
if (proc->waitLock)
|
if (proc->waitLock)
|
||||||
LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
|
LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
|
||||||
|
|
||||||
holder = (HOLDER *) SHMQueueNext(procHolders, procHolders,
|
holder = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
|
||||||
offsetof(HOLDER, procLink));
|
offsetof(PROCLOCK, procLink));
|
||||||
|
|
||||||
while (holder)
|
while (holder)
|
||||||
{
|
{
|
||||||
@ -1404,11 +1404,11 @@ DumpLocks(void)
|
|||||||
|
|
||||||
lock = (LOCK *) MAKE_PTR(holder->tag.lock);
|
lock = (LOCK *) MAKE_PTR(holder->tag.lock);
|
||||||
|
|
||||||
HOLDER_PRINT("DumpLocks", holder);
|
PROCLOCK_PRINT("DumpLocks", holder);
|
||||||
LOCK_PRINT("DumpLocks", lock, 0);
|
LOCK_PRINT("DumpLocks", lock, 0);
|
||||||
|
|
||||||
holder = (HOLDER *) SHMQueueNext(procHolders, &holder->procLink,
|
holder = (PROCLOCK *) SHMQueueNext(procHolders, &holder->procLink,
|
||||||
offsetof(HOLDER, procLink));
|
offsetof(PROCLOCK, procLink));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1419,7 +1419,7 @@ void
|
|||||||
DumpAllLocks(void)
|
DumpAllLocks(void)
|
||||||
{
|
{
|
||||||
PGPROC *proc;
|
PGPROC *proc;
|
||||||
HOLDER *holder;
|
PROCLOCK *holder;
|
||||||
LOCK *lock;
|
LOCK *lock;
|
||||||
int lockmethod = DEFAULT_LOCKMETHOD;
|
int lockmethod = DEFAULT_LOCKMETHOD;
|
||||||
LOCKMETHODTABLE *lockMethodTable;
|
LOCKMETHODTABLE *lockMethodTable;
|
||||||
@ -1441,9 +1441,9 @@ DumpAllLocks(void)
|
|||||||
LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
|
LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
|
||||||
|
|
||||||
hash_seq_init(&status, holderTable);
|
hash_seq_init(&status, holderTable);
|
||||||
while ((holder = (HOLDER *) hash_seq_search(&status)) != NULL)
|
while ((holder = (PROCLOCK *) hash_seq_search(&status)) != NULL)
|
||||||
{
|
{
|
||||||
HOLDER_PRINT("DumpAllLocks", holder);
|
PROCLOCK_PRINT("DumpAllLocks", holder);
|
||||||
|
|
||||||
if (holder->tag.lock)
|
if (holder->tag.lock)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.123 2002/07/18 23:06:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.124 2002/07/19 00:17:40 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -501,7 +501,7 @@ int
|
|||||||
ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
||||||
LOCKMODE lockmode,
|
LOCKMODE lockmode,
|
||||||
LOCK *lock,
|
LOCK *lock,
|
||||||
HOLDER *holder)
|
PROCLOCK *holder)
|
||||||
{
|
{
|
||||||
LWLockId masterLock = lockMethodTable->masterLock;
|
LWLockId masterLock = lockMethodTable->masterLock;
|
||||||
PROC_QUEUE *waitQueue = &(lock->waitProcs);
|
PROC_QUEUE *waitQueue = &(lock->waitProcs);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* 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.62 2002/07/18 23:06:20 momjian Exp $
|
* $Id: lock.h,v 1.63 2002/07/19 00:17:40 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -130,7 +130,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.
|
* lockHolders -- list of PROCLOCK 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!!).
|
||||||
@ -146,7 +146,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 */
|
SHM_QUEUE lockHolders; /* list of PROCLOCK objects assoc. with lock */
|
||||||
PROC_QUEUE waitProcs; /* list of PGPROC objects waiting on lock */
|
PROC_QUEUE waitProcs; /* list of PGPROC objects waiting on lock */
|
||||||
int requested[MAX_LOCKMODES]; /* counts of requested
|
int requested[MAX_LOCKMODES]; /* counts of requested
|
||||||
* locks */
|
* locks */
|
||||||
@ -163,8 +163,8 @@ typedef struct LOCK
|
|||||||
* on the same lockable object. We need to store some per-holder information
|
* on the same lockable object. We need to store some per-holder information
|
||||||
* for each such holder (or would-be holder).
|
* for each such holder (or would-be holder).
|
||||||
*
|
*
|
||||||
* HOLDERTAG is the key information needed to look up a HOLDER item in the
|
* PROCLOCKTAG is the key information needed to look up a PROCLOCK item in the
|
||||||
* holder hashtable. A HOLDERTAG value uniquely identifies a lock holder.
|
* holder hashtable. A PROCLOCKTAG 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 PGPROC of the backend running it, and the xact's own ID) and
|
* both by the PGPROC of the backend running it, and the xact's own ID) and
|
||||||
@ -180,32 +180,32 @@ typedef struct LOCK
|
|||||||
* 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
|
* Each PROCLOCK object is linked into lists for both the associated LOCK object
|
||||||
* and the owning PGPROC object. Note that the HOLDER is entered into these
|
* and the owning PGPROC object. Note that the PROCLOCK is entered into these
|
||||||
* lists as soon as it is created, even if no lock has yet been granted.
|
* lists as soon as it is created, even if no lock has yet been granted.
|
||||||
* A PGPROC that is waiting for a lock to be granted will also be linked into
|
* A PGPROC that is waiting for a lock to be granted will also be linked into
|
||||||
* the lock's waitProcs queue.
|
* the lock's waitProcs queue.
|
||||||
*/
|
*/
|
||||||
typedef struct HOLDERTAG
|
typedef struct PROCLOCKTAG
|
||||||
{
|
{
|
||||||
SHMEM_OFFSET lock; /* link to per-lockable-object information */
|
SHMEM_OFFSET lock; /* link to per-lockable-object information */
|
||||||
SHMEM_OFFSET proc; /* link to PGPROC of owning backend */
|
SHMEM_OFFSET proc; /* link to PGPROC of owning backend */
|
||||||
TransactionId xid; /* xact ID, or InvalidTransactionId */
|
TransactionId xid; /* xact ID, or InvalidTransactionId */
|
||||||
} HOLDERTAG;
|
} PROCLOCKTAG;
|
||||||
|
|
||||||
typedef struct HOLDER
|
typedef struct PROCLOCK
|
||||||
{
|
{
|
||||||
/* tag */
|
/* tag */
|
||||||
HOLDERTAG tag; /* unique identifier of holder object */
|
PROCLOCKTAG tag; /* unique identifier of holder object */
|
||||||
|
|
||||||
/* 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 lockLink; /* list link for lock's 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 */
|
SHM_QUEUE procLink; /* list link for process's list of holders */
|
||||||
} HOLDER;
|
} PROCLOCK;
|
||||||
|
|
||||||
#define HOLDER_LOCKMETHOD(holder) \
|
#define PROCLOCK_LOCKMETHOD(holder) \
|
||||||
(((LOCK *) MAKE_PTR((holder).tag.lock))->tag.lockmethod)
|
(((LOCK *) MAKE_PTR((holder).tag.lock))->tag.lockmethod)
|
||||||
|
|
||||||
|
|
||||||
@ -225,9 +225,9 @@ extern bool LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
|
|||||||
bool allxids, TransactionId xid);
|
bool allxids, TransactionId xid);
|
||||||
extern int LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
extern int LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
|
||||||
LOCKMODE lockmode,
|
LOCKMODE lockmode,
|
||||||
LOCK *lock, HOLDER *holder, PGPROC *proc,
|
LOCK *lock, PROCLOCK *holder, PGPROC *proc,
|
||||||
int *myHolding);
|
int *myHolding);
|
||||||
extern void GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode);
|
extern void GrantLock(LOCK *lock, PROCLOCK *holder, LOCKMODE lockmode);
|
||||||
extern void RemoveFromWaitQueue(PGPROC *proc);
|
extern void RemoveFromWaitQueue(PGPROC *proc);
|
||||||
extern int LockShmemSize(int maxBackends);
|
extern int LockShmemSize(int maxBackends);
|
||||||
extern bool DeadLockCheck(PGPROC *proc);
|
extern bool DeadLockCheck(PGPROC *proc);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* 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.58 2002/07/13 01:02:14 momjian Exp $
|
* $Id: proc.h,v 1.59 2002/07/19 00:17:40 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -61,12 +61,12 @@ struct PGPROC
|
|||||||
/* 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. */
|
/* 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 */
|
PROCLOCK *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 heldLocks; /* bitmask for lock types already held on
|
LOCKMASK heldLocks; /* bitmask for lock types already held on
|
||||||
* this lock object by this backend */
|
* this lock object by this backend */
|
||||||
|
|
||||||
SHM_QUEUE procHolders; /* list of HOLDER objects for locks held
|
SHM_QUEUE procHolders; /* list of PROCLOCK objects for locks held
|
||||||
* or awaited by this backend */
|
* or awaited by this backend */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ extern void ProcReleaseLocks(bool isCommit);
|
|||||||
|
|
||||||
extern void ProcQueueInit(PROC_QUEUE *queue);
|
extern void ProcQueueInit(PROC_QUEUE *queue);
|
||||||
extern int ProcSleep(LOCKMETHODTABLE *lockMethodTable, LOCKMODE lockmode,
|
extern int ProcSleep(LOCKMETHODTABLE *lockMethodTable, LOCKMODE lockmode,
|
||||||
LOCK *lock, HOLDER *holder);
|
LOCK *lock, PROCLOCK *holder);
|
||||||
extern PGPROC *ProcWakeup(PGPROC *proc, int errType);
|
extern PGPROC *ProcWakeup(PGPROC *proc, int errType);
|
||||||
extern void ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock);
|
extern void ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock);
|
||||||
extern bool LockWaitCancel(void);
|
extern bool LockWaitCancel(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user