DSI 之lock学习

锁的申请:
1.使用hash算法将资源做hash,做完hash得到一个结果值将对应一个hash bucket
2.申请enqueue hash chain以访问hash bucket。
3.此时,将资源放到hash bucket的hash chain上。如果在hash chain上没有找到对应的资源结构,就到free resource list上找,找到后放入到hash chain上。
4.获得enqueue latch
5.获得free lock的结构(与lock free list的头部断连)
6.将正确的资源信息放到lock上。
7.将lock结构连接到资源结构上。
8.释放enqueue latch
9.释放enqueue hash chain latch。

锁的释放:
1.使用hash函数得到resource的hash chain
2.获得enqueue hash chain来访问hash bucket
3.找到hash bucket,顺着hash chain找到resource。
4.申请enqueue latch
5.将lock结构和resource结构断连
6.将lock结构再次连到free lock list上
7.释放enqueue latch
8.如果resource结构有converter或者waiter,这继续处理。
9.如果可能的话,将resource结构从hash chain上断开,将resource 结构放到free resource list中。
10.释放enquene hash chain latch。

注:上面的resource是指能被session共享的resource,如一个表、一个library cache中的child handle等等。enqueue是用于控制如何访问这些共享资源的后续会具体说明。

打个比方吧,有个钻石加工厂,要把钻石镶嵌到项链上,项链有不同大小的眼以供钻石镶嵌上去。由于为了清洗项链,项链被放在一个开水桶里面,开水桶做了标记,1,2,3,4……

开水桶就是我们的hash bucket,钻石是我们的resource,项链上的眼是resource structure,enquene hash chain是能伸进开水桶的钳子,free resource list是放了一堆链子托盘,如果某个桶里面没有链子,可以到这个上面去找一条来放入到开水桶中,enqueue是做镶嵌工作时小榔头。lock structure是项链上的眼需要抓紧钻石的爪子。该工厂就只有一把钳子和一把榔头,因此后续要操作的人必须等待。

钻石根据其自身的成色/切工/大小,根据hash算法,知道需要镶嵌在5号桶的一条项链上,于是,首先获得enqueue hash chain钳子,去捞那条链子,如果发现5号的hash bucket桶里面没有这条链子,则去free resource list上找一条链子,再泡到开水桶中。如果找到,就把抓钻石的小爪子安放到项链的眼上,小榔头把爪子敲好。

相关视图和基表:
X$KSQRS——v$resource的基表
x$ksqst——可以看系统级的enqueue的type,gets和waits
X$KSQEQ——v$lock的基表

enqueue可以通过v$session_wait来查询,这里的v$session_wait中的p1、p2也就是resource name中对应的ID1和ID2.
如果v$session_wait中的等待是enqueue,那么对应的p1raw就能找出对应的type,而不必通过p1的繁琐运算:
如:

分布式事务的死锁无法判断,因为不在一个SGA中,无法判断是真的死锁,还是等待时间太长的锁,可以通过_DISTRIBUTED_LOCK_TIMEOUT隐含参数来设置分布式事务锁的时间。

v$lock:
lmode>0 request=0 ->owner
lmode=0 request>0 ->waiter
lmode>0 request>0 ->converter

数据字典的锁:row cache lock,type是QA~QZ, 隐含参数_ROW_CACHE_INSTANCE_LOCKS定义了系统最多的row cache lock,默认值是100.
获取过程:申请-如果未获取,则等3秒-再次申请,如此反复1000次,如果还是未获取,就放弃,报错Waited too long for row cache enqueue lock,考虑加大shared pool(主要是share pool中的data dictionary部分)
注意:row cache lock的resource structure是cached row

库缓存的锁:library cache lock是加在library cache对象的句柄上,type是LA~LP。
在parse阶段,会在parent handle和child handle上加library cache lock的独占锁,在dependency上加library cache lock的共享锁。
library cache lock在以下情况会保持null状态:1)检测无效对象;2)避免再次locate handle。
注意:library cache lock的resource structure是object handle
相关视图:
X$KGLLK

library cache pin是加在library data heap上,type有NA~NZ。
当修改data heap的时候,library cache pin会以独占的模式获取
在读取data heap或者需要保护被修改的对象的时候,library cache pin会以share的模式获取。
当一个client修改或检查一个对象的时候,会先在对应的handle上获取library cache lock,再在合适的heap上获取pin。
注意:library cache pin的resource structure是object handle。
相关视图:X$KGLPN

DML行锁是包含行级锁(row level lock)和事务锁:
行级锁是由于:1.行头争用,2.数据块或者索引块的ITL争用
事务锁是TX的enqueue表现的。

(一)行级锁:
行头争用:


如update一行记录:
1.访问对应的block,并且allocate一个ITL
2.通过rowid访问对应的行,如果确认没有其他的事务锁住该行,则将行头的第二个byte当时应该是0
3.找到ITL对应的索引值,通过这个值将行头的lock field改成非0。
4.当另一个事务update这一行时,就会发现行头的标记已经是非0。
5.事务2想知道事务1是否已经commit或者rollback,事务2执行ITL cleanout,当执行完ITL cleanout之后,发现事务1还是active的,于是enqueue等待。

ITL争用:
ITL的初始值为INITRANS的值。最大值为MAXTRANS,能动态修改。

如一个表的maxtrans为3,里面有4行,
1.update第一行记录,这个事务占据一个ITL
2.再开一个窗口update第二行,即又一个事务占据另一个ITL,
3.再开一个窗口update第三行记录,即又占据一个ITL。此时3个ITL已经都被占满,
4.如果此时又开一个窗口update另一行,则此session被挂起。该session会有一个TX的lmode为4(即S锁)的锁。

(二)事务锁:
事务锁是针对活动事务来说的,他们是在回滚段头的块中。transaction identifiers(XID)唯一数据block或者index block的ITL中,是唯一的。XID的格式是:
XID=USN#.SLOT#.WRAP#
XID和回滚段头的关系如下:

dump transaction table:
主要是dump回滚段头:
alter system dump undo header ‘_SYSSMU8$’;
dump出来的结果中state为10表示active,9表示inactive

Buffer 锁:
注意:buffer lock的resource structure是buffer header。session通过buffer handle来访问buffer,buffer handle是lock structure。
buffer header为session提供buffer handle双向链表,一方面指向session使用的buffer,另一方面指向session等待的buffer。正在等待buffer lock的session会报buffer busy wait或者write complete wait。
buffer busy wait在v$session_wait中 p1表示绝对文件好,p2表示block号,p3表示错误代码。
可以通过v$waitstat看各个类型:

1.如buffer busy wait是data block争用:
1.1 如果是data block的读等待,则限制使用选择性不高的索引。
1.2 如果是data block的修改等待,则增加行的选择性:修改pctfree或pctused,增加initrans,减少RECORDS_PER_BLOCK,减小db_block_size,避免使用right hand index。

2.如buffer busy wait是undo的争用
2.1 undo header的争用,则需要更多的undo segment,或者减少transactions_per_rollback_segment。注:9i开始由于使用AUM,自动管理undo,所以该等待出现的情况不多。

3.如buffer busy wait是free list争用,主要是buffer cache中segment header block的争用。
3.1 增加 free list
3.2 增加free list group

SMON的作用:
1.合并free extent,注,会有ST enqueue。
2.清理temporary segment——注:不一定是temp表空间,如truncate之后的表,就被列为temporary segment了。
3.清理不存在的object
4.清理online rebuild但crash后的IND$
5.回缩undo segment
6.启动时的事务恢复
7.事务回滚(被PMON触发)。

相关文章

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据