初探Cache Fusion对block的锁管理

本文以双节点RAC为例,揭示了在执行select及DML操作过程中,Cache Fusion在幕后是如何对block进行锁管理的。

###实例1上查询scott.t0820_1表
select * from scott.t0820_1;
        ID
----------
         2


select dbms_rowid.rowid_relative_fno(rowid) rfno,dbms_rowid.rowid_block_number(rowid) blkno from scott.t0820_1;
      RFNO      BLKNO
---------- ----------
         6        255


select to_char(6,'xxx'),to_char(255,'xxx') from dual;
TO_C TO_C
---- ----
   6   ff


select object_id,data_object_id from dba_objects where object_name='T0820_1';
 OBJECT_ID DATA_OBJECT_ID
---------- --------------
     15976          15976

###用到的脚本 

//// get_buffer_stat.sql ////
col object_name for a10
select (select object_name from dba_objects where object_id = b.obj) as object_name,decode (state,0, 'Free', 1, 'XCUR', 2, 'SCUR', 3, 'CR', 4,'BEING READ',5, 'MREC', 6, 'IREC', 7, 'WRITE_CLONE', 8, 'PI') state,mode_held, le_addr, cr_scn_bas, cr_scn_wrp from x$bh b where obj = 15976 and dbablk = 255 and class = 1;


//// get_resource_name.sql,获得block在GRD内存的资源名////
col hexname for a35
col resource_name for a15
set linesize 170
select b.kjblname hexname, b.kjblname2 resource_name,b.kjblgrant, b.kjblrole, b.kjblowner,b.kjblmaster,b.KJBLPKEY,b.kjblsid,b.kjblrequest from x$le a, x$kjbl b where a.le_kjbl=b.kjbllockp and a.le_addr = ( select le_addr from x$bh where dbablk = 255 and obj    = 15976 and class  = 1 and state   <> 3);


//// get_resource_stat.sql 获得block资源的授权访问信息,注意:因为v$dlm_ress只在block的主节点上才能查到,而v$ges_enqueue在两节点上都有,所以查询结果表示block以inst_id所指节点为主节点,inst_id=mast+1 ////
col resource_name for a34
col state for a8
col mast for 9999
col grnt for 9999
col cnvt for 9999
set linesize 160
select a.inst_id,a.resource_name, b.state, a.master_node mast, a.on_convert_q cnvt,a.on_grant_q grnt, b.request_level, b.grant_level, b.owner_node from  gv$dlm_ress a, gv$ges_enqueue b where upper(a.resource_name) = upper(b.resource_name1) and a.resource_name like '%[0xff][0x6]%' and a.inst_id=b.inst_id;


//// get_master_node.sql 获得block资源的主节点 ////
col resource_name for a34
col state for a8
col mast for 9999
col grnt for 9999
col cnvt for 9999
set linesize 160
select inst_id,resource_name,ON_GRANT_Q,ON_CONVERT_Q,master_node from gv$ges_resource where resource_name like '[0xff][0x6],[BL]%';


//// get_ges_enqueue.sql 查询gv$ges_enqueue视图////
set linesize 180
select inst_id,owner_node,resource_name1,resource_name2,GRANT_LEVEL,REQUEST_LEVEL from gv$ges_enqueue where upper(RESOURCE_NAME1) like '[0XFF][0X6],[BL]%' order by inst_id,owner_node;




---实例1上执行get系列脚本
###因为之前实例1访问过这个block所以以下脚本有输出
SQL> @get_buffer_stat.sql


OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    SCUR              0 000000008BFAEE38          0          0


###block的主节点在实例2上,因为MASTER_NODE=1
SQL> @get_master_node.sql
   INST_ID RESOURCE_NAME                      ON_GRANT_Q ON_CONVERT_Q MASTER_NODE
---------- ---------------------------------- ---------- ------------ -----------
         2 [0xff][0x6],[BL][ext 0x0,0x0]               1            0           1
         
###获得block的资源名称,只有访问过这个block的节点才能查到       
SQL> @get_resource_name


HEXNAME                             RESOURCE_NAME   KJBLGRANT   KJBLROLE  KJBLOWNER KJBLMASTER   KJBLPKEY    KJBLSID KJBLREQUE
----------------------------------- --------------- --------- ---------- ---------- ---------- ---------- ---------- ---------
[0xff][0x6],[BL][ext 0x0,0x0]       255,6,BL        KJUSERPR           0          0          1      15976          0 KJUSERNL   <---KJBLPKEY等于object_id  


###inst_id=1或者MAST=0都表示block的主节点在实例2上,owner_node=0、state=GRANTED及grant_level=KJUSERPR表示目前实例1读取了这个block,经实例2的允许实例1在block上加了KJUSERPR锁
SQL> @get_resource_stat.sql         
   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         2 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      1     0     1 KJUSERNL  KJUSERPR           0         


*************
* 人工将主节点从实例2调整为实例1
*************
---在实例1上执行         
###尝试将block的主节点从实例2人工调整为实例1
SQL> oradebug setmypid;  
Statement processed.
SQL> oradebug lkdebug -m pkey 15976
Statement processed.


###MASTER_NODE=0表明block 6/255的主节点为实例1


SQL> @get_master_node.sql
   INST_ID RESOURCE_NAME                      ON_GRANT_Q ON_CONVERT_Q MASTER_NODE
---------- ---------------------------------- ---------- ------------ -----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]               1            0           0


###以下两个输出除了MASTER变成0,其他均和上一轮的输出保持一致
SQL> @get_resource_name
HEXNAME                             RESOURCE_NAME   KJBLGRANT   KJBLROLE  KJBLOWNER KJBLMASTER   KJBLPKEY    KJBLSID KJBLREQUE
----------------------------------- --------------- --------- ---------- ---------- ---------- ---------- ---------- ---------
[0xff][0x6],[BL][ext 0x0,0x0]       255,6,BL        KJUSERPR           0          0          0      15976          0 KJUSERNL        


SQL> @get_resource_stat.sql
   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSERPR           0   <---inst_id说明主节点是实例1,owner_node=0表示实例1曾经访问过block 6/255、并持有KJUSERPR锁


---实例2上执行get系列脚本
###实例2尚未访问过该block所以无输出
SQL> @get_buffer_stat.sql


no rows selected


###来看看实例2上此时的输出
SQL> @get_master_node.sql
   INST_ID RESOURCE_NAME                      ON_GRANT_Q ON_CONVERT_Q MASTER_NODE
---------- ---------------------------------- ---------- ------------ -----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]               1            0           0       <---ON_GRANT_Q=1表示block已经被授予某个节点的访问权限
         
SQL> @get_resource_name
 
no rows selected      <---因为实例2尚未访问过该block所以尚无输出


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSERPR           0


---实例2上执行block 6/255的查询、然后执行get系列脚本
select * from scott.t0820_1;
        ID
----------
         2
         
SQL> @get_buffer_stat.sql
OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    SCUR              0 000000008AFF8E28          0          0


SQL> @get_master_node.sql
   INST_ID RESOURCE_NAME                      ON_GRANT_Q ON_CONVERT_Q MASTER_NODE
---------- ---------------------------------- ---------- ------------ -----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]               1            0           0
         
SQL> @get_resource_name
HEXNAME                             RESOURCE_NAME   KJBLGRANT   KJBLROLE  KJBLOWNER KJBLMASTER   KJBLPKEY    KJBLSID KJBLREQUE
----------------------------------- --------------- --------- ---------- ---------- ---------- ---------- ---------- ---------
[0xff][0x6],[BL][ext 0x0,0x0]       255,6,BL        KJUSERPR           0          1          0      15976          0 KJUSERNL   <---KJBLOWNER=1


###inst_id=1表示block主节点是实例1,输出的两行分别表示实例1、实例2均以读的方式访问block
SQL> @get_resource_stat.sql
   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSERPR           0
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSERPR           1


###作为主节点的实例1记录了所有访问过该block的节点信息(inst_id=1的两条记录,owner_node=0记录实例1的访问,owner_node=1记录了实例2的访问),主节点所掌握的信息在RAC里称为master metadata;而实例2只记录了自己对于block的访问(inst_id=2的那条记录),非主节点掌握的信息在RAC里被称为shadow metadata
SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSERPR  KJUSERNL        
         1          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSERPR  KJUSERNL
         2          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSERPR  KJUSERNL         


*************
* 人工将主节点从实例1调整为实例2,先后在实例2、实例1上发起update操作
*************
---实例2上通过执行oradebug把block 6/255的主节点再次重置为实例2,观察master metadata是否都转移到了实例2上
SQL> oradebug setmypid;  
Statement processed.
SQL> oradebug lkdebug -m pkey 15976
Statement processed.


###果然实例2对该block的记录变为了两条(inst_id=2有两条),表明主节点对应的实例上保存RAC环境里所有节点对某个block访问时持有的锁信息
SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSERPR  KJUSERNL
         2          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSERPR  KJUSERNL      
         2          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSERPR  KJUSERNL


---实例2上发起对block的更改,运行get系列脚本
SQL> @get_buffer_stat.sql
OBJECT_NAM STATE        MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- ----------- ---------- ---------------- ---------- ----------
T0820_1    SCUR              0 0000000089F90298          0          0


update scott.t0820_1 set id=id+1;
commit;


SQL> @get_buffer_stat.sql


OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    XCUR              0 0000000089F90298          0          0
T0820_1    CR                0 00                  1947380          0


SQL> @get_resource_name.sql


HEXNAME                             RESOURCE_NAME   KJBLGRANT   KJBLROLE  KJBLOWNER KJBLMASTER   KJBLPKEY    KJBLSID KJBLREQUE
----------------------------------- --------------- --------- ---------- ---------- ---------- ---------- ---------- ---------
[0xff][0x6],[BL][ext 0x0,0x0]       255,6,BL        KJUSEREX           0          1          1      15976          0 KJUSERNL


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         2 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      1     0     1 KJUSERNL  KJUSEREX           1


SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         2          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL  <---作为主节点的实例2 master metadata信息里包含了自己(OWNER_NODE=1)修改block时加的X锁


---实例1上运行get系列脚本
SQL> @get_buffer_stat.sql


OBJECT_NAM STATE        MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- ----------- ---------- ---------------- ---------- ----------
T0820_1    CR                   0 00                  1947379          0


SQL> @get_resource_name.sql            


no rows selected <---get_resource_name.sql脚本实质上是关联x$le、x$kjbl两张表得出实例对block施加的锁信息,没有输出是因为实例1的cache里只有CR类型的buffer,只能给自己使用,不能分享其它节点,所以无需持有任何锁


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         2 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      1     0     1 KJUSERNL  KJUSEREX           1          <---只剩下了实例2 update block时留下的X锁,实例1先期加在block上的Share锁已解除


SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         2          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL             <---作为主节点的实例2 master metadata信息里包含了自己(OWNER_NODE=1)修改block时加的X锁,没有inst_id=1的记录说明实例1没有关于该block的shadow metadata


---实例1上发起对block的更改,运行get系列脚本
SQL> @get_buffer_stat.sql


OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    CR                0 00                  1947379          0


update scott.t0820_1 set id=id+1;
commit;


SQL> @get_buffer_stat.sql


OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    XCUR              0 0000000089F95818          0          0
T0820_1    CR                0 00                            0
T0820_1    CR                0 00                  1947379          0


SQL> @get_resource_name.sql


HEXNAME                             RESOURCE_NAME   KJBLGRANT   KJBLROLE  KJBLOWNER KJBLMASTER   KJBLPKEY    KJBLSID KJBLREQUE
----------------------------------- --------------- --------- ---------- ---------- ---------- ---------- ---------- ---------
[0xff][0x6],[BL][ext 0x0,0x0]       255,6,BL        KJUSEREX           0          0          1      15976          0 KJUSERNL         <---KJBLOWNER=0表示实例1访问了block


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         2 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      1     0     1 KJUSERNL  KJUSEREX           0       <---OWNER_NODE=0说明之前实例2修改block时加上的X锁已被释放,改为记录本次实例1修改block时的锁信息


SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL          <---因为最近一次修改block是从实例1发起,所以实例1的GRD里记录了OWNER_NODE=0(代表实例1)修改时持有的锁信息;实例2之所以会记录实例1锁修改时的锁信息是因为实例2是master node,必须记录所有访问过该block的节点信息
         2          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL




---实例2上运行get系列脚本

SQL> @get_buffer_stat.sql


OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    CR                0 00                  1950280          0
T0820_1    CR                0 00                  1947380          0


SQL> @get_resource_name.sql      <---实例1发起更改后,实例2 cache里只有CR类型的buffer,只能给自己使用,不能分享其它节点,所以无需持有任何锁(实质是x$bh.le_addr=NULL所以与x$le.le_addr关联无结果)


no rows selected


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         2 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      1     0     1 KJUSERNL  KJUSEREX           0


SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL
         2          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL


如果此时我们将block的master node再一次指回实例1,那么get_ges_enqueue.sql仅会显示inst_id=1的记录,因为实例2不再是主节点,所以没必要保存其它节点的block锁信息


*************
* 人工将主节点从实例2调整回实例1,观察v$ges_enqueue视图的内容
*************
---实例1执行
SQL> oradebug setmypid;
Statement processed.
SQL> oradebug lkdebug -m pkey 15976
Statement processed.


SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL    <---仅有节点1(owner_node=0)的block锁信息保存在节点1(inst_id=1)上


*************
* 重启数据库后,执行update但不提交的情况下,block锁资源查询
*************
###重启数据库
srvctl stop database -d susedb1 -o immediate
srvctl start database -d susedb1


---实例1、实例2分别查询scott.t0820_1表
select * from scott.t0820_1;


---实例1查询block 6/255资源上的锁持有情况,此时实例1是主节点,实例1、实例2都对block持有共享读模式的锁
SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSERPR           0
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSERPR           1


---实例1执行update后不提交,紧接着运行get系列脚本
update scott.t0820_1 set id=id+1;


SQL> @get_buffer_stat.sql


OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    XCUR              0 0000000089F90C18          0          0
T0820_1    CR                0 00                  2015904          0


SQL> @get_resource_name.sql


HEXNAME                             RESOURCE_NAME   KJBLGRANT   KJBLROLE  KJBLOWNER KJBLMASTER   KJBLPKEY    KJBLSID KJBLREQUE
----------------------------------- --------------- --------- ---------- ---------- ---------- ---------- ---------- ---------
[0xff][0x6],[BL][ext 0x0,0x0]       255,6,BL        KJUSEREX           0          0          0      15976          0 KJUSERNL


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSEREX           0


SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL


---实例2运行get系列脚本查看资源状态信息
SQL> @get_buffer_stat.sql


OBJECT_NAM STATE        MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- ----------- ---------- ---------------- ---------- ----------
T0820_1    CR                   0 00                  2015903          0


SQL> @get_resource_name.sql


no rows selected           <---原有的KJUSERPR锁解除


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSEREX           0


SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL         
         
---实例2 update同一条记录,
update scott.t0820_1 set id=id+1;


<----处于等待


SQL> @get_buffer_stat.sql


OBJECT_NAM STATE        MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- ----------- ---------- ---------------- ---------- ----------
T0820_1    XCUR                 0 0000000089F96198          0          0
T0820_1    CR                   1 00                  2016429          0
T0820_1    CR                   0 00                  2015903          0


SQL> @get_resource_name.sql


HEXNAME                             RESOURCE_NAME   KJBLGRANT   KJBLROLE  KJBLOWNER KJBLMASTER   KJBLPKEY    KJBLSID KJBLREQUE
----------------------------------- --------------- --------- ---------- ---------- ---------- ---------- ---------- ---------
[0xff][0x6],[BL][ext 0x0,0x0]       255,6,BL        KJUSEREX          64          1          0      15976          0 KJUSERNL


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSERNL           0   <---如果实例1的buffer cache里有pi类型的block在,才会有这条记录
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSEREX           1   <---虽然实例2的会话因为锁而处于等待,但GRANT_LEVEL还是显示为KJUSEREX,从GC视图看不出行级锁的存在


SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          0 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSERNL  KJUSERNL
         1          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL
         2          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL   <---虽然实例2的会话因为锁而处于等待,但GRANT_LEVEL还是显示为KJUSEREX


---实例1执行get系列脚本


SQL> @get_buffer_stat.sql


OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    CR                0 00                  2016429          0
T0820_1    CR                0 00                  2016430          0
T0820_1    CR                0 00                  2015904          0


SQL> @get_resource_name.sql


no rows selected               <---因为实例1的buffer里都是CR类型的block,所以这里必然返回0条记录


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSEREX           1    <---实例1的buffer cache里有pi类型的block因为checkpoint发生变成CR了,所以相比上次在实例2的执行,结果里少了OWNER_NODE=1的记录
 
SQL> @get_ges_enqueue.sql


   INST_ID OWNER_NODE RESOURCE_NAME1                 RESOURCE_NAME2                 GRANT_LEV REQUEST_L
---------- ---------- ------------------------------ ------------------------------ --------- ---------
         1          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL     <---相比上次在实例2执行的输出少了owner_node=0、GRANT_LEVEL/REQUEST_LEVEL=KJUSERNL的记录,因为实例1上的pi block变成了CR
         2          1 [0xff][0x6],[BL][ext 0x0,0x0]  255,6,BL                       KJUSEREX  KJUSERNL


*************
* 实例1回滚后,block资源使用情况观察
*************
---实例1 执行rollback回滚刚才的更改
SQL> update scott.t0820_1 set id=id+1;


1 row updated.


SQL> rollback;


Rollback complete.


SQL> @get_buffer_stat.sql   <---回滚后可看到PI出现


OBJECT_NAM STATE        MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- ----------- ---------- ---------------- ---------- ----------
T0820_1    PI                   0 0000000089F90C18          0          0
T0820_1    CR                   0 00                  2016429          0
T0820_1    CR                   0 00                  2016430          0
T0820_1    CR                   0 00                  2015904          0


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSERNL           0   <---PI block保留有KJUSERNL锁,这点与CR block不同,后者没有任何锁
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSEREX           1


SQL> alter system checkpoint;


System altered.


SQL> @get_buffer_stat.sql


OBJECT_NAM STATE     MODE_HELD LE_ADDR          CR_SCN_BAS CR_SCN_WRP
---------- -------- ---------- ---------------- ---------- ----------
T0820_1    CR                0 00                  2020380          0     <---checkpoint发生后PI变成了CR
T0820_1    CR                0 00                  2016429          0
T0820_1    CR                0 00                  2016430          0
T0820_1    CR                0 00                  2015904          0


SQL> @get_resource_stat.sql


   INST_ID RESOURCE_NAME                      STATE     MAST  CNVT  GRNT REQUEST_L GRANT_LEV OWNER_NODE
---------- ---------------------------------- -------- ----- ----- ----- --------- --------- ----------
         1 [0xff][0x6],[BL][ext 0x0,0x0]      GRANTED      0     0     1 KJUSERNL  KJUSEREX           1   <---REQUEST_LEVEL/GRANT_LEVEL均为KJUSERNL的记录消失




总结:
1、当多个节点在自己的buffer cache里拥有同一block的scur buffer时,他们对block持有的KJUSERPR类型的锁信息可以并存于GRD
2、当某节点修改了block,该block xcur类型的buffer出现在执行修改操作节点的buffer cache,其余节点只会有PI或CR类型的buffer,对于每个PI类的buffer GRD里各保留一行REQUEST_LEVEL/GRANT_LEVEL均为KJUSERNL的记录;对于CR类的buffer GRD里不保留任何锁信息


本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
【故障处理】队列等待之 enq: US - contention 案例 1    BLOG 文档结构图       2    前言部分 2.1    导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识, ~O(∩_∩)O~ : ① enq: US - contention 等待事件的解决 ② 一般等待事件的解决办法 ③ 队列等待的基本知识   Tips: ① 本文在 ITpub ( http://blog.itpub.net/26736162 )、博客园
    在Oracle 10g的中搭建Data Guard环境真是一个纠结,目前大体都是采用两种方式,一种是rman备份,一种是duplicate的方式,但是这两个地方不够让我满意,一来是rman备份数据量不小,需要先在本地生成备份,然后拷贝到备库去,这个搭建周期略长,另外一个就是推荐的方式duplicate,在10g中有些鸡肋的味道,本地备份,然后拷贝到备库,然后动用duplicate的方式,这样的方式还不如手工rman的方式同步来得顺心顺意,所以在10g中我是不怎么喜欢duplicate方式。当然11g
【故障处理】队列等待之 TX - allocate ITL entry 引起的死锁处理 1    BLOG 文档结构图       2    前言部分 2.1    导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识, ~O(∩_∩)O~ : ① enq: TX - allocate ITL entry 等待事件的解决 ② 一般等待事件的解决办法 ③ 队列等待的基本知识 ④  ITL 死锁解决 ⑤  ITL 死锁模拟 ⑥  Merge 语句的非关联形式的查
【技巧】如何使用客户端发布 BLOG+ 如何快速发布微信公众号文章   1    BLOG 文档结构图     2    前言部分   2.1    导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识, ~O(∩_∩)O~ : ①  如何使用客户端发布 BLOG (重点) ②  如何快速发布微信公众号文章 ③  如何批量上传图片到blog ④  如何批量上传图片到微信公众号上     Tips: ① 本文在 itpub ( http://blog.itpu

降低高水位线的方法 - 2016-09-13 14:09:09

准备工作,创建一张表: CREATE TABLE TEST2 (     ID    NUMBER(10),     NAME  VARCHAR2(32) ); 1、移动表: SQL begin   2  for i in 1..10000 loop   3  insert into test2 values(i,'bbb');   4  end loop;   5  commit;   6  end;   7  / PL/SQL procedure successfully completed. SQL
预备知识: 1)row cache lock事件   --内存share pool分为library cache,dictionary cache;而row cache lock对象分布在dictionary cache中,是由于对于字典缓冲的访问造成的;   --这类属于latch类的资源竞争,相当耗CPU,如果并发量大的话,容易down机 如果发现这个等待十分高,一般来说可能由于2种原因,一是共享池太小了,需要增加共享池,另外一种情况是SQL分析过于频繁,对于共享池的并发访问量过大。对于任何一种情况,绝
【故障处理】队列等待之 TX - allocate ITL entry 案例 1    BLOG 文档结构图       2    前言部分 2.1    导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识, ~O(∩_∩)O~ : ① enq: TX - allocate ITL entry 等待事件的解决 ② 一般等待事件的解决办法 ③ 队列等待的基本知识 Tips: ① 本文在 ITpub ( http://blog.itpub.net/267361
Oracle 一次缩小表空间的处理过程 1    BLOG 文档结构图       2    前言部分 2.1    导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识, ~O(∩_∩)O~ : ①  收缩表空间的几种办法 ② 表空间大小查询 ③  AIX 下查询磁盘空间大小的 shell 脚本 ④ 删除数据文件的正确方法 ⑤  ORA-03262 处理 ⑥ 缩小数据文件 ⑦  su - grid asmcmd lsdg 的使用 ⑧ 其他常用命令   Ti
等待事件系列(1)--User I/O类型(上) 全文可参考: http://www.cnblogs.com/lhrbest/articles/5835420.html   1    BLOG 文档结构图     2    前言部分   2.1    导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识, ~O(∩_∩)O~ : ①  等待事件系列(1)--User I/O类型     Tips: ① 本文在 ITpub ( http://blog.itpu
等待事件系列(1) --User I/O 类型(下) 全文可参考: http://www.cnblogs.com/lhrbest/articles/5835420.html   1    BLOG 文档结构图   6.3      d b file parallel read SELECT   * FROM    v$event_name WHERE    NAME   IN   ( 'db file parallel read' );   在 V$SESSION_WAIT这个视图里面,这个等待事件有三个