编辑手记:上周分享了备份的有效性校验,其中提到了一个概念,叫做数据块的校验值(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,或者扫描下面二维码,备注:云和恩墨大讲堂,即可入群。每周与千人共享免费技术分享,与讲师在线讨论。