阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

初探Cache Fusion对block的锁管理

452次阅读
没有评论

共计 21315 个字符,预计需要花费 54 分钟才能阅读完成。

本文以双节点 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 里不保留任何锁信息

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-09/135135.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计21315字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
8002024
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸

一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸

一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸 前言 作为天天跟架构图、拓扑图死磕的...
12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换...
告别Notion焦虑!这款全平台开源加密笔记神器,让你的隐私真正“上锁”

告别Notion焦虑!这款全平台开源加密笔记神器,让你的隐私真正“上锁”

  告别 Notion 焦虑!这款全平台开源加密笔记神器,让你的隐私真正“上锁” 引言 在数字笔记工...
小白也能看懂:什么是云服务器?腾讯云 vs 阿里云对比

小白也能看懂:什么是云服务器?腾讯云 vs 阿里云对比

小白也能看懂:什么是云服务器?腾讯云 vs 阿里云对比 星哥玩云,带你从小白到上云高手。今天咱们就来聊聊——什...
星哥带你玩飞牛NAS-12:开源笔记的进化之路,效率玩家的新选择

星哥带你玩飞牛NAS-12:开源笔记的进化之路,效率玩家的新选择

星哥带你玩飞牛 NAS-12:开源笔记的进化之路,效率玩家的新选择 前言 如何高效管理知识与笔记,已经成为技术...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

  240 元左右!五盘位 NAS 主机,7 代 U 硬解 4K 稳如狗,拓展性碾压同价位 在 NA...
安装并使用谷歌AI编程工具Antigravity(亲测有效)

安装并使用谷歌AI编程工具Antigravity(亲测有效)

  安装并使用谷歌 AI 编程工具 Antigravity(亲测有效) 引言 Antigravity...
你的云服务器到底有多强?宝塔跑分告诉你

你的云服务器到底有多强?宝塔跑分告诉你

你的云服务器到底有多强?宝塔跑分告诉你 为什么要用宝塔跑分? 宝塔跑分其实就是对 CPU、内存、磁盘、IO 做...
让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级

让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级

让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级 大家好,我是星哥,之前写了一篇文章 自己手撸一...
星哥带你玩飞牛NAS-14:解锁公网自由!Lucky功能工具安装使用保姆级教程

星哥带你玩飞牛NAS-14:解锁公网自由!Lucky功能工具安装使用保姆级教程

星哥带你玩飞牛 NAS-14:解锁公网自由!Lucky 功能工具安装使用保姆级教程 作为 NAS 玩家,咱们最...