
//通过rdba查找一个数据块 //vRDBA:数据块的地址(FILEID+BLOCKID) //vSCN:用于一致性读的SCN Find Buffer( int vRDBA,int vSCN) { //获取该数据块的HASH链的HASH值 v_hash_value=getRdbaHash(vRDBA); //SPIN 相关cache buffers chains,根据hash value选择不同的子闩锁 while (!spinLatch('cache buffers chains',v_hash_value)) { 如果spin失败,就sleep,然后继续SPIN pinLatchSleep(sleepTime++); } //在指定的hash chains中查找符合某个SCN条件的数据块的BUFFER HEAD,这个功能用于MVCC多版本控制,产生一致性读 retVal=findBufferInHashChains(v_hash_value,vRDBA,vScn,); if(retVal==O_找到兼容版本数据) //如果找到了兼容的版本的DB CACHE数据,那么通过BH中的指针找到这个CACHE的地址, //然后将该地址写入UGA的访问该数据块的LIBRARY CACHE的访问数据块列表中 { //vkcbh是这个buffer的buffer head,这个bh被链接在HASH CHAINS上,kcbbhba是BH对应的BUFFER的地址 vksuse->ksusesql->...=vkcbh->kcbbhba; //释放CACHE BUFFERS CHAINS闩锁,然后返回,结束访问 unpinLatch('cache buffers chains',v_hash_value); return; } else { if(retVal==(O_找到BUFFER||O_当前快||O_SCN不兼容) //需要生成CR BLOCK,然后读取 { //释放CACHE BUFFERS CHAINS闩锁,然后返回,结束访问 unpinLatch('cache buffers chains',v_hash_value); //查找一个空闲的BUFFER,用于生成CR block //查找空闲块,将起buffer head赋予vbh,如果找不到,反复重试 while((vbh=findFreeBuffer())==null) { //如果没有找到空闲块,发出makefree消息,然后SLEEP,等待唤醒 sendMakeFreeMsg(); sleepForFreeMsg(); } //再次获取相关cache buffers chains,根据hash value选择不同的子闩锁 while (!spinLatch('cache buffers chains',v_hash_value)) { //如果spin失败,就sleep,然后继续SPIN pinLatchSleep(sleepTime++); } //下面操作省略,算法十分复杂,先复制CURRENT的BUFFER到新BUFFER,然后通过UNDO数据前滚数据块的数据 ... ... ... //处理完成,释放cache buffers chains闩锁,然后返回 unpinLatch('cache buffers chains',v_hash_value); return; } } else //没有找到BUFFER,找一个可用的BUFFER,从数据文件读入相关BLOCK { //释放CACHE BUFFERS CHAINS闩锁,然后返回,结束访问 unpinLatch('cache buffers chains',v_hash_value); //查找一个空闲的BUFFER,用于读取数据块 //查找空闲块,将起buffer head赋予vbh,如果找不到,反复重试 while((vbh=findFreeBuffer())==null) { //如果没有找到空闲块,发出makefree消息,然后SLEEP,等待唤醒 sendMakeFreeMsg(); sleepForFreeMsg(); } //再次获取相关cache buffers chains,根据hash value选择不同的子闩锁 while (!spinLatch('cache buffers chains',v_hash_value)) { //如果spin失败,就sleep,然后继续SPIN pinLatchSleep(sleepTime++); } //下面省略,从数据文件中读取该数据块 ... ... ... //处理完成,释放cache buffers chains闩锁,然后返回 vksuse->ksusesql->...=vkcbh->kcbbhba; //以下省略,从数据块中查找所需要的记录 … … unpinLatch('cache buffers chains',v_hash_value); return; } } |
上面这段代码是老白理解的数据块被读入DB CACHE并被检索的过程,和Oracle 实际的算法可能相差十万八千里。不过老白这段代码体现出了Oracle DB CACHE操作的一些基本的原理性的东西。大家可以参考。要访问某个数据块,首先要计算出该数据块的HASH VALUE,然后获取该HASH链的相关闩锁,再去搜索HASH CHAINS。搜索的时候不仅要找到RDBA一致的数据块,而且其SCN也要符合要求,如果SCN不符合要求,那么我们可能需要产生CR块,再从CR块中读取相关数据。
这部分的知识点十分丰富,而且和很多知识点都有关联和交叉,因此老白这段代码只是考虑了最为简单的场景。如果大家有兴趣,可以继续细化这段代码,从而更深入的理解这些知识点。
这部分相关的知识点包括:working set(x$kcbwds)、DB BLOCK(包括数据文件、表空间、extent、segment等)、buffer head(x$bh)、hash chains、lru chains、undo、会话和PGA等等。




