案例演示
场景: 双节点RAC环境下,三个不同的会话访问同一张表T:
1.P1申请表的共享模式锁。
2.P2申请表的共享模式锁。
3.P2执行回滚操作。
4.P1申请表的独占模式锁。
5.P3申请表的共享模式锁。
6.P1执行回滚操作。
第1-2步:核心流程
在步骤1中,P1将表锁定在共享模式下。在步骤2中,P2在共享模式下锁定同一个表。差异出现在kjusuc层。
ksqgtl层:获取enqueue,type =“TM”,id1= table_object_id,id2 = 0,timeout= infinite。在调用ksqcmi之前,在相关联的资源上分配队列锁。
ksqcmi层:使用get-convert函数。注册指定队列相关的队列等待事件,为DLM计算出XID。设置锁获取选项(请求死锁检测)。当kjusuc层等待AST时,使用在kjiwev中注册的等待事件。
ksipget:获取组锁,DLM接口同步,设置DLM资源名称,设置超时时间(unlimit)。 在返回调用kjusuc时,增加“global lock sync gets”和“global lock gettime”计数和时间。
第1步:详细流程
1:分配lock1并更新V$RESOURCE_LIMIT。
2:将锁定状态设置为KJL_OPENING。
3:分配资源1并更新V $RESOURCE_LIMIT。
4:通过前面介绍的算法(后续系列会详细介绍)计算出主节点。
5:向主节点发送消息。(因为这是实例第一次申请该资源,所以它必须向主节点发送消息)
现在,两个实例中并行发起两个活动(1)6:将锁放在转换队列,并将其挂在死锁队列中。此类型锁“TM”并且是无超时限制的,因为它可能成为死锁,因此它不会附加到计时器队列,而是放在死锁队列中。
(1) 7:轮询等待AST,用等待事件“enqueue”表示等待状态。
(2)1:分配进程1描述符和lock 1(相同模式)。
(2)2:因为资源从未在实例2中使用过,所以实例2会创建它,然后将其链接到lock 1。因为它是第一次在实例2中使用资源1,所以这个申请操作将会成功。
(2)3:排队并向请求者实例发送消息。
8:将lock挂在授权队列中并将它从死锁队列中剔除。
9:设置标识,发送AST给客户端进程。
10:处理AST;清除KJL_OPENING并退出。
第2步:kjusuc流程细节
资源已经存在,因此流程很简单立即授予锁即可,因为:
• 本地没有不兼容的锁。
• 请求模式为S,与之前持有的模式相同。因为授予另一个共享模式锁不会涉及到锁模式的升级。无需向主实例发送消息。
1.分配lock1并更新V$RESOURCE_LIMIT。
2.将锁定状态设置为KJL_OPENING,KJL_CONVERTING。
3.挂起现有资源1上的锁。
4.处理AST; 清除KJL_OPENING,KJL_CONVERTING然后退出。
第3步:核心流程
在步骤3中,P2通过执行回滚来释放表共享模式锁。
Ksiprls是分布式锁管理针对CLOSE lock操作的同步接口。在返回调用kjuscl时,增加“global lock releases”统计信息。
第3步: kjuscl详细流程
因为资源1上一直挂着lock1,因此释放p2申请的资源后资源1依然无法释放。
1.将锁定状态设置为KJL_CLOSING。
2.从资源1中删除lock2和进程2。
3.释放lock2,更新V$RESOURCE_LIMIT。
4.退出。因为删除锁2不会更改资源1的保持模式或其请求模式,所以不会向主节点发送消息。
第4步:核心流程
在步骤4中,P1将表共享模式锁升级为独占锁。ksqcnv提供一个锁定描述,如之前使用kjusuc获得的。
ksipcon是用于锁定转换的DLM的同步接口。调用kjuscv(timeout无限制),然后增加“global lock sync converts”并更新“global lock convert time”。
因为此转换会使资源的保持模式从S变为X并且实例1不是主实例,所以必须将消息发送到主实例以确定转换申请是否可以执行。
1.将锁定状态设置为KJL_CONVERTING。
2.将资源1上的锁从grant队列移动到转换队列。lock1不会未挂起,因为在计时器队列上它是无超时限制的。
3.将lock1挂在死锁队列上,因为lock1可能会成为死锁。
注意,仅当锁是本地锁时,锁才挂在计时器队列和死锁队列上。换句话说,锁的拥有实例与本地实例相同。
4.将消息发送到主实例。
5.轮询等待AST,用等待事件“enqueue”表示等待状态。
实例21.因为在主实例中并且没有锁模式的冲突,所以lock1的模式从S转换为X,。
2.排队并向请求者实例发送消息。
实例1等待继续。
6.将lock1置于授权队列中,并将其从死锁队列中删除。
7.通过设置其标志将AST发送到客户端进程。
8.响应处理AST; 清除KJL_CONVERTING并退出。
第5步:详细流程 在步骤1中,P3请求以共享模式锁定表。代码路径与步骤1和2相同,在kjusuc中进行处理。
1.分配lock 3和进程3,更新V$DLM_RESOURCE_LIMIT。
2.将lock3的状态设置为KJL_OPENING,KJL_CONVERTING。
3.将lock3放入资源1的转换队列中。因为lock3与lock1冲突,所以不能立即转换。
4.将lock3放置在死锁队列中。
5.发送消息以探测阻塞实例中是否有新变化。这个消息分为两条,一条是针对资源1的授权队列上所有与lock 3有冲突的锁的探测消息。另外一条是转换队列中的与锁3冲突的锁的探测消息。
第6步:详细流程 P1通过在实例1中执行回滚来释放其独占表锁。
1.将锁定状态设置为KJL_CLOSING。
2.将锁从S模式转换成N模式。
3.锁模式从X转换为NULL后,因为lock1对resource1的持有模式也发生了变化,所以需要将消息KJX_CONVERT_REQ发送到主实例。
4.释放资源1,并进行更新V$RESOURCE_LIMIT。
5.释放锁1并更新V$RESOURCE_LIMIT。
6.结束退出。
实例2从实例1收到KJX_CONVERT_REQ消息后:
1.锁1从X转换为NULL。
2.尝试为资源1授予转换队列上的所有锁。因为lock1已经被降级为NULL,所以可以授予lock3。
3. AST被发送到P3,P3仍在等待第5步。
4. P3处理AST,完成锁定获取,退出DLM。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28218939/viewspace-2653134/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/28218939/viewspace-2653134/