关于fractured block的修复

| 4 Comments | No TrackBacks

我们先来看一下大家都耳熟能详的oracleblock的粗略结构:

oracle block structure resize.jpg

 

Typ:    Block type

Fmt:    Block format; in Oracle8, Oracle8i and Oracle9i this is 0x02

Filler:   Not currently used

RDBA:  Relative database address of the block

SCNBase:   SCN base

SCNWrap:   SCN wrap

Seq:  Sequence number incremented for each change made to the block at the same SCN

Flg:  Flag (as defined in kcbh.h)

  #define KCBHFNEW 0x01 /* new block - zeroed data area     */

  #define KCBHFDLC 0x02 /* Delayed Logging Change advance SCN/seq */

  #define KCBHFCKV 0x04 /* ChecK Value saved-block xor's to zero */

  #define KCBHFTMP 0x08 /* Temporary block */

ChkVal:   Optional check value for the block

Tail:   Information to verify that the beginning and the end of the block are of the same version (lower order 2 bytes of SCNBase, plus block type, plus SCN Seq number)

Note: If there are 254 changes at the same SCN, then it is necessary to force a new SCN allocation on the next change of the block.

 

好了,有了理论基础后我们来分两步构造一个fractured block的例子:

SQL> desc t2;

Name Type        Nullable Default Comments

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

C1   NUMBER      Y                        

C2   VARCHAR2(5) Y 

 

SQL> select c1,c2,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location from t2;

 

        C1 C2    LOCATION

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

         1 a     133_34

         2 d     133_34

         3 c     133_34

 

BBED> set file 133

        FILE#           133

 

BBED> set block 34

        BLOCK#          34

 

BBED> dump

 File: /dras20/astca/test01.dbf (133)

 Block: 34               Offsets:    0 to  511           Dba:0x21400022

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

 06020000 21400022 a9e7d1b7 00080106 39dc0000 01000000 0001505c a9e7d1aa

 00080000 00020300 00000000 000a0014 0000c212 12c0001b 2c442f00 20030000

 a9e7d1b7 00000000 00000000 00000000 00000000 00000000 00000000 00010003

 ffff0018 1f881f6d 1f6d0000 00031f98 1f901f88 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 

 <32 bytes per line>

 

BBED> set offset 8000

        OFFSET          8000

 

BBED> dump

 File: /dras20/astca/test01.dbf (133)

 Block: 34               Offsets: 8000 to 8191           Dba:0x21400022

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

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 2c010202 c1040163 2c010202 c1030164 2c010202 c1020161 d1b70601

 

 <32 bytes per line>

 

Oracle402e中指出:

The Tail field corresponds to the last four bytes of the data block, and is used as a sanity check to detect fractured blocks.

 

现在我们把上述tail改掉,第一步我们只改tail

BBED> set file 133

        FILE#           133

 

BBED> set block 34

        BLOCK#          34

 

BBED> set offset 8188

        OFFSET          8188

 

BBED> dump

 File: /dras20/astca/test01.dbf (133)

 Block: 34               Offsets: 8188 to 8191           Dba:0x21400022

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

 d1b70601

 

 <32 bytes per line>

 

BBED> modify /x d1b70602

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

 File: /dras20/astca/test01.dbf (133)

 Block: 34               Offsets: 8188 to 8191           Dba:0x21400022

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

 d1b70602

 

 <32 bytes per line>

 

BBED> sum apply

Check value for File 133, Block 34:

current = 0x39df, required = 0x39df

 

等我改完后再查询t2oracle这时候如期报错了:

SQL> select * from t2;

 

select * from t2

 

ORA-01578: ORACLE data block corrupted (file # 133, block # 34)

ORA-01110: data file 133: '/dras20/astca/test01.dbf'

 

相应的alert log里显示:

***

Corrupt block relative dba: 0x21400022 (file 133, block 34)

Fractured block found during buffer read

Data in bad block -

 type: 6 format: 2 rdba: 0x21400022

 last change scn: 0x0008.a9e7d1b7 seq: 0x1 flg: 0x06

 consistency value in tail: 0xd1b70602

 check value in block header: 0x39df, computed block checksum: 0x0

 spare1: 0x0, spare2: 0x0, spare3: 0x0

***

Reread of rdba: 0x21400022 (file 133, block 34) found same corrupted data

 

也就是说oracle这里确实是通过检查tail来决定是否是fractured block

 

但是,通常checksum value不对和fractured block的出现不会仅仅是单纯的checksum value或者tail的值不对,往往还伴随着block内部数据的损坏。

 

这种情况下我们应该怎么办?

 

好了,我们现在来进行第二步,把表t2中的c1=3的那条记录彻底改坏:

BBED> set file 133

        FILE#           133

 

BBED> set block 34

        BLOCK#          34

 

BBED> set offset 8164

        OFFSET          8164

 

BBED> dump

 File: /dras20/astca/test01.dbf (133)

 Block: 34               Offsets: 8164 to 8191           Dba:0x21400022

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

 2c010202 c1040163 2c010202 c1030164 2c010202 c1020161 d1b70602

 

 <32 bytes per line>

 

BBED> modify /x 1111111111111111

 File: /dras20/astca/test01.dbf (133)

 Block: 34               Offsets: 8164 to 8191           Dba:0x21400022

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

 11111111 11111111 2c010202 c1030164 2c010202 c1020161 d1b70602

 

 <32 bytes per line>

 

BBED> sum apply

Check value for File 133, Block 34:

current = 0xd7bb, required = 0xd7bb

 

在这种情况下我们来尝试一下ODU是否能读出其余的c1=1c1=2的那两条记录:

$ export LIBPATH=$ORACLE_HOME/odu/lib:$LIBPATH

$ ./odu

 

Oracle Data Unloader:Release 2.6.0

 

Copyright (c) 2008,2009 XiongJun. All rights reserved.

 

Web: http://www.laoxiong.net

Email: magic007cn@gmail.com

 

loading default config.......

 

byte_order big

block_size  8192

data_path   data

lob_path    lob

charset_name ZHS16GBK

ncharset_name AL16UTF16

output_format text

lob_storage infile

clob_byte_order little

trace_level 1

delimiter

file_header_offset 0

 

 

 

load control file 'config.txt' successful

loading default control file ......

 

 

 ts#   fn  rfn bsize   blocks bf offset filename

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

   0    1    1  8192    64000 N       0 /dras11/oradata/astca/system01.dbf

   0  125  125  8192   128000 N       0 /dras21/astca/system02.dbf

  84  133  133  8192      128 N       0 /dras20/astca/test01.dbf

load control file 'control.txt' successful

loading dictionary data......

 

ODU> unload dict

CLUSTER C_USER# file_no: 1 block_no: 89

TABLE OBJ$ file_no: 1 block_no: 121

CLUSTER C_OBJ# file_no: 1 block_no: 25

CLUSTER C_OBJ# file_no: 1 block_no: 25

found IND$'s obj# 19

found IND$'s dataobj#:2,ts#:0,file#:1,block#:25,tab#:3

found TABPART$'s obj# 230

found TABPART$'s dataobj#:230,ts#:0,file#:1,block#:1657,tab#:0

found INDPART$'s obj# 234

found INDPART$'s dataobj#:234,ts#:0,file#:1,block#:1689,tab#:0

found TABSUBPART$'s obj# 240

found TABSUBPART$'s dataobj#:240,ts#:0,file#:1,block#:1737,tab#:0

found INDSUBPART$'s obj# 245

found INDSUBPART$'s dataobj#:245,ts#:0,file#:1,block#:1777,tab#:0

found IND$'s obj# 19

found IND$'s dataobj#:2,ts#:0,file#:1,block#:25,tab#:3

found LOB$'s obj# 156

found LOB$'s dataobj#:2,ts#:0,file#:1,block#:25,tab#:6

found LOBFRAG$'s obj# 258

found LOBFRAG$'s dataobj#:258,ts#:0,file#:1,block#:1881,tab#:0

 

ODU> unload table dras.t2

 

Unloading table: T2,object ID: 86108

Unloading segment,storage(Obj#=86108 DataObj#=86108 TS#=84 File#=133 Block#=33 Cluster=0)

 

ODU> exit

$ ls

col.odu      control.txt  ext.odu      lib          lobfrag.odu  obj.odu      segment.txt  user.odu

config.txt   data         ind.odu      lob.odu      login.sql    odu          tab.odu

 

$ cd data

 

$ ls

DRAS_T2.ctl             ODU_ODU_0000086133.ctl  ODU_ODU_0000086133.txt  ODU_ODU_0000086134.sql  sample.txt

DRAS_T2.sql             ODU_ODU_0000086133.log  ODU_ODU_0000086134.ctl  ODU_ODU_0000086134.txt

DRAS_T2.txt             ODU_ODU_0000086133.sql  ODU_ODU_0000086134.log  login.sql

 

$ cat DRAS_T2.txt

1a

2d

 

熊哥ODU太牛了,我们从结果来可以看到,我只是随便用了特别旧的2.6的版本(ODU的最新版本是3.0.8)就已经可以支持fractured block了。

 

感觉ODU这里是跳过了它认为有问题的数据行。

我们现在还原c1=3的那条数据,并把c1=2的那条数据改坏。这么做是为了验证ODU在出错后是否会继续unload数据

BBED> set file 133

        FILE#           133

 

BBED> set block 34

        BLOCK#          34

 

BBED> set offset 8164

        OFFSET          8164

 

BBED> dump

 File: /dras20/astca/test01.dbf (133)

 Block: 34               Offsets: 8164 to 8191           Dba:0x21400022

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

 11111111 11111111 2c010202 c1030164 2c010202 c1020161 d1b70602

 

 <32 bytes per line>

 

BBED> modify /x 2c010202c10401631111111111111111

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

 File: /dras20/astca/test01.dbf (133)

 Block: 34               Offsets: 8164 to 8191           Dba:0x21400022

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

 2c010202 c1040163 11111111 11111111 2c010202 c1020161 d1b70602

 

 <32 bytes per line>

 

BBED> sum apply

Check value for File 133, Block 34:

current = 0xd7bb, required = 0xd7bb

 

ODU> unload table dras.t2

 

Unloading table: T2,object ID: 86108

Unloading segment,storage(Obj#=86108 DataObj#=86108 TS#=84 File#=133 Block#=33 Cluster=0)

 

ODU> exit

$ cd data

 

$ ls

DRAS_T2.ctl             ODU_ODU_0000086133.ctl  ODU_ODU_0000086133.txt  ODU_ODU_0000086134.sql  sample.txt

DRAS_T2.sql             ODU_ODU_0000086133.log  ODU_ODU_0000086134.ctl  ODU_ODU_0000086134.txt

DRAS_T2.txt             ODU_ODU_0000086133.sql  ODU_ODU_0000086134.log  login.sql

 

$ cat DRAS_T2.txt

1a

3c

 

结论:当碰到fractured block的时候,先用BBED dump一下这个block,看看这个block损坏到什么程度了,然后再用熊哥ODU来最大限度的抢救数据。

No TrackBacks

TrackBack URL: http://dbsnake.com/cgi-bin/mt/mt-tb.cgi/69

4 Comments

感谢你又给我打了一把广告:)


06020000 21400022 a9e7d1b7 00080106
Tail应该是scnbase的后两个字节+block type+Seq number
怎么得到d1b7呢?这不是4个字节吗?
d1b70601
谢谢

d1b7是两个字节啊,兄弟。
d1=1101 0001
b7=1011 0111

Leave a comment

Recent Comments

  • cui hua: d1b7是两个字节啊,兄弟。 d1=1101 0001 b7=1011 0111 read more
  • fengxue: 06020000 21400022 a9e7d1b7 00080106 Tail应该是scnbase的后两个字节+block type+Seq number 怎么得到d1b7呢?这不是4个字节吗? d1b70601 read more
  • cui hua: 不用谢:) read more
  • 老熊: 感谢你又给我打了一把广告:) read more

About this Entry

This page contains a single entry by cui hua published on August 24, 2009 11:21 AM.

HHWM下为什么会出现未格式化的块 was the previous entry in this blog.

详细解析9i和10g的datafile header is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.