Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
b75fcf93
Commit
b75fcf93
authored
Jul 19, 2002
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Complete TODO item:
* -HOLDER/HOLDERTAB rename to PROCLOCK/PROCLOCKTAG
parent
97377048
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
200 additions
and
194 deletions
+200
-194
src/backend/storage/lmgr/README
src/backend/storage/lmgr/README
+112
-106
src/backend/storage/lmgr/deadlock.c
src/backend/storage/lmgr/deadlock.c
+6
-6
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/lock.c
+61
-61
src/backend/storage/lmgr/proc.c
src/backend/storage/lmgr/proc.c
+2
-2
src/include/storage/lock.h
src/include/storage/lock.h
+15
-15
src/include/storage/proc.h
src/include/storage/proc.h
+4
-4
No files found.
src/backend/storage/lmgr/README
View file @
b75fcf93
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.1
0 2002/04/15 23:46:13
momjian Exp $
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.1
1 2002/07/19 00:17:40
momjian Exp $
LOCKING OVERVIEW
LOCKING OVERVIEW
...
@@ -7,38 +7,40 @@ Postgres uses three types of interprocess locks:
...
@@ -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
access to datastructures in shared memory. LWLocks support both exclusive
* Lightweight locks (LWLocks). These locks are typically used to
and shared lock modes (for read/write and read-only access to a shared object).
interlock access to datastructures in shared memory. LWLocks support
There is no provision for deadlock detection, but the LWLock manager will
both exclusive and shared lock modes (for read/write and read-only
automatically release held LWLocks during elog() recovery, so it is safe to
access to a shared object). There is no provision for deadlock
raise an error while holding LWLocks. Obtaining or releasing an LWLock is
detection, but the LWLock manager will automatically release held
quite fast (a few dozen instructions) when there is no contention for the
LWLocks during elog() recovery, so it is safe to raise an error while
lock. When a process has to wait for an LWLock, it blocks on a SysV semaphore
holding LWLocks. Obtaining or releasing an LWLock is quite fast (a few
so as to not consume CPU time. Waiting processes will be granted the lock
dozen instructions) when there is no contention for the lock. When a
in arrival order. There is no timeout.
process has to wait for an LWLock, it blocks on a SysV semaphore so as
to not consume CPU time. Waiting processes will be granted the lock in
* Regular locks (a/k/a heavyweight locks). The regular lock manager supports
arrival order. There is no timeout.
a variety of lock modes with table-driven semantics, and it has full deadlock
detection and automatic release at transaction end. Regular locks should be
* Regular locks (a/k/a heavyweight locks). The regular lock manager
used for all user-driven lock requests.
supports a variety of lock modes with table-driven semantics, and it has
full deadlock detection and automatic release at transaction end.
Acquisition of either a spinlock or a lightweight lock causes query cancel
Regular locks should be used for all user-driven lock requests.
and die() interrupts to be held off until all such locks are released.
No such restriction exists for regular locks, however. Also note that we
Acquisition of either a spinlock or a lightweight lock causes query
can accept query cancel and die() interrupts while waiting for a regular
cancel and die() interrupts to be held off until all such locks are
lock, but we will not accept them while waiting for spinlocks or LW locks.
released. No such restriction exists for regular locks, however. Also
It is therefore not a good idea to use LW locks when the wait time might
note that we can accept query cancel and die() interrupts while waiting
exceed a few seconds.
for a regular lock, but we will not accept them while waiting for
spinlocks or LW locks. It is therefore not a good idea to use LW locks
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.
...
@@ -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 -
...
@@ -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
HOLDER
s are in this
the lock object. Note that both granted and waiting
PROCLOCK
s 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.
...
@@ -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 -
...
@@ -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
...
@@ -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
...
@@ -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
t
o cancel one request to remove the cycle; we don't need to kill all the
t
hat 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
...
@@ -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.
src/backend/storage/lmgr/deadlock.c
View file @
b75fcf93
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/deadlock.c,v 1.1
1 2002/07/18 23:06:19
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/deadlock.c,v 1.1
2 2002/07/19 00:17:40
momjian Exp $
*
*
* Interface:
* Interface:
*
*
...
@@ -377,7 +377,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
...
@@ -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,
...
@@ -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,
...
@@ -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
));
}
}
/*
/*
...
...
src/backend/storage/lmgr/lock.c
View file @
b75fcf93
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.1
09 2002/07/18 23:06:19
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.1
10 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 */
...
@@ -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)
...
@@ -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)
...
@@ -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,
...
@@ -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
(
HOLDER
TAG
);
info
.
keysize
=
sizeof
(
PROCLOCK
TAG
);
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
...
@@ -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
;
HOLDER
TAG
holdertag
;
PROCLOCK
TAG
holdertag
;
HTAB
*
holderTable
;
HTAB
*
holderTable
;
bool
found
;
bool
found
;
LOCK
*
lock
;
LOCK
*
lock
;
...
@@ -513,7 +513,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
...
@@ -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
(
HOLDER
TAG
));
/* must clear padding,
MemSet
(
&
holdertag
,
0
,
sizeof
(
PROCLOCK
TAG
));
/* 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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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
...
@@ -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,
...
@@ -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,
...
@@ -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
...
@@ -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)
...
@@ -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)
...
@@ -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)
...
@@ -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,
...
@@ -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
;
HOLDER
TAG
holdertag
;
PROCLOCK
TAG
holdertag
;
HTAB
*
holderTable
;
HTAB
*
holderTable
;
bool
wakeupNeeded
=
false
;
bool
wakeupNeeded
=
false
;
...
@@ -1031,14 +1031,14 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
...
@@ -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
(
HOLDER
TAG
));
/* must clear padding,
MemSet
(
&
holdertag
,
0
,
sizeof
(
PROCLOCK
TAG
));
/* 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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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,
...
@@ -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)
...
@@ -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)
...
@@ -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)
...
@@ -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)
...
@@ -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
...
@@ -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)
...
@@ -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
)
{
{
...
...
src/backend/storage/lmgr/proc.c
View file @
b75fcf93
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.12
3 2002/07/18 23:06:2
0 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.12
4 2002/07/19 00:17:4
0 momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -501,7 +501,7 @@ int
...
@@ -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
);
...
...
src/include/storage/lock.h
View file @
b75fcf93
...
@@ -7,7 +7,7 @@
...
@@ -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.6
2 2002/07/18 23:06:2
0 momjian Exp $
* $Id: lock.h,v 1.6
3 2002/07/19 00:17:4
0 momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -130,7 +130,7 @@ typedef struct LOCKTAG
...
@@ -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
...
@@ -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
...
@@ -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
HOLDER
TAG value uniquely identifies a lock holder.
* holder hashtable. A
PROCLOCK
TAG 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
...
@@ -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
HOLDER
TAG
typedef
struct
PROCLOCK
TAG
{
{
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 */
}
HOLDER
TAG
;
}
PROCLOCK
TAG
;
typedef
struct
HOLDER
typedef
struct
PROCLOCK
{
{
/* tag */
/* tag */
HOLDER
TAG
tag
;
/* unique identifier of holder object */
PROCLOCK
TAG
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,
...
@@ -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
);
...
...
src/include/storage/proc.h
View file @
b75fcf93
...
@@ -7,7 +7,7 @@
...
@@ -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.5
8 2002/07/13 01:02:14
momjian Exp $
* $Id: proc.h,v 1.5
9 2002/07/19 00:17:40
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -61,12 +61,12 @@ struct PGPROC
...
@@ -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);
...
@@ -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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment