Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
862927f4
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,发现更多精彩内容 >>
提交
862927f4
编写于
1月 27, 1998
作者:
B
Bruce Momjian
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Real deadlock detection.
上级
0e913671
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
130 addition
and
49 deletion
+130
-49
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/lock.c
+82
-10
src/backend/storage/lmgr/proc.c
src/backend/storage/lmgr/proc.c
+37
-30
src/include/config.h.in
src/include/config.h.in
+9
-7
src/include/storage/lock.h
src/include/storage/lock.h
+2
-2
未找到文件。
src/backend/storage/lmgr/lock.c
浏览文件 @
862927f4
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.2
1 1998/01/25 05:14:02
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.2
2 1998/01/27 03:00:28
momjian Exp $
*
* NOTES
* Outside modules can create a lock table and acquire/release
...
...
@@ -1201,7 +1201,7 @@ LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue)
done
=
(
xidLook
->
queue
.
next
==
end
);
lock
=
(
LOCK
*
)
MAKE_PTR
(
xidLook
->
tag
.
lock
);
LOCK_PRINT
(
"ReleaseAll"
,
(
&
lock
->
tag
),
0
);
LOCK_PRINT
(
"
Lock
ReleaseAll"
,
(
&
lock
->
tag
),
0
);
#ifdef USER_LOCKS
...
...
@@ -1307,11 +1307,7 @@ LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue)
||
!
found
)
{
SpinRelease
(
masterLock
);
#ifdef USER_LOCKS
elog
(
NOTICE
,
"LockReleaseAll: xid table corrupted"
);
#else
elog
(
NOTICE
,
"LockReplace: xid table corrupted"
);
#endif
return
(
FALSE
);
}
...
...
@@ -1329,11 +1325,7 @@ LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue)
if
((
!
lock
)
||
(
!
found
))
{
SpinRelease
(
masterLock
);
#ifdef USER_LOCKS
elog
(
NOTICE
,
"LockReleaseAll: cannot remove lock from HTAB"
);
#else
elog
(
NOTICE
,
"LockReplace: cannot remove lock from HTAB"
);
#endif
return
(
FALSE
);
}
}
...
...
@@ -1415,6 +1407,86 @@ LockingDisabled()
return
LockingIsDisabled
;
}
/*
* DeadlockCheck -- Checks for deadlocks for a given process
*
* We can't block on user locks, so no sense testing for deadlock
* because there is no blocking, and no timer for the block.
*
* This code takes a list of locks a process holds, and the lock that
* the process is sleeping on, and tries to find if any of the processes
* waiting on its locks hold the lock it is waiting for.
*
* We have already locked the master lock before being called.
*/
bool
DeadLockCheck
(
SHM_QUEUE
*
lockQueue
,
LOCK
*
findlock
,
bool
skip_check
)
{
int
done
;
XIDLookupEnt
*
xidLook
=
NULL
;
XIDLookupEnt
*
tmp
=
NULL
;
SHMEM_OFFSET
end
=
MAKE_OFFSET
(
lockQueue
);
LOCK
*
lock
;
if
(
SHMQueueEmpty
(
lockQueue
))
return
false
;
SHMQueueFirst
(
lockQueue
,
(
Pointer
*
)
&
xidLook
,
&
xidLook
->
queue
);
XID_PRINT
(
"DeadLockCheck"
,
xidLook
);
for
(;;)
{
/* ---------------------------
* XXX Here we assume the shared memory queue is circular and
* that we know its internal structure. Should have some sort of
* macros to allow one to walk it. mer 20 July 1991
* ---------------------------
*/
done
=
(
xidLook
->
queue
.
next
==
end
);
lock
=
(
LOCK
*
)
MAKE_PTR
(
xidLook
->
tag
.
lock
);
LOCK_PRINT
(
"DeadLockCheck"
,
(
&
lock
->
tag
),
0
);
/*
* This is our only check to see if we found the lock we want.
*
* The lock we are waiting for is already in MyProc->lockQueue
* so we need to skip it here. We are trying to find it in
* someone else's lockQueue.
*/
if
(
lock
==
findlock
&&
!
skip_check
)
return
true
;
else
if
(
lock
!=
findlock
||
!
skip_check
)
{
PROC_QUEUE
*
waitQueue
=
&
(
lock
->
waitProcs
);
PROC
*
proc
;
int
i
;
proc
=
(
PROC
*
)
MAKE_PTR
(
waitQueue
->
links
.
prev
);
for
(
i
=
0
;
i
<
waitQueue
->
size
;
i
++
)
{
/* prevent endless loops */
if
(
proc
!=
MyProc
&&
skip_check
)
{
/* If we found a deadlock, we can stop right now */
if
(
DeadLockCheck
(
&
(
proc
->
lockQueue
),
findlock
,
false
))
return
true
;
}
proc
=
(
PROC
*
)
MAKE_PTR
(
proc
->
links
.
prev
);
}
}
if
(
done
)
break
;
SHMQueueFirst
(
&
xidLook
->
queue
,
(
Pointer
*
)
&
tmp
,
&
tmp
->
queue
);
xidLook
=
tmp
;
}
/* if we got here, no deadlock */
return
false
;
}
#ifdef DEADLOCK_DEBUG
/*
* Dump all locks. Must have already acquired the masterLock.
...
...
src/backend/storage/lmgr/proc.c
浏览文件 @
862927f4
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.2
8 1998/01/25 05:14:0
9 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.2
9 1998/01/27 03:00:2
9 momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -46,7 +46,7 @@
* This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95
*
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.2
8 1998/01/25 05:14:0
9 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.2
9 1998/01/27 03:00:2
9 momjian Exp $
*/
#include <sys/time.h>
#include <unistd.h>
...
...
@@ -442,7 +442,7 @@ ProcQueueInit(PROC_QUEUE *queue)
* NOTES: The process queue is now a priority queue for locking.
*/
int
ProcSleep
(
PROC_QUEUE
*
q
ueue
,
ProcSleep
(
PROC_QUEUE
*
waitQ
ueue
,
SPINLOCK
spinlock
,
int
token
,
int
prio
,
...
...
@@ -453,8 +453,8 @@ ProcSleep(PROC_QUEUE *queue,
struct
itimerval
timeval
,
dummy
;
proc
=
(
PROC
*
)
MAKE_PTR
(
q
ueue
->
links
.
prev
);
for
(
i
=
0
;
i
<
q
ueue
->
size
;
i
++
)
proc
=
(
PROC
*
)
MAKE_PTR
(
waitQ
ueue
->
links
.
prev
);
for
(
i
=
0
;
i
<
waitQ
ueue
->
size
;
i
++
)
{
if
(
proc
->
prio
>=
prio
)
proc
=
(
PROC
*
)
MAKE_PTR
(
proc
->
links
.
prev
);
...
...
@@ -478,36 +478,38 @@ ProcSleep(PROC_QUEUE *queue,
* -------------------
*/
SHMQueueInsertTL
(
&
(
proc
->
links
),
&
(
MyProc
->
links
));
q
ueue
->
size
++
;
waitQ
ueue
->
size
++
;
SpinRelease
(
spinlock
);
/* --------------
* Postgres does not have any deadlock detection code and for this
* reason we must set a timer to wake up the process in the event of
* a deadlock. For now the timer is set for 1 minute and we assume that
* any process which sleeps for this amount of time is deadlocked and will
* receive a SIGALRM signal. The handler should release the processes
* semaphore and abort the current transaction.
* We set this so we can wake up periodically and check for a deadlock.
* If a deadlock is detected, the handler releases the processes
* semaphore and aborts the current transaction.
*
* Need to zero out struct to set the interval and the micro seconds fields
* to 0.
* --------------
*/
MemSet
(
&
timeval
,
0
,
sizeof
(
struct
itimerval
));
timeval
.
it_value
.
tv_sec
=
DEADLOCK_
TIMEOUT
;
timeval
.
it_value
.
tv_sec
=
DEADLOCK_
CHECK_TIMER
;
if
(
setitimer
(
ITIMER_REAL
,
&
timeval
,
&
dummy
))
elog
(
FATAL
,
"ProcSleep: Unable to set timer for process wakeup"
);
do
{
MyProc
->
errType
=
NO_ERROR
;
/* reset flag after deadlock check */
/* --------------
* if someone wakes us between SpinRelease and IpcSemaphoreLock,
* IpcSemaphoreLock will not block. The wakeup is "saved" by
* the semaphore implementation.
* --------------
*/
IpcSemaphoreLock
(
MyProc
->
sem
.
semId
,
MyProc
->
sem
.
semNum
,
IpcExclusiveLock
);
if
(
setitimer
(
ITIMER_REAL
,
&
timeval
,
&
dummy
))
elog
(
FATAL
,
"ProcSleep: Unable to set timer for process wakeup"
);
/* --------------
* if someone wakes us between SpinRelease and IpcSemaphoreLock,
* IpcSemaphoreLock will not block. The wakeup is "saved" by
* the semaphore implementation.
* --------------
*/
IpcSemaphoreLock
(
MyProc
->
sem
.
semId
,
MyProc
->
sem
.
semNum
,
IpcExclusiveLock
);
}
while
(
MyProc
->
errType
==
STATUS_NOT_FOUND
);
/* sleep after deadlock check */
/* ---------------
* We were awoken before a timeout - now disable the timer
* ---------------
...
...
@@ -615,10 +617,9 @@ ProcAddLock(SHM_QUEUE *elem)
}
/* --------------------
* We only get to this routine if we got SIGALRM after DEADLOCK_TIMEOUT
* while waiting for a lock to be released by some other process. After
* the one minute deadline we assume we have a deadlock and must abort
* this transaction. We must also indicate that I'm no longer waiting
* We only get to this routine if we got SIGALRM after DEADLOCK_CHECK_TIMER
* while waiting for a lock to be released by some other process. If we have
* a real deadlock, we must also indicate that I'm no longer waiting
* on a lock so that other processes don't try to wake me up and screw
* up my semaphore.
* --------------------
...
...
@@ -665,12 +666,19 @@ HandleDeadLock(int sig)
return
;
}
mywaitlock
=
MyProc
->
waitLock
;
#ifdef DEADLOCK_DEBUG
DumpLocks
();
#endif
if
(
!
DeadLockCheck
(
&
(
MyProc
->
lockQueue
),
MyProc
->
waitLock
,
true
))
{
UnlockLockTable
();
MyProc
->
errType
=
STATUS_NOT_FOUND
;
return
;
}
mywaitlock
=
MyProc
->
waitLock
;
/* ------------------------
* Get this process off the lock's wait queue
* ------------------------
...
...
@@ -701,8 +709,7 @@ HandleDeadLock(int sig)
*/
UnlockLockTable
();
elog
(
NOTICE
,
"Timeout interval reached -- possible deadlock."
);
elog
(
NOTICE
,
"See the lock(l) manual page for a possible cause."
);
elog
(
NOTICE
,
"Deadlock detected -- See the lock(l) manual page for a possible cause."
);
return
;
}
...
...
src/include/config.h.in
浏览文件 @
862927f4
...
...
@@ -210,14 +210,16 @@ extern void srandom(int seed);
code seems broken without it, Bruce Momjian */
/* #define LOARRAY */
/* This is the time, in seconds, at which a given backend server
* will wait on a lock before deciding to abort the transaction
* (this is what we do in lieu of deadlock detection).
*
* Low numbers are not recommended as they will tend to cause
* false aborts if many transactions are long-lived.
/*
* As soon as the backend blocks on a lock, it waits this number of seconds
* before checking for a deadlock. If not, it keeps checking every this
* number of seconds.
* We don't check for deadlocks just before sleeping because a deadlock is
* a rare event, and checking is an expensive operation.
* We only detect deadlocks between two processes, not three or more, but
* these are the most common.
*/
#define DEADLOCK_
TIMEOUT
60
#define DEADLOCK_
CHECK_TIMER
60
/*
* This flag enables the use of idexes in plans generated for function
...
...
src/include/storage/lock.h
浏览文件 @
862927f4
...
...
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: lock.h,v 1.
9 1998/01/24 22:50:11
momjian Exp $
* $Id: lock.h,v 1.
10 1998/01/27 03:00:43
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -214,7 +214,7 @@ extern void GrantLock(LOCK *lock, LOCKT lockt);
extern
bool
LockReleaseAll
(
LockTableId
tableId
,
SHM_QUEUE
*
lockQueue
);
extern
int
LockShmemSize
(
void
);
extern
bool
LockingDisabled
(
void
);
extern
bool
DeadLockCheck
(
SHM_QUEUE
*
lockQueue
,
LOCK
*
findlock
,
bool
skip_check
);
#ifdef DEADLOCK_DEBUG
extern
void
DumpLocks
(
void
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录