暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【数据一致性校验】如何计算Oracle Block的校验值

韩朝阳 2017-02-15
1068

编辑手记:上周分享了备份的有效性校验,其中提到了一个概念,叫做数据块的校验值(checksum),该值用于判断数据块是否损坏。今天我们来深入学习,如何计算Oracle数据块的校验值。


回顾前文:

讲真,你该做备份的一致性校验了


作者简介

韩朝阳


超过10年的专业数据库运维管理服务经验,服务的产品主要包括Oracle Database,Oracle EBS,Oracle MiddleWare,Oracle Exadata。熟悉Oracle数据库高可用架构,擅长Oracle 数据库架构规划、优化、故障诊断及异常恢复。曾长期服务于Oracle公司美国数据中心。喜欢做有挑战性的事情。个人网站http://ohsdba.cn


什么是checksum?

An optional checksum of the block contents. When a block is written, the checksum is eithercleared or set depending on the setting of the db_block_checksum parameter.When a block is read, the checksum is verified if present and if the parameteris set to TRUE. Checksums are always calculated and checked for blocks in theSYSTEM tablespace. 

(选自于http://www.ixora.com.au/notes/cache_header.htm


意思是说Checksum是一个可选项,当一个块被写入后,checksum或许会被设置或许会被清除,这个取决于db_block_checksum参数的设置。当读取一个块时,Checksum会被检验,如果db_block_checksum参数设置为true,并且这个块存在Checksum。SYSTEM表空间总是会被校验和检查无论db_block_checksum设置为True或False。


曾经有过的关于Checksum猜想?

A.如果是对整个数据块做Checksum,然后写入数据块头部,如果是这样下次做Checksum和数据库头部原来Checksum值会不一致。


B.如果是对数据块除了头部(除Cache Layer外)做checksum,然后把这个Checksum值写入头部,理论上感觉这样也可以,但不能保证头部的变化。

 

Checksum的正确算法

The checksum is theXOR of all the other 2-byte pairs in the block. Thus when a block with achecksum is checked, the XOR of all the 2-byte words in the block should be 0.


以2个byte为一组,除offset16,17(从offset 0开始算起)外对块中所有内容做异或运算XOR(异或运算:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0),然后把这个数值写入offset16,17(从offset 0开始算起)。这样整个块的异或计算之后的值就等于0。如果对数据块做更改,重新校验的值和原来offset(从offset 0开始算起)的值就不匹配。所以用BBED更改块后,必须重新计算和应用才能保证块的一致性。


大家也可以思考这样一个问题:假定Checksum(chkval_kcbh)占用2个字节,可不可以是3个byte一组,4个byte一组或者更多为一组呢?


Checksum的标识KCBHFCKV

几乎所有的块都有这个信息,占用20个字节,记录着块类型、版本、格式、RDBA、SCN和数据块的校验信息等信息。


type_kcbh:大部分块的类型是都是6(代表表、索引等类型的块)
frmt_kcbh:块格式。不同版本,不同的文件,这个值也不一样

Oracle 6,7 : 0x01

  8i~9i:all: 0x02

10g~12c:2k : 0x62

        4k : 0x82

        8k : 0xa2

       16k : 0xc2

Redo 6~12c : 0x22

rdba_kcbh:数据块地址

AODU> rdba 0x01400017

        rdba : 0x01400017=20971543 (dba=5,23)

        rfile# : 5

        block# : 23

        Dump Block: alter system dump datafile 5 block 23;

AODU>

flg_kcbh:块标识,不同的值代表不同的意思

#define KCBHFNEW 0x01 * new block */

#define KCBHFDLC 0x02 * last change to the block was fora cleanout operation */

#define KCBHFCKV 0x04 * checksum value is set */

#define KCBHFTMP 0x08 * temporary data */

 

其中KCBHFCKV是Checksum的标识,如果不设置,修改块时将不会计算新的Checksum值.


下面的测试时将flg_kcbh[0x06 (KCBHFDLC, KCBHFCKV)]修改为[0x02 (KCBHFDLC)]


BBED> m x 02 offset 15

Warning: contents of previous BIFILE will be lost.Proceed? (Y/N) y

File:/oradata/upgr/ohsdba.dbf (5)

Block: 13   Offsets:15 to 30   Dba:0x0140000d

-----------------------------------------------------------

02f81f00 0001000000c85501 0048c312

<32 bytes perline>


修改flg_kcbh过后,再计算checksum,值保持不变

BBED> sum

Check value for File 5, Block 13:

current = 0x1ff8, required = 0x1ff8

BBED> m x ff offset 90

File:/oradata/upgr/ohsdba.dbf (5)

Block: 13    Offsets: 90 to 105   Dba:0x0140000d

-----------------------------------------------------------------------

ff000000 0000000000000001 0100ffff

<32 bytes perline>


随便做个更改,重新计算Checksum,Checksum值依旧保持不变

BBED> sum
Check value for File 5, Block 13:
current = 0x1ff8, required = 0x1ff8
BBED>


验证Checksum算法

用dd复制数据块23,然后用oddump这个块内容。由于Linux为小端,需要将od输出内容做翻转,比如第一个a206,应该为06a2。也可以直接使用dd命令加conv=swab来以正常的格式来查看块内容。


可参考“如何在小端服务器以正常格式查看Oracle数据文件”http://www.ohsdba.cn/index.php?m=Article&a=show&id=106查看

 


注意:

-->这个后面是对应的XOR操作的结果,然后再将每行计算结果做XOR,最后计算出结果为2AFC。


如果感兴趣,自己可以动手算下。其实数据文件、控制文件、日志文件os块,也就是常说的block0,也有Checksum值。

 

大家也可以思考这样一个问题:假定Checksum(chkval_kcbh)占用2个字节,可不可以是3个byte一组,4个byte一组或者更多为一组呢?

请在留言中给出你的思考。

加入"云和恩墨大讲堂"微信群,参与讨论学习

搜索 盖国强(Eygle) :eyygle,或者扫描下面二维码,备注:云和恩墨大讲堂,即可入群。每周与千人共享免费技术分享,与讲师在线讨论。


关注微信,获得后续精彩分享

文章转载自韩朝阳,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论