使用BBED帮助理解Oracle数据块结构
BBED是Oracle提供的块编辑器,借助BBED,可以帮助我们更好的理解Oracle的Block的结构。当然,反过来说,也只有更加理解块的结构,才能更好的利用BBED完成某些特殊情况下的灾难恢复。
Oracle Data Block的结构简图如下,其中从Data header到Row Data部分合称Data Layer:
--------------------- - Cache Layer - --------------------- - Transaction Layer - --------------------- - Data Header - --------------------- - Table Directory - --------------------- - Row Directory - --------------------- - Free Space - --------------------- - Row Data - --------------------- - Tailchk - ---------------------
通过bbed的map命令,可以看到数据块内部的一些数据结构名:
BBED> map File: /u01/oracle/oradata/dbmon/system.dbf (1) Block: 31729 Dba:0x00407bf1 ------------------------------------------------------------ KTB Data Block (Table/Cluster) struct kcbh, 20 bytes @0 struct ktbbh, 72 bytes @20 struct kdbh, 14 bytes @92 struct kdbt[1], 4 bytes @106 sb2 kdbr[336] @110 ub1 freespace[821] @782 ub1 rowdata[6585] @1603 ub4 tailchk @8188
Cache Layer:Block的第一部分,长度为20字节,内部数据结构名为kcbh,包括
type_kcbh:块类型(table/index,rollback segment,temporary segment等)
frmt_kcbh:块格式(v6,v7,v8)
rdba_kcbh:块地址DBA
bas_kcbh/wrp_kcbh:SCN
seq_kcbh:块的序列号
flg_kcbh:块的标志
BBED> p kcbh struct kcbh, 20 bytes @0 ub1 type_kcbh @0 0x06 ub1 frmt_kcbh @1 0xa2 ub1 spare1_kcbh @2 0x00 ub1 spare2_kcbh @3 0x00 ub4 rdba_kcbh @4 0x00407bf1 ub4 bas_kcbh @8 0xd6449de8 ub2 wrp_kcbh @12 0x0595 ub1 seq_kcbh @14 0x03 ub1 flg_kcbh @15 0x04 (KCBHFCKV) ub2 chkval_kcbh @16 0x9130 ub2 spare3_kcbh @18 0x0000
Transaction Layer:内部结构名kcbbh。分成两部分,第一部分为固定长度,长度为24字节,包含事务相关的一些基本信息。第二部分为可变长度,包含itl,长度根据itl条目的个数变化,每个itl长度为24字节,内部结构名ktbbhitl。
BBED> p ktbbh
struct ktbbh, 72 bytes @20
ub1 ktbbhtyp @20 0x01 (KDDBTDATA)
union ktbbhsid, 4 bytes @24
ub4 ktbbhsg1 @24 0x000050fc
ub4 ktbbhod1 @24 0x000050fc
struct ktbbhcsc, 8 bytes @28
ub4 kscnbas @28 0xd6449de7
ub2 kscnwrp @32 0x0595
b2 ktbbhict @36 2
ub1 ktbbhflg @38 0x02 (NONE)
ub1 ktbbhfsl @39 0x00
ub4 ktbbhfnx @40 0x00000000
struct ktbbhitl[0], 24 bytes @44
struct ktbitxid, 8 bytes @44
ub2 kxidusn @44 0x0008
ub2 kxidslt @46 0x000c
ub4 kxidsqn @48 0x0000e991
struct ktbituba, 8 bytes @52
ub4 kubadba @52 0x0080222e
ub2 kubaseq @56 0x03a4
ub1 kubarec @58 0x22
ub2 ktbitflg @60 0x8000 (KTBFCOM)
union _ktbitun, 2 bytes @62
b2 _ktbitfsc @62 1429
ub2 _ktbitwrp @62 0x0595
ub4 ktbitbas @64 0xd6449de6
struct ktbbhitl[1], 24 bytes @68
struct ktbitxid, 8 bytes @68
ub2 kxidusn @68 0x0008
ub2 kxidslt @70 0x0015
ub4 kxidsqn @72 0x0000e992
struct ktbituba, 8 bytes @76
ub4 kubadba @76 0x0080222e
ub2 kubaseq @80 0x03a4
ub1 kubarec @82 0x23
ub2 ktbitflg @84 0x0001 (NONE)
union _ktbitun, 2 bytes @86
b2 _ktbitfsc @86 0
ub2 _ktbitwrp @86 0x0000
ub4 ktbitbas @88 0x00000000
Data Layer:包括Data Header,Table Directory,Row Directory,Free Space和Row Data。其中
Data Header:长度14字节,内部数据结构名kdbh
BBED> p kdbh struct kdbh, 14 bytes @92 ub1 kdbhflag @92 0x00 (NONE) b1 kdbhntab @93 1 b2 kdbhnrow @94 336 sb2 kdbhfrre @96 -1 sb2 kdbhfsbo @98 690 sb2 kdbhfseo @100 1511 b2 kdbhavsp @102 821 b2 kdbhtosp @104 821
Table Directory: 一般table只有一个条目,cluster则有一个或多个条目。每个条目长4字节,内部数据结构名kdbt。
BBED> p kdbt struct kdbt[0], 4 bytes @106 b2 kdbtoffs @106 0 b2 kdbtnrow @108 336
Row Directory:数目由块中数据的行数决定,每个条目长2字节,内部数据结构名kdbr
BBED> p kdbr sb2 kdbr[0] @110 7998 sb2 kdbr[1] @112 8017 ... sb2 kdbr[335] @780 1511
Free Space:表示数据块中可用空间,内部数据结构名freespace
Row Data:表示实际的数据,内部数据结构名rowdata
Tailchk:保存在块结尾用于校验的数据,长度4个字节,内部结构名tailchk。
BBED>p tailchk ub4 tailchk @8188 0x9de80603
注意到tailchk=bas_kcbh低2字节(9de8)+type_kcbh(06)+seq_kcbh(03)
安装使用BBED
在一次故障处理中,使用到了BBED(Oracle Block Brower and EDitor Tool),这是Oracle一款内部工具,可以直接修改Oracle数据文件块的内容,在一些极端恢复场景下比较有用。该工具不受Oracle支持,所以默认是没有生成可执行文件的,在使用前需要重新连接。
在9i/10g中连接生成bbed:
cd $ORACLE_HOME/rdbms/lib make -f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed
以上生成的bbed可执行文件在$ORACLE_HOME/rdbms/lib目录,可以复制到其他位置或者其他同Oracle版本的机器上运行。也可通过以下命令将bbed生成到$ORACLE_HOME/bin目录
make -f ins_rdbms.mk BBED=$ORACLE_HOME/bin/bbed $ORACLE_HOME/bin/bbed
在11g中生成bbed,需要先从10g中复制如下文件到相应目录,然后再执行上述连接命令:
$ORACLE_HOME/rdbms/lib/ssbbded.o $ORACLE_HOME/rdbms/lib/sbbdpt.o $ORACLE_HOME/rdbms/mesg/bbedus.msb
BBED设置了口令保护,密码为blockedit。BBED的命令行参数:
$bbed help=yes PASSWORD - Required parameter FILENAME - Database file name BLOCKSIZE - Database block size LISTFILE - List file name MODE - [browse/edit] SPOOL - Spool to logfile [no/yes] CMDFILE - BBED command file name LOGFILE - BBED log file name PARFILE - Parameter file name BIFILE - BBED before-image file name REVERT - Rollback changes from BIFILE [no/yes] SILENT - Hide banner [no/yes] HELP - Show all valid parameters [no/yes]
一般将一些常用选项写入到一个parfile中:
blocksize=8192 listfile=filelist.txt mode=edit
其中filelist.txt列出了需要使用BBED编辑的数据文件列表,格式为
文件编号 文件名字 文件大小 1 /u01/oracle/oradata/NinGoo/system.dbf 2097160192 2 /u01/oracle/oradata/NinGoo/test.dbf 2097160192
这里的文件编号不一定要和数据库里的file_id相同,当然最好能设置相同,以免在处理过程中搞混淆了。
$bbed parfile=bbed.par Password: BBED: Release 2.0.0.0.0 - Limited Production on Sun Nov 15 00:26:14 2009 Copyright (c) 1982, 2007, Oracle. All rights reserved. ************* !!! For Oracle Internal Use only !!! *************** BBED> help HELP [| ALL ] BBED> help all SET DBA [ dba | file#, block# ] SET FILENAME 'filename' SET FILE file# SET BLOCK [+/-]block# SET OFFSET [ [+/-]byte offset | symbol | *symbol ] SET BLOCKSIZE bytes SET LIST[FILE] 'filename' SET WIDTH character_count SET COUNT bytes_to_display SET IBASE [ HEX | OCT | DEC ] SET OBASE [ HEX | OCT | DEC ] SET MODE [ BROWSE | EDIT ] SET SPOOL [ Y | N ] SHOW [ | ALL ] INFO MAP[/v] [ DBA | FILENAME | FILE | BLOCK ] DUMP[/v] [ DBA | FILENAME | FILE | BLOCK | OFFSET | COUNT ] PRINT[/x|d|u|o|c] [ DBA | FILE | FILENAME | BLOCK | OFFSET | symbol | *symbol ] EXAMINE[/Nuf] [ DBA | FILE | FILENAME | BLOCK | OFFSET | symbol | *symbol ] : N - a number which specifies a repeat count. u - a letter which specifies a unit size: b - b1, ub1 (byte) h - b2, ub2 (half-word) w - b4, ub4(word) r - Oracle table/index row f - a letter which specifies a display format: x - hexadecimal d - decimal u - unsigned decimal o - octal c - character (native) n - Oracle number t - Oracle date i - Oracle rowid FIND[/x|d|u|o|c] numeric/character string [ TOP | CURR ] COPY [ DBA | FILE | FILENAME | BLOCK ] TO [ DBA | FILE | FILENAME | BLOCK ] MODIFY[/x|d|u|o|c] numeric/character string [ DBA | FILE | FILENAME | BLOCK | OFFSET | symbol | *symbol ] ASSIGN[/x|d|u|o] = : [ DBA | FILE | FILENAME | BLOCK | OFFSET | symbol | *symbol ] : [ value | ] SUM [ DBA | FILE | FILENAME | BLOCK ] [ APPLY ] PUSH [ DBA | FILE | FILENAME | BLOCK | OFFSET ] POP [ALL] REVERT [ DBA | FILE | FILENAME | BLOCK ] UNDO HELP [ | ALL ] VERIFY [ DBA | FILE | FILENAME | BLOCK ] CORRUPT [ DBA | FILE | FILENAME | BLOCK ]
关于bbed的具体用法,这里就不罗嗦了,有兴趣的可以自行学习,下面这篇参考文档非常的详尽:
http://orafaq.com/papers/dissassembling_the_data_block.pdf
记一次redo损坏导致ora-600[4000]的恢复
据说今天是光棍节,逢年过节,必有大事。快下班的时候,一位朋友碰到了一个大问题,数据库服务器异常断电重启以后,数据库无法启动,报ora-600[4000]错误,尝试了使用隐藏参数,还是无法打开。
ORA-00704: bootstrap process failure ORA-00704: bootstrap process failure ORA-00600: internal error code, arguments: [4000], [46], [], [], [], [], [], []
从ora-600内部错误的类型可以看到,4000是trasaction undo相关的内部错误。搜索一下可以发现,logzgh同学已经两次碰到过该问题了(第一次,第二次)。看来在异常宕机的情况下,这个问题出现的机率还是比较高的。既然是有先例的,恢复起来应该是没有问题的,这个案例和logzgh的第一个案例基本一样,trace文件里显示也是obj$上有异常事务:
ORA-00600: internal error code, arguments: [4000], [46], [], [], [], [], [], [] Current SQL statement for this session: select ctime, mtime, stime from obj$ where obj# = :1
将trace文件往下翻,可以看到出现问题的block的dump信息,在block的itl中果然有一条活动事务存在。用bbed找到对应块,设置offset到61,将itl的flag从20改为80,重新计算block的checksum并apply。然后尝试重新启动数据库,这次ora-600[4000]错误没有了,报的是ora-600[2662]错误,数据库无法open。2662就比较容易了,网上相关的处理案例已经一大堆了,将数据库启动到mount状态,设置10015事件来调整scn即可
alter session set events '10015 trace name adjust_scn level 1';
如果数据库已经处于open状态,则可以使用如下语句来调整SCN:
alter session set events 'IMMEDIATE trace name ADJUST_SCN level x';
再次重新打开库,报ora-600[2256],继续使用10015事件,这次level设置为(ora-600错误的第三个参数+1)*4
alter session set event '10015 trace name adjust_scn level 20';
重启,报ora-600[4097]错误,好了,现在基本上恢复已经接近尾声了,使用下面几个隐藏参数,可以正常将数据库打开了。接下来就是告诉朋友做全库export/重建库/import了。
_allow_resetlogs_corruption=true _allow_terminal_recovery_corruption=true _corrupted_rollback_segments=(_SYSSMU1$, _SYSSMU2$, _SYSSMU3$, _SYSSMU4$, _SYSSMU5$, _SYSSMU6$, _SYSSMU7$, _SYSSMU8$, _SYSSMU9$, _SYSSMU10$)
年关将近,事故高发时期,阿弥陀佛,多求个平安吧。话说这个案例还没来得及些写呢,晚上回家的路上又接到说有人truncate了一张表。。。