暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

openGauss常规锁死锁检测

openGauss小助手 2021-10-29
1692

openGauss在获取锁时如果没有冲突可以直接上锁;如果有冲突则设置一个定时器timer,并进入等待,过一段时间会被timer唤起进行死锁检测。如果在某个锁的等锁队列中,进程T2排在进程T1后面,且进程T2需要获取的锁与T1需要获取的锁资源冲突,则T2到T1会有一条软等待边(soft edge)。如果进程T2的加锁请求与T1进程所持有的锁冲突,则有一条硬等待边(hard edge)。那么整体思路就是通过递归调用,从当前顶点等锁的顶点出发,沿着等待边向前走,看是否存在环,如果环中有soft edge,说明环中两个进程都在等锁,重新排序,尝试解决死锁冲突。如果没有soft edge,那么只能终止当前等锁的事务,解决死锁等待环。如图5-19所示,虚线代表soft edge,实线代表hard fdge。线程A等待线程B,线程B等待线程C,线程C等待线程A,因为线程A等待线程B的是soft edge,进行一次调整成为图5-19右边的等待关系,此时发现线程A等待线程C,线程C等待线程A,没有soft edge,检测到死锁。


图5-19 常规锁死锁检测示意图

主要函数如下。

(1) DeadLockCheck:死锁检测函数。
(2) DeadLockCheckRecurse:如果死锁则返回true,如果有soft edge,返回false并且尝试解决死锁冲突。
(3) check_stack_depth:openGauss会检查死锁递归检测堆栈(死锁检测递归栈过长,会引发在死锁检测时,长期持有所有锁的LWLock分区,从而阻塞业务)。
(4) CheckDeadLockRunningTooLong:openGauss会检查死锁检测时间,防止死锁检测时间过长,阻塞后面所有业务。对应的代码如下:

static void CheckDeadLockRunningTooLong(int depth)

{ /* 每4层检测一下 */

if (depth > 0 && ((depth % 4) == 0)) {

TimestampTz now = GetCurrentTimestamp();

long secs = 0;

int usecs = 0;

if (now > t_thrd.storage_cxt.deadlock_checker_start_time) {

TimestampDifference(t_thrd.storage_cxt.deadlock_checker_start_time, now, &secs, &usecs);

if (secs > 600) { /* 如果从死锁检测开始超过十分钟,则报错处理。 */

#ifdef USE_ASSERT_CHECKING

DumpAllLocks();/* 在debug版本时,导出所有的锁信息,便于定位问题。 */

#endif

ereport(defence_errlevel(), (errcode(ERRCODE_INTERNAL_ERROR),

errmsg("Deadlock checker runs too long and is greater than 10 minutes.")));

}

}

}

}

(5) FindLockCycle:检查是否有死锁环。
(6) FindLockCycleRecurse:死锁检测内部递归调用函数。

相应的数据结构有:

(1) 死锁检测中最核心最关键的有向边数据结构。对应的代码如下:

typedef struct EDGE {

PGPROC *waiter; /* 等待的线程 */

PGPROC *blocker; /* 阻塞的线程 */

int pred; /* 拓扑排序的工作区 */

int link; /* 拓扑排序的工作区 */

} EDGE;

(2) 可重排的一个等待队列。对应的代码如下:

typedef struct WAIT_ORDER {

LOCK *lock; /* the lock whose wait queue is described */

PGPROC **procs; /* array of PGPROC *'s in new wait order */

int nProcs;

} WAIT_ORDER;

(3) 死锁检测最后打印的相应信息。对应的代码如下:

typedef struct DEADLOCK_INFO {

LOCKTAG locktag; /* 等待锁对象的唯一标识 */

LOCKMODE lockmode; /* 等待锁对象的锁类型 */

ThreadId pid; /* 阻塞线程的线程ID */

} DEADLOCK_INFO;

最后修改时间:2021-11-01 18:26:53
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论