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的繁琐运算:
如:

1* select event,sid,p1,p2,p1raw from v$session_wait where event='enqueue'
SQL> /
 
EVENT                       SID         P1         P2 P1RAW
------------------
-- ---------- ---------- ---------- ----------------
enqueue                      65 1415053318      65542 0000000054580006
 
SQL>
 
--取
p1raw54580006,其中5458表示类型,0006表示lmode6的锁。我们把5458再分解。54是个16进制的数字,转换成10进制,就是:
SQL> select to_number(54,'xxxxxxxx') from dual;
 
TO_NUMBER(54,'XXXXXXXX')
----------------------
--
                      84

 
SQL>
--转换反
ascii码:
SQL> select chr(84) from dual;
 
C
-
T
 
--同理可得
58
 
1* select to_number(58,'xxxxxxxx') from dual
SQL> /
 
TO_NUMBER(58,'XXXXXXXX')
----------------------
--
                      88

 
SQL> select chr(88) from dual;
 
C
-
X
 
SQL>
--因此得到类型为
TX的锁。
 
--或者直接计算:
SQL> select chr(to_number(substr(p1raw,9,2),'xxxxxxxx'))
 
2  ||chr(to_number(substr(p1raw,11,2),'xxxxxxxx'))  as enqueue_type
 
3  from v$session_wait
 
4  where event='enqueue'
 
5  /
 
ENQU
--
--
TX

 
SQL>

分布式事务的死锁无法判断,因为不在一个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看各个类型:

SQL> l
 
1* select * from V$WAITSTAT order by 1
SQL> /
 
CLASS                   COUNT       TIME
----------------
-- ---------- ----------
1st level bmb               0          0
2nd level bmb               0          0
3rd level bmb               0          0
bitmap block                0          0
bitmap index block          0          0
data block            1664116     576375
extent map                  2          5
file header block          17       3650
free list                   0          0
save undo block             0          0
save undo header            0          0
segment header           9037         42
sort block                  0          0
system undo block           0          0
system undo header          0          0
undo block                376          0
undo header             15244       9343
unused                      0          0
 
18 rows selected.
 
SQL>

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触发)。

· 【文章发布信息】发表于: 2009-09-15 @ 20:43:02 · ||分类: Study note, Useful script

留条评论