揭密buffer Cache中的链表补遗
揭密buffer Cache中的链表补遗:
(揭密Oracle之七种武器之四:揭密Buffer Cache中的链表
http://www.itpub.net/thread-1631537-1-1.html)
补充两个问题:
1、如果一个脏块在CKPT-Q上,当此脏块被移到LRUW时,会从CKPT-Q上去掉吗?
回答:不会。直到从LRUW上被写到磁盘上后,才会从CKPT-Q上去掉。
测试过程很简单,搞一个脏块,然后再运行一个需要大量扫描LRU的操作,我是这样的:
set autot trace
update a2_70m set id2=id2+0 where id1=1;
commit;
select * from a4_70m;
(测试环境和前面所述一致,Buffer Cache 100M,a4_70m 80M,但它被设为了Cache)
然后在另一会话中不停运行如下几条语句:
alter session set events 'immediate trace name SET_TSN_P1 level 5';
set pagesize 50000
set linesize 10000
select file#,dbablk,tch,lru_flag,ba,decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',6,'irec',7,'write',8,'pi', 9,'memory',10,'mwrite',11,'donated'),
decode(bitand(flag,1), 0, 'N', 'Y') dirty,NXT_REPL,PRV_REPL,WA_NXT,WA_PRV,ts#,HLADDR from x$bh a where file#=4 and dbablk=20
order by FILE# , DBABLK;
select CNUM_SET,CNUM_REPL,ANUM_REPL,CNUM_WRITE ,ANUM_WRITE from x$kcbwds where cnum_set>0;
alter session set events 'immediate trace name BUFFER level 0x01000014';
在DUMP结果中,可以找到如下内容:
BH (7c3f497c) file#: 4 rdba: 0x01000014 (4/20) class: 1 ba: 7c298000
……………………(省略部分无意义内容)…………………………………………………………
hash: [8e96e068,8e96e068] lru: [80bf9cc8,7c7efffc]
obj-flags: object_ckpt_list
ckptq: [7bfe8140,7dfea5d0] fileq: [8ea707ec,8ea707ec] objq: [88c3d034,88c3d034]
……………………(省略部分无意义内容)…………………………………………………………
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x7C298000 to 0x7C29A000
……………………(省略部分无意义内容)…………………………………………………………
BH (7c3f497c) file#: 4 rdba: 0x01000014 (4/20) class: 1 ba: 7c298000
……………………(省略部分无意义内容)…………………………………………………………
hash: [8e96e068,8e96e068] lru-write: [8ea63e58,7c7efffc]
obj-flags: object_ckpt_list
ckptq: [7bfe8140,7dfea5d0] fileq: [8ea707ec,8ea707ec] objq: [88c3d034,88c3d034]
……………………(省略部分无意义内容)…………………………………………………………
上一次DUMP的时候,LRU链前后块的指针为lru: [80bf9cc8,7c7efffc],下一次DUMP时,已经变成lru-write: [8ea63e58,7c7efffc],但检查点队列相关的信息没变,都是ckptq: [7bfe8140,7dfea5d0]。
当脏块写完成时,BH中信息变为这样:
BH (7c3f497c) file#: 4 rdba: 0x01000014 (4/20) class: 1 ba: 7c298000
……………………(省略部分无意义内容)…………………………………………………………
hash: [8e96e068,8e96e068] lru: [7c7efffc,7c3f2f18]
lru-flags: on_auxiliary_list
ckptq: [NULL] fileq: [NULL] objq: [88c3d02c,88c3d02c]
……………………(省略部分无意义内容)…………………………………………………………
从lru-write: [8ea63e58,7c7efffc],变为了lru: [7c7efffc,7c3f2f18],从lru-flags可以看到,已经被放到辅助链表中了。同时,ckptq已经是NULL了。写磁盘完成时,才从CKPT-Q上摘掉。
2、根据上面的测试结果,脏块可能会同时存在于两个链表:LRUW和CKPT-Q。块从LRUW写磁盘后,会从CKPT-Q上摘掉。但反过来呢?从CKPT-Q中写磁盘,写完后会从LRUW上摘掉吗?
答案是,会的。
如何验证呢?我是通过Latch的获取来验证的。
脏块通过CKPT-Q写到磁盘后,其所处的LRU位置不变,这一点我在前文中已经提到过,也很容易验证这点,从x$BH中的NXT_REPL,PRV_REPL两列,就可以验证此点。也就是说,从CKPT-Q写脏块,是和LRU链表无关的,也就是不需要获得LRU Latch。如果从CKPT-Q写脏块申请了LRU Latch,哪一定和LRUW有关。
将检查点超时参数设为很小的值,写个简单的DTrace脚本,跟踪一下DBWR进程Latch的获得情况。发现每次从CKPT-Q写脏块时,DBWR都要按如下顺序申请Latch:
获得cache buffers chains Latch
获得LRU Latch
释放LRU Latch
释放cache buffers chains Latch
获得checkpoint queue latch
释放checkpoint queue latch
获得cache buffers lru chain
释放cache buffers lru chain
也就是说,从CKPT-Q写脏块时,不但要获得checkpoint queue latch,还要LRU Latch。根据前面的分析,从CKPT-Q写脏块时,获取LRU Latch的目的,只能是为了访问LRUW,因为CKPT-Q写不改变块在LRU的位置,不必要访问LRU。哪么,CKPT-Q写访问LRUW的目的是什么,可以推论,目的是为了检查脏块是否在LRUW、并摘掉它。
还有一点,由于块已经从LUR移到了LURW,从CKPT-Q写完成后,虽然不是从LURW写的,块应该仍会被放入辅助LRU,这个就是猜想了。我尽量找个测试实际验证下。
相关文章