分享

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

 数据和云 2020-07-01

回顾前文:

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

作者简介

韩朝阳

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

什么是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./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./index.php?m=Article&a=show&id=106查看

注意:

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

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

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

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

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

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多