Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
b75fcf93
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
b75fcf93
编写于
7月 19, 2002
作者:
B
Bruce Momjian
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Complete TODO item:
* -HOLDER/HOLDERTAB rename to PROCLOCK/PROCLOCKTAG
上级
97377048
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
200 addition
and
194 deletion
+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
未找到文件。
src/backend/storage/lmgr/README
浏览文件 @
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
...
...
@@ -7,38 +7,40 @@ Postgres uses three types of interprocess locks:
* 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
kernel call (or even a call to a nontrivial subroutine), don't use a spinlock.
Spinlocks are primarily used as infrastructure for lightweight locks.
They are implemented using a hardware atomic-test-and-set instruction,
if available. Waiting processes busy-loop until they can get the lock.
There is no provision for deadlock detection, automatic release on error,
or any other nicety. There is a timeout if the lock cannot be gotten after
a minute or so (which is approximately forever in 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
and shared lock modes (for read/write and read-only access to a shared object).
There is no provision for deadlock detection, but the LWLock manager will
automatically release held LWLocks during elog() recovery, so it is safe to
raise an error while holding LWLocks. Obtaining or releasing an LWLock is
quite fast (a few dozen instructions) when there is no contention for the
lock. When a 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 arrival order. There is no timeout.
* Regular locks (a/k/a heavyweight locks). The regular lock manager supports
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
used for all user-driven lock requests.
Acquisition of either a spinlock or a lightweight lock causes query cancel
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
can accept query cancel and die() interrupts while waiting 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.
kernel call (or even a call to a nontrivial subroutine), don't use a
spinlock. Spinlocks are primarily used as infrastructure for lightweight
locks. They are implemented using a hardware atomic-test-and-set
instruction, if available. Waiting processes busy-loop until they can
get the lock. There is no provision for deadlock detection, automatic
release on error, or any other nicety. There is a timeout if the lock
cannot be gotten after a minute or so (which is approximately forever in
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 and shared lock modes (for read/write and read-only
access to a shared object). There is no provision for deadlock
detection, but the LWLock manager will automatically release held
LWLocks during elog() recovery, so it is safe to raise an error while
holding LWLocks. Obtaining or releasing an LWLock is quite fast (a few
dozen instructions) when there is no contention for the lock. When a
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
arrival order. There is no timeout.
* Regular locks (a/k/a heavyweight locks). The regular lock manager
supports 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 used for all user-driven lock requests.
Acquisition of either a spinlock or a lightweight lock causes query
cancel 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 can accept query cancel and die() interrupts while waiting
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.
...
...
@@ -46,9 +48,9 @@ The rest of this README file discusses the regular lock manager in detail.
LOCK DATA STRUCTURES
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.
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 methods describe the overall locking behavior. Currently there are
...
...
@@ -102,9 +104,9 @@ waitMask -
is 1 if and only if requested[i] > granted[i].
lockHolders -
This is a shared memory queue of all the
HOLDER
structs associated with
the lock object. Note that both granted and waiting
HOLDER
s are in this
list (indeed, the same
HOLDER
might have some already-granted locks and
This is a shared memory queue of all the
PROCLOCK
structs associated with
the lock object. Note that both granted and waiting
PROCLOCK
s are in this
list (indeed, the same
PROCLOCK
might have some already-granted locks and
be waiting for more!).
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 -
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.
tag.lock
SHMEM offset of the LOCK object this
holder
is for.
SHMEM offset of the LOCK object this
PROCLOCK
is for.
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
XID of transaction this
holder
is for, or InvalidTransactionId
if the
holder
is for session-level locking.
XID of transaction this
PROCLOCK
is for, or InvalidTransactionId
if the
PROCLOCK
is for session-level locking.
Note that this structure will support multiple transactions running
concurrently in one backend, which may be handy if we someday decide
...
...
@@ -169,18 +171,18 @@ tag -
transaction operations like VACUUM.
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!
nHolding -
Sum of the holding[] array.
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.
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.
---------------------------------------------------------------------------
...
...
@@ -193,47 +195,48 @@ fairly standard in essence, but there are many special considerations
needed to deal with Postgres' generalized locking model.
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
the overhead of deadlock handling as much as possible. We do this using
an "optimistic waiting" approach: if a process cannot acquire the lock
it wants immediately, it goes to sleep without any deadlock check. But
it also sets a delay timer, with a delay of DeadlockTimeout milliseconds
(typically set to one second). If the delay expires before the process is
granted the lock it wants, it runs the deadlock detection/breaking code.
Normally this code will determine that there is no deadlock condition,
and then the process will go back to sleep and wait quietly until it is
granted the lock. But if a deadlock condition does exist, it will be
resolved, usually by aborting the detecting process' transaction. In this
way, we avoid deadlock handling overhead whenever the wait time for a lock
is less than DeadlockTimeout, while not imposing an unreasonable delay of
detection when there is an error.
(lock grant and release) run quickly when there is no deadlock, and
avoid the overhead of deadlock handling as much as possible. We do this
using an "optimistic waiting" approach: if a process cannot acquire the
lock it wants immediately, it goes to sleep without any deadlock check.
But it also sets a delay timer, with a delay of DeadlockTimeout
milliseconds (typically set to one second). If the delay expires before
the process is granted the lock it wants, it runs the deadlock
detection/breaking code. Normally this code will determine that there is
no deadlock condition, and then the process will go back to sleep and
wait quietly until it is granted the lock. But if a deadlock condition
does exist, it will be resolved, usually by aborting the detecting
process' transaction. In this way, we avoid deadlock handling overhead
whenever the wait time for a lock is less than DeadlockTimeout, while
not imposing an unreasonable delay of
detection when there is an error.
Lock acquisition (routines LockAcquire and ProcSleep) follows these rules:
1. A lock request is granted immediately if it does not conflict with
any
existing or waiting lock request, or if the process already holds an
1. A lock request is granted immediately if it does not conflict with
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
lock twice). Note that a process never conflicts with itself, eg one can
obtain read lock when one already holds exclusive lock.
2. Otherwise the process joins the lock's wait queue. Normally it will be
added to the end of the queue, but there is an exception: if the process
already holds locks on this same lockable object that conflict with the
request of any pending waiter, then the process will be inserted in the
wait queue just ahead of the first such waiter. (If we did not make this
check, the deadlock detection code would adjust the queue order to resolve
the conflict, but it's relatively cheap to make the check in ProcSleep and
avoid a deadlock timeout delay in this case.) Note special case when
inserting before the end of the queue: if the process's request does not
conflict with any existing lock nor any waiting request before its insertion
point, then go ahead and grant the lock without waiting.
lock twice). Note that a process never conflicts with itself, eg one
can obtain read lock when one already holds exclusive lock.
2. Otherwise the process joins the lock's wait queue. Normally it will
be added to the end of the queue, but there is an exception: if the
process already holds locks on this same lockable object that conflict
with the request of any pending waiter, then the process will be
inserted in the wait queue just ahead of the first such waiter. (If we
did not make this check, the deadlock detection code would adjust the
queue order to resolve the conflict, but it's relatively cheap to make
the check in ProcSleep and avoid a deadlock timeout delay in this case.)
Note special case when inserting before the end of the queue: if the
process's request does not conflict with any existing lock nor any
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
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
not conflict with the requests of prior un-wakable waiters. Rule (b)
ensures that conflicting requests are granted in order of arrival.
There
are cases where a later waiter must be allowed to go in front of
ensures that conflicting requests are granted in order of arrival.
There
are cases where a later waiter must be allowed to go in front of
conflicting earlier waiters to avoid deadlock, but it is not
ProcLockWakeup's responsibility to recognize these cases; instead, the
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
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
lock. There is a deadlock condition if and only if the WFG contains
a cycle. We detect cycles by searching outward along waits-for edges
to
see if we return to our starting point. There are three possible
lock. There is a deadlock condition if and only if the WFG contains
a
cycle. We detect cycles by searching outward along waits-for edges to
see if we return to our starting point. There are three possible
outcomes:
1. All outgoing paths terminate at a running process (which has no
outgoing edge).
2. A deadlock is detected by looping back to the start point. We
resolve
such a deadlock by canceling the start point's lock request and reporting
an error in that transaction, which normally leads to transaction abort
and release of that transaction's held locks. Note that it's sufficient
t
o cancel one request to remove the cycle; we don't need to kill all the
transactions involved.
2. A deadlock is detected by looping back to the start point. We
resolve such a deadlock by canceling the start point's lock request and
reporting an error in that transaction, which normally leads to
transaction abort and release of that transaction's held locks. Note
t
hat it's sufficient to cancel one request to remove the cycle; we don't
need to kill all the
transactions involved.
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.
We ignore this condition on the grounds that resolving such a deadlock
is the responsibility of the processes involved --- killing our start-
point process would not resolve the deadlock. So, cases 1 and 3 both
report "no deadlock".
indicates a deadlock, but one that does not involve our starting
process. We ignore this condition on the grounds that resolving such a
deadlock is the responsibility of the processes involved --- killing our
start- point process would not resolve the deadlock. So, cases 1 and 3
both
report "no deadlock".
Postgres' situation is a little more complex than the standard discussion
of deadlock detection, for two reasons:
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
with the waiter's request. This creates no real difficulty however; we
simply need to be prepared to trace more than one outgoing edge.
might be multiple PROCLOCKs of (non-conflicting) lock types that all
conflict with the waiter's request. This creates no real difficulty
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
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
waiters.
4. We can minimize excess rearrangement-trial work by being careful to scan
the wait queue from the front when looking for soft edges. For example,
if we have queue order A,B,C and C has deadlock conflicts with both A and B,
we want to generate the "C before A" constraint first, rather than wasting
time with "C before B", which won't move C far enough up. So we look for
soft edges outgoing from C starting at the front of the wait queue.
4. We can minimize excess rearrangement-trial work by being careful to
scan the wait queue from the front when looking for soft edges. For
example, if we have queue order A,B,C and C has deadlock conflicts with
both A and B, we want to generate the "C before A" constraint first,
rather than wasting time with "C before B", which won't move C far
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
be limited to numbers of entries computed from MaxBackends. Therefore,
we can allocate the worst-case space needed during backend startup.
This seems a safer approach than trying to allocate workspace on the fly;
we don't want to risk having the deadlock detector run out of memory,
else we really have no guarantees at all that deadlock will be detected.
we can allocate the worst-case space needed during backend startup. This
seems a safer approach than trying to allocate workspace on the fly; we
don't want to risk having the deadlock detector run out of memory, else
we really have no guarantees at all that deadlock will be detected.
src/backend/storage/lmgr/deadlock.c
浏览文件 @
b75fcf93
...
...
@@ -12,7 +12,7 @@
*
*
* 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:
*
...
...
@@ -377,7 +377,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
{
PGPROC
*
proc
;
LOCK
*
lock
;
HOLDER
*
holder
;
PROCLOCK
*
holder
;
SHM_QUEUE
*
lockHolders
;
LOCKMETHODTABLE
*
lockMethodTable
;
PROC_QUEUE
*
waitQueue
;
...
...
@@ -427,8 +427,8 @@ FindLockCycleRecurse(PGPROC *checkProc,
*/
lockHolders
=
&
(
lock
->
lockHolders
);
holder
=
(
HOLDER
*
)
SHMQueueNext
(
lockHolders
,
lockHolders
,
offsetof
(
HOLDER
,
lockLink
));
holder
=
(
PROCLOCK
*
)
SHMQueueNext
(
lockHolders
,
lockHolders
,
offsetof
(
PROCLOCK
,
lockLink
));
while
(
holder
)
{
...
...
@@ -451,8 +451,8 @@ FindLockCycleRecurse(PGPROC *checkProc,
}
}
holder
=
(
HOLDER
*
)
SHMQueueNext
(
lockHolders
,
&
holder
->
lockLink
,
offsetof
(
HOLDER
,
lockLink
));
holder
=
(
PROCLOCK
*
)
SHMQueueNext
(
lockHolders
,
&
holder
->
lockLink
,
offsetof
(
PROCLOCK
,
lockLink
));
}
/*
...
...
src/backend/storage/lmgr/lock.c
浏览文件 @
b75fcf93
...
...
@@ -8,7 +8,7 @@
*
*
* 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
* 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
,
LOCK
*
lock
,
HOLDER
*
holder
);
LOCK
*
lock
,
PROCLOCK
*
holder
);
static
void
LockCountMyLocks
(
SHMEM_OFFSET
lockOffset
,
PGPROC
*
proc
,
int
*
myHolding
);
...
...
@@ -125,18 +125,18 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
inline
static
void
HOLDER_PRINT
(
const
char
*
where
,
const
HOLDER
*
holderP
)
PROCLOCK_PRINT
(
const
char
*
where
,
const
PROCLOCK
*
holderP
)
{
if
(
(((
HOLDER
_LOCKMETHOD
(
*
holderP
)
==
DEFAULT_LOCKMETHOD
&&
Trace_locks
)
||
(
HOLDER
_LOCKMETHOD
(
*
holderP
)
==
USER_LOCKMETHOD
&&
Trace_userlocks
))
(((
PROCLOCK
_LOCKMETHOD
(
*
holderP
)
==
DEFAULT_LOCKMETHOD
&&
Trace_locks
)
||
(
PROCLOCK
_LOCKMETHOD
(
*
holderP
)
==
USER_LOCKMETHOD
&&
Trace_userlocks
))
&&
(((
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
))
)
elog
(
LOG
,
"%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
,
HOLDER
_LOCKMETHOD
(
*
(
holderP
)),
PROCLOCK
_LOCKMETHOD
(
*
(
holderP
)),
holderP
->
tag
.
proc
,
holderP
->
tag
.
xid
,
holderP
->
holding
[
1
],
holderP
->
holding
[
2
],
holderP
->
holding
[
3
],
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 */
#define LOCK_PRINT(where, lock, type)
#define
HOLDER
_PRINT(where, holderP)
#define
PROCLOCK
_PRINT(where, holderP)
#endif
/* not LOCK_DEBUG */
...
...
@@ -316,11 +316,11 @@ LockMethodTableInit(char *tabName,
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.
*/
info
.
keysize
=
sizeof
(
HOLDER
TAG
);
info
.
entrysize
=
sizeof
(
HOLDER
);
info
.
keysize
=
sizeof
(
PROCLOCK
TAG
);
info
.
entrysize
=
sizeof
(
PROCLOCK
);
info
.
hash
=
tag_hash
;
hash_flags
=
(
HASH_ELEM
|
HASH_FUNCTION
);
...
...
@@ -440,8 +440,8 @@ bool
LockAcquire
(
LOCKMETHOD
lockmethod
,
LOCKTAG
*
locktag
,
TransactionId
xid
,
LOCKMODE
lockmode
,
bool
dontWait
)
{
HOLDER
*
holder
;
HOLDER
TAG
holdertag
;
PROCLOCK
*
holder
;
PROCLOCK
TAG
holdertag
;
HTAB
*
holderTable
;
bool
found
;
LOCK
*
lock
;
...
...
@@ -513,7 +513,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
/*
* 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 */
holdertag
.
lock
=
MAKE_OFFSET
(
lock
);
holdertag
.
proc
=
MAKE_OFFSET
(
MyProc
);
...
...
@@ -523,7 +523,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
* Find or create a holder entry with this tag
*/
holderTable
=
lockMethodTable
->
holderHash
;
holder
=
(
HOLDER
*
)
hash_search
(
holderTable
,
holder
=
(
PROCLOCK
*
)
hash_search
(
holderTable
,
(
void
*
)
&
holdertag
,
HASH_ENTER
,
&
found
);
if
(
!
holder
)
...
...
@@ -543,11 +543,11 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
/* Add holder to appropriate lists */
SHMQueueInsertBefore
(
&
lock
->
lockHolders
,
&
holder
->
lockLink
);
SHMQueueInsertBefore
(
&
MyProc
->
procHolders
,
&
holder
->
procLink
);
HOLDER
_PRINT
(
"LockAcquire: new"
,
holder
);
PROCLOCK
_PRINT
(
"LockAcquire: new"
,
holder
);
}
else
{
HOLDER
_PRINT
(
"LockAcquire: found"
,
holder
);
PROCLOCK
_PRINT
(
"LockAcquire: found"
,
holder
);
Assert
((
holder
->
nHolding
>=
0
)
&&
(
holder
->
holding
[
lockmode
]
>=
0
));
Assert
(
holder
->
nHolding
<=
lock
->
nGranted
);
...
...
@@ -600,7 +600,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
if
(
holder
->
holding
[
lockmode
]
>
0
)
{
GrantLock
(
lock
,
holder
,
lockmode
);
HOLDER
_PRINT
(
"LockAcquire: owning"
,
holder
);
PROCLOCK
_PRINT
(
"LockAcquire: owning"
,
holder
);
LWLockRelease
(
masterLock
);
return
TRUE
;
}
...
...
@@ -613,7 +613,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
if
(
myHolding
[
lockmode
]
>
0
)
{
GrantLock
(
lock
,
holder
,
lockmode
);
HOLDER
_PRINT
(
"LockAcquire: my other XID owning"
,
holder
);
PROCLOCK
_PRINT
(
"LockAcquire: my other XID owning"
,
holder
);
LWLockRelease
(
masterLock
);
return
TRUE
;
}
...
...
@@ -650,14 +650,14 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
{
SHMQueueDelete
(
&
holder
->
lockLink
);
SHMQueueDelete
(
&
holder
->
procLink
);
holder
=
(
HOLDER
*
)
hash_search
(
holderTable
,
holder
=
(
PROCLOCK
*
)
hash_search
(
holderTable
,
(
void
*
)
holder
,
HASH_REMOVE
,
NULL
);
if
(
!
holder
)
elog
(
WARNING
,
"LockAcquire: remove holder, table corrupted"
);
}
else
HOLDER
_PRINT
(
"LockAcquire: NHOLDING"
,
holder
);
PROCLOCK
_PRINT
(
"LockAcquire: NHOLDING"
,
holder
);
lock
->
nRequested
--
;
lock
->
requested
[
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
)))
{
HOLDER
_PRINT
(
"LockAcquire: INCONSISTENT"
,
holder
);
PROCLOCK
_PRINT
(
"LockAcquire: INCONSISTENT"
,
holder
);
LOCK_PRINT
(
"LockAcquire: INCONSISTENT"
,
lock
,
lockmode
);
/* Should we retry ? */
LWLockRelease
(
masterLock
);
return
FALSE
;
}
HOLDER
_PRINT
(
"LockAcquire: granted"
,
holder
);
PROCLOCK
_PRINT
(
"LockAcquire: granted"
,
holder
);
LOCK_PRINT
(
"LockAcquire: granted"
,
lock
,
lockmode
);
}
...
...
@@ -737,7 +737,7 @@ int
LockCheckConflicts
(
LOCKMETHODTABLE
*
lockMethodTable
,
LOCKMODE
lockmode
,
LOCK
*
lock
,
HOLDER
*
holder
,
PROCLOCK
*
holder
,
PGPROC
*
proc
,
int
*
myHolding
)
/* myHolding[] array or NULL */
{
...
...
@@ -758,7 +758,7 @@ LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
*/
if
(
!
(
lockMethodTable
->
conflictTab
[
lockmode
]
&
lock
->
grantMask
))
{
HOLDER
_PRINT
(
"LockCheckConflicts: no conflict"
,
holder
);
PROCLOCK
_PRINT
(
"LockCheckConflicts: no conflict"
,
holder
);
return
STATUS_OK
;
}
...
...
@@ -792,11 +792,11 @@ LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
if
(
!
(
lockMethodTable
->
conflictTab
[
lockmode
]
&
bitmask
))
{
/* no conflict. OK to get the lock */
HOLDER
_PRINT
(
"LockCheckConflicts: resolved"
,
holder
);
PROCLOCK
_PRINT
(
"LockCheckConflicts: resolved"
,
holder
);
return
STATUS_OK
;
}
HOLDER
_PRINT
(
"LockCheckConflicts: conflicting"
,
holder
);
PROCLOCK
_PRINT
(
"LockCheckConflicts: conflicting"
,
holder
);
return
STATUS_FOUND
;
}
...
...
@@ -814,13 +814,13 @@ static void
LockCountMyLocks
(
SHMEM_OFFSET
lockOffset
,
PGPROC
*
proc
,
int
*
myHolding
)
{
SHM_QUEUE
*
procHolders
=
&
(
proc
->
procHolders
);
HOLDER
*
holder
;
PROCLOCK
*
holder
;
int
i
;
MemSet
(
myHolding
,
0
,
MAX_LOCKMODES
*
sizeof
(
int
));
holder
=
(
HOLDER
*
)
SHMQueueNext
(
procHolders
,
procHolders
,
offsetof
(
HOLDER
,
procLink
));
holder
=
(
PROCLOCK
*
)
SHMQueueNext
(
procHolders
,
procHolders
,
offsetof
(
PROCLOCK
,
procLink
));
while
(
holder
)
{
...
...
@@ -830,8 +830,8 @@ LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding)
myHolding
[
i
]
+=
holder
->
holding
[
i
];
}
holder
=
(
HOLDER
*
)
SHMQueueNext
(
procHolders
,
&
holder
->
procLink
,
offsetof
(
HOLDER
,
procLink
));
holder
=
(
PROCLOCK
*
)
SHMQueueNext
(
procHolders
,
&
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.
*/
void
GrantLock
(
LOCK
*
lock
,
HOLDER
*
holder
,
LOCKMODE
lockmode
)
GrantLock
(
LOCK
*
lock
,
PROCLOCK
*
holder
,
LOCKMODE
lockmode
)
{
lock
->
nGranted
++
;
lock
->
granted
[
lockmode
]
++
;
...
...
@@ -868,7 +868,7 @@ GrantLock(LOCK *lock, HOLDER *holder, LOCKMODE lockmode)
*/
static
int
WaitOnLock
(
LOCKMETHOD
lockmethod
,
LOCKMODE
lockmode
,
LOCK
*
lock
,
HOLDER
*
holder
)
LOCK
*
lock
,
PROCLOCK
*
holder
)
{
LOCKMETHODTABLE
*
lockMethodTable
=
LockMethodTable
[
lockmethod
];
char
*
new_status
,
...
...
@@ -984,8 +984,8 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
LOCK
*
lock
;
LWLockId
masterLock
;
LOCKMETHODTABLE
*
lockMethodTable
;
HOLDER
*
holder
;
HOLDER
TAG
holdertag
;
PROCLOCK
*
holder
;
PROCLOCK
TAG
holdertag
;
HTAB
*
holderTable
;
bool
wakeupNeeded
=
false
;
...
...
@@ -1031,14 +1031,14 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
/*
* 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 */
holdertag
.
lock
=
MAKE_OFFSET
(
lock
);
holdertag
.
proc
=
MAKE_OFFSET
(
MyProc
);
TransactionIdStore
(
xid
,
&
holdertag
.
xid
);
holderTable
=
lockMethodTable
->
holderHash
;
holder
=
(
HOLDER
*
)
hash_search
(
holderTable
,
holder
=
(
PROCLOCK
*
)
hash_search
(
holderTable
,
(
void
*
)
&
holdertag
,
HASH_FIND_SAVE
,
NULL
);
if
(
!
holder
)
...
...
@@ -1052,7 +1052,7 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
elog
(
WARNING
,
"LockRelease: holder table corrupted"
);
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
...
...
@@ -1060,7 +1060,7 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
*/
if
(
!
(
holder
->
holding
[
lockmode
]
>
0
))
{
HOLDER
_PRINT
(
"LockRelease: WRONGTYPE"
,
holder
);
PROCLOCK
_PRINT
(
"LockRelease: WRONGTYPE"
,
holder
);
Assert
(
holder
->
holding
[
lockmode
]
>=
0
);
LWLockRelease
(
masterLock
);
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
->
nHolding
--
;
HOLDER
_PRINT
(
"LockRelease: updated"
,
holder
);
PROCLOCK
_PRINT
(
"LockRelease: updated"
,
holder
);
Assert
((
holder
->
nHolding
>=
0
)
&&
(
holder
->
holding
[
lockmode
]
>=
0
));
/*
...
...
@@ -1137,10 +1137,10 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag,
*/
if
(
holder
->
nHolding
==
0
)
{
HOLDER
_PRINT
(
"LockRelease: deleting"
,
holder
);
PROCLOCK
_PRINT
(
"LockRelease: deleting"
,
holder
);
SHMQueueDelete
(
&
holder
->
lockLink
);
SHMQueueDelete
(
&
holder
->
procLink
);
holder
=
(
HOLDER
*
)
hash_search
(
holderTable
,
holder
=
(
PROCLOCK
*
)
hash_search
(
holderTable
,
(
void
*
)
&
holder
,
HASH_REMOVE_SAVED
,
NULL
);
if
(
!
holder
)
...
...
@@ -1177,8 +1177,8 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
bool
allxids
,
TransactionId
xid
)
{
SHM_QUEUE
*
procHolders
=
&
(
proc
->
procHolders
);
HOLDER
*
holder
;
HOLDER
*
nextHolder
;
PROCLOCK
*
holder
;
PROCLOCK
*
nextHolder
;
LWLockId
masterLock
;
LOCKMETHODTABLE
*
lockMethodTable
;
int
i
,
...
...
@@ -1204,16 +1204,16 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
LWLockAcquire
(
masterLock
,
LW_EXCLUSIVE
);
holder
=
(
HOLDER
*
)
SHMQueueNext
(
procHolders
,
procHolders
,
offsetof
(
HOLDER
,
procLink
));
holder
=
(
PROCLOCK
*
)
SHMQueueNext
(
procHolders
,
procHolders
,
offsetof
(
PROCLOCK
,
procLink
));
while
(
holder
)
{
bool
wakeupNeeded
=
false
;
/* Get link first, since we may unlink/delete this holder */
nextHolder
=
(
HOLDER
*
)
SHMQueueNext
(
procHolders
,
&
holder
->
procLink
,
offsetof
(
HOLDER
,
procLink
));
nextHolder
=
(
PROCLOCK
*
)
SHMQueueNext
(
procHolders
,
&
holder
->
procLink
,
offsetof
(
PROCLOCK
,
procLink
));
Assert
(
holder
->
tag
.
proc
==
MAKE_OFFSET
(
proc
));
...
...
@@ -1227,7 +1227,7 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
if
(
!
allxids
&&
!
TransactionIdEquals
(
xid
,
holder
->
tag
.
xid
))
goto
next_item
;
HOLDER
_PRINT
(
"LockReleaseAll"
,
holder
);
PROCLOCK
_PRINT
(
"LockReleaseAll"
,
holder
);
LOCK_PRINT
(
"LockReleaseAll"
,
lock
,
0
);
Assert
(
lock
->
nRequested
>=
0
);
Assert
(
lock
->
nGranted
>=
0
);
...
...
@@ -1281,7 +1281,7 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
}
LOCK_PRINT
(
"LockReleaseAll: updated"
,
lock
,
0
);
HOLDER
_PRINT
(
"LockReleaseAll: deleting"
,
holder
);
PROCLOCK
_PRINT
(
"LockReleaseAll: deleting"
,
holder
);
/*
* Remove the holder entry from the linked lists
...
...
@@ -1292,7 +1292,7 @@ LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
/*
* remove the holder entry from the hashtable
*/
holder
=
(
HOLDER
*
)
hash_search
(
lockMethodTable
->
holderHash
,
holder
=
(
PROCLOCK
*
)
hash_search
(
lockMethodTable
->
holderHash
,
(
void
*
)
holder
,
HASH_REMOVE
,
NULL
);
...
...
@@ -1353,7 +1353,7 @@ LockShmemSize(int maxBackends)
size
+=
hash_estimate_size
(
max_table_size
,
sizeof
(
LOCK
));
/* 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%
...
...
@@ -1376,7 +1376,7 @@ DumpLocks(void)
{
PGPROC
*
proc
;
SHM_QUEUE
*
procHolders
;
HOLDER
*
holder
;
PROCLOCK
*
holder
;
LOCK
*
lock
;
int
lockmethod
=
DEFAULT_LOCKMETHOD
;
LOCKMETHODTABLE
*
lockMethodTable
;
...
...
@@ -1395,8 +1395,8 @@ DumpLocks(void)
if
(
proc
->
waitLock
)
LOCK_PRINT
(
"DumpLocks: waiting on"
,
proc
->
waitLock
,
0
);
holder
=
(
HOLDER
*
)
SHMQueueNext
(
procHolders
,
procHolders
,
offsetof
(
HOLDER
,
procLink
));
holder
=
(
PROCLOCK
*
)
SHMQueueNext
(
procHolders
,
procHolders
,
offsetof
(
PROCLOCK
,
procLink
));
while
(
holder
)
{
...
...
@@ -1404,11 +1404,11 @@ DumpLocks(void)
lock
=
(
LOCK
*
)
MAKE_PTR
(
holder
->
tag
.
lock
);
HOLDER
_PRINT
(
"DumpLocks"
,
holder
);
PROCLOCK
_PRINT
(
"DumpLocks"
,
holder
);
LOCK_PRINT
(
"DumpLocks"
,
lock
,
0
);
holder
=
(
HOLDER
*
)
SHMQueueNext
(
procHolders
,
&
holder
->
procLink
,
offsetof
(
HOLDER
,
procLink
));
holder
=
(
PROCLOCK
*
)
SHMQueueNext
(
procHolders
,
&
holder
->
procLink
,
offsetof
(
PROCLOCK
,
procLink
));
}
}
...
...
@@ -1419,7 +1419,7 @@ void
DumpAllLocks
(
void
)
{
PGPROC
*
proc
;
HOLDER
*
holder
;
PROCLOCK
*
holder
;
LOCK
*
lock
;
int
lockmethod
=
DEFAULT_LOCKMETHOD
;
LOCKMETHODTABLE
*
lockMethodTable
;
...
...
@@ -1441,9 +1441,9 @@ DumpAllLocks(void)
LOCK_PRINT
(
"DumpAllLocks: waiting on"
,
proc
->
waitLock
,
0
);
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
)
{
...
...
src/backend/storage/lmgr/proc.c
浏览文件 @
b75fcf93
...
...
@@ -8,7 +8,7 @@
*
*
* 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
ProcSleep
(
LOCKMETHODTABLE
*
lockMethodTable
,
LOCKMODE
lockmode
,
LOCK
*
lock
,
HOLDER
*
holder
)
PROCLOCK
*
holder
)
{
LWLockId
masterLock
=
lockMethodTable
->
masterLock
;
PROC_QUEUE
*
waitQueue
=
&
(
lock
->
waitProcs
);
...
...
src/include/storage/lock.h
浏览文件 @
b75fcf93
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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
* tag -- uniquely identifies the object being locked
* grantMask -- bitmask for all lock types currently granted 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.
* requested -- count of each lock type currently requested on the lock
* (includes requests already granted!!).
...
...
@@ -146,7 +146,7 @@ typedef struct LOCK
/* data */
int
grantMask
;
/* bitmask for lock types already granted */
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 */
int
requested
[
MAX_LOCKMODES
];
/* counts of requested
* locks */
...
...
@@ -163,8 +163,8 @@ typedef struct LOCK
* on the same lockable object. We need to store some per-holder information
* for each such holder (or would-be holder).
*
*
HOLDERTAG is the key information needed to look up a HOLDER
item in the
* holder hashtable. A
HOLDER
TAG value uniquely identifies a lock holder.
*
PROCLOCKTAG is the key information needed to look up a PROCLOCK
item in the
* holder hashtable. A
PROCLOCK
TAG value uniquely identifies a lock holder.
*
* 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
...
...
@@ -180,32 +180,32 @@ typedef struct LOCK
* Otherwise, holder objects whose counts have gone to zero are recycled
* as soon as convenient.
*
* Each
HOLDER
object is linked into lists for both the associated LOCK object
* and the owning PGPROC object. Note that the
HOLDER
is entered into these
* Each
PROCLOCK
object is linked into lists for both the associated LOCK object
* 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.
* A PGPROC that is waiting for a lock to be granted will also be linked into
* the lock's waitProcs queue.
*/
typedef
struct
HOLDER
TAG
typedef
struct
PROCLOCK
TAG
{
SHMEM_OFFSET
lock
;
/* link to per-lockable-object information */
SHMEM_OFFSET
proc
;
/* link to PGPROC of owning backend */
TransactionId
xid
;
/* xact ID, or InvalidTransactionId */
}
HOLDER
TAG
;
}
PROCLOCK
TAG
;
typedef
struct
HOLDER
typedef
struct
PROCLOCK
{
/* tag */
HOLDER
TAG
tag
;
/* unique identifier of holder object */
PROCLOCK
TAG
tag
;
/* unique identifier of holder object */
/* data */
int
holding
[
MAX_LOCKMODES
];
/* count of locks currently held */
int
nHolding
;
/* total of holding[] array */
SHM_QUEUE
lockLink
;
/* list link for lock'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)
...
...
@@ -225,9 +225,9 @@ extern bool LockReleaseAll(LOCKMETHOD lockmethod, PGPROC *proc,
bool
allxids
,
TransactionId
xid
);
extern
int
LockCheckConflicts
(
LOCKMETHODTABLE
*
lockMethodTable
,
LOCKMODE
lockmode
,
LOCK
*
lock
,
HOLDER
*
holder
,
PGPROC
*
proc
,
LOCK
*
lock
,
PROCLOCK
*
holder
,
PGPROC
*
proc
,
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
int
LockShmemSize
(
int
maxBackends
);
extern
bool
DeadLockCheck
(
PGPROC
*
proc
);
...
...
src/include/storage/proc.h
浏览文件 @
b75fcf93
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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
/* Info about lock the process is currently waiting for, if any. */
/* waitLock and waitHolder are NULL if not currently waiting. */
LOCK
*
waitLock
;
/* Lock object we're sleeping on ... */
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 */
LOCKMASK
heldLocks
;
/* bitmask for lock types already held on
* 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 */
};
...
...
@@ -101,7 +101,7 @@ extern void ProcReleaseLocks(bool isCommit);
extern
void
ProcQueueInit
(
PROC_QUEUE
*
queue
);
extern
int
ProcSleep
(
LOCKMETHODTABLE
*
lockMethodTable
,
LOCKMODE
lockmode
,
LOCK
*
lock
,
HOLDER
*
holder
);
LOCK
*
lock
,
PROCLOCK
*
holder
);
extern
PGPROC
*
ProcWakeup
(
PGPROC
*
proc
,
int
errType
);
extern
void
ProcLockWakeup
(
LOCKMETHODTABLE
*
lockMethodTable
,
LOCK
*
lock
);
extern
bool
LockWaitCancel
(
void
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录