揭密buffer Cache中的链表补遗

2020-06-23 00:00:00 磁盘 内容 省略 无意义 摘掉
揭密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,这个就是猜想了。我尽量找个测试实际验证下。

相关文章