Environment:
Oracle 10.0.2.1.0
Linux kernal 2.6.18-92.el5PAE
ASSM Tablespace
Block type: 0x06=trans data
上边这幅图虽然是Concept上的但是实际上并不完整,但是还是有一定的参考价值所以就放上来了
首先复习下数据块的结构,一个0x06的block包含4个layer
---------------------
1- Cache Layer - kcbh 20byte 该层主要包含block format, type(index, table or cluster and so on)在block中使用kcbh struct来描述
---------------------
2- Transaction Layer - ktbbh 48byte(包含ktbbh,ktbit就是一个ITL的容器,单个ITL结构为ktbbhitl大小为24byte)
--------------------- ---------------------
3- Data Layer 包含 - - Data Header - kdbh
--------------------- ---------------------
- Table Directory - 包含:offset
---------------------
- Row Directory -
---------------------
- Free Space -
---------------------
- Row Data -
---------------------
---------------------
4- Tailchk -
---------------------
在BBED中查看Data Block的结构
node1-> bbed parfile=bbed.par
BBED> map
File: /u02/oradata/ETMCDB.dbf (6)
Block: 71 Dba:0x01800047
------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes @0 1 Cache Layer(kcbh) 20bytes: block format, type(index, table or cluster and so on)
struct ktbbh, 72 bytes @20 2 Transaction Layer(ktbbh+ ktbit) 72bytes: ITL(each ITL is 24byte),including 2 strcs (ktbbh 24bytes & ktbit 48bytes)
struct kdbh, 14 bytes @100 3 Data Header
struct kdbt[1], 4 bytes @114 4 Table Directory
sb2 kdbr[733] @118 5 Row Directory
ub1 freespace[1579] @1584 6 Free Space
ub1 rowdata[5025] @3163 7 Row Data
ub4 tailchk @8188 8 Tailchk
kc~kernel cache, kt~kernel transaction, kd~kernel data
BBED> map /v
File: /u02/oradata/ETMCDB.dbf (6)
Block: 71 Dba:0x01800047
------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes @0 1 Block Header Structure(kcbh) Cache Layer 20bytes: block format, type(index, table or cluster and so on)
ub1 type_kcbh @0
ub1 frmt_kcbh @1
ub1 spare1_kcbh @2
ub1 spare2_kcbh @3
ub4 rdba_kcbh @4
ub4 bas_kcbh @8
ub2 wrp_kcbh @12
ub1 seq_kcbh @14
ub1 flg_kcbh @15
ub2 chkval_kcbh @16
ub2 spare3_kcbh @18
struct ktbbh, 72 bytes @20 2 Transaction Layer 72bytes: 包含两个struct (ktbbh_ 24bytes & ktbit_ 48bytes(每个ITL占用24bytes)) 之所以是这两个struct是因为ktbbh里边的结构都是以这两个strct开头的
10201 struct ktbbh block header
ub1 ktbbhtyp @20 --block type
union ktbbhsid, 4 bytes @24
struct ktbbhcsc, 8 bytes @28 --effective time of last cleanout
b2 ktbbhict @36 --number of itl entries mask 0x00ff
ub1 ktbbhflg @38 --flags
ub1 ktbbhfsl @39 --free space lock
ub4 ktbbhfnx @40 --next block in free list
struct ktbbhitl[2], 48 bytes @44
struct kdbh, 14 bytes @100 3 Data Header
ub1 kdbhflag @100 --flags
b1 kdbhntab @101 --Number of TABles in the table index
b2 kdbhnrow @102 --Number of ROWs in the row index
sb2 kdbhfrre @104 --first FRee Row index Entry
sb2 kdbhfsbo @106 --Free Space Beginning Offset
sb2 kdbhfseo @108 --Free Space Ending Offset
b2 kdbhavsp @110 --AVailable SPace in the block
b2 kdbhtosp @112 --TOtal Space that will be available
struct kdbt[1], 4 bytes @114 4 Table Directory
b2 kdbtoffs @114 --OFFSet in the block from kdbpri
b2 kdbtnrow @116 --Number of Rows in the table
sb2 kdbr[15] @118 5 Row Directory
ub1 freespace[7064] @148 6 Free Space
ub1 rowdata[976] @7212 7 Row Data
ub4 tailchk @8188 8 Tailchk
使用BBED 方法查看Data Block 的内部信息
BBED> set dba 6,71
BBED> dump
使用Dump 方法查看Data Block 的逻辑信息
SQL> alter system dump datafile 6 block 71;
System altered.
Start dump data blocks tsn: 7 file#: 6 minblk 71 maxblk 71
1 Cache Layer
buffer tsn: 7 rdba: 0×01800047 (6/71)
scn: 0×0000.0032cd71 seq: 0×01 flg: 0×02 tail: 0xcd710601
frmt: 0×02 chkval: 0×0000 type: 0×06=trans data
Hex dump of block: st=0, typ_found=1
<—-more—->
Block header dump: 0×01800047
Object id on Block? Y
seg/obj: 0xda30 csc: 0×00.32cd5a itc: 2 flg: E typ: 1 – DATA
brn: 0 bdba: 0×1800041 ver: 0×01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0×01 0x000a.019.000005b4 0×00800226.0347.1a –U- 733 fsc 0×0000.0032cd71
0×02 0×0000.000.00000000 0×00000000.0000.00 —- 0 fsc 0×0000.00000000
data_block_dump,data header at 0xd071464
===============
tsiz: 0x1f98
hsiz: 0x5cc
pbl: 0x0d071464
bdba: 0×01800047
76543210
flag=——–
ntab=1 -- One table, if it’s a Cluster this num will be > 1;
nrow=733 –- Num of Rows in Table
frre=-1
fsbo=0x5cc –-free space start block: 44+NO_OF_ITLS*24+0x5cc)
fseo=0xbf7 –-free space end block: 44+NO_OF_ITLS*24+0x5cc)
?why the free space of current block is that much?0xbf7-0x5cc= 3063-1484 , therefore the PCTFREE is 0?
avsp=0×7
tosp=0×7
0xe:pti[0] nrow=733 offs=0
0×12:pri[0] offs=0x1f92 –- first row address 0x1f92 + (44+NO_OF_ITLS*24)
0×14:pri[1] offs=0x1f8c -- second row address 0x1f8c + (44+NO_OF_ITLS*24)
0×16:pri[2] offs=0x1f86
<—-more—->
0x5c8:pri[731] offs=0xbfe
0x5ca:pri[732] offs=0xbf7
block_row_dump:
tab 0, row 0, @0x1f92 –- first row
tl: 6 fb: –H-FL– lb: 0×1 cc: 1
col 0: [ 2] c1 02
tab 0, row 1, @0x1f8c -- second row
tl: 6 fb: –H-FL– lb: 0×1 cc: 1
col 0: [ 2] c1 03
tab 0, row 2, @0x1f86
tl: 6 fb: –H-FL– lb: 0×1 cc: 1
<—-more—->
tl: 7 fb: –H-FL– lb: 0×1 cc: 1
col 0: [ 3] c2 08 21
tab 0, row 732, @0xbf7
tl: 7 fb: –H-FL– lb: 0×1 cc: 1
col 0: [ 3] c2 08 22
end_of_block_dump
End dump data blocks tsn: 7 file#: 6 minblk 71 maxblk 71
在随后的内容里将会一一对比这4个layer在BBED和Dump中的结果,进而更深一步的了解Data Block
---------------------------------1 Block Header / Cache Layer [struct kcbh]-----------------------------------
Let’s have a look on the first section [struct kcbh] which is 20 bytes:
typedef struct kcbh_ {
ub1 type_kcbh;
ub1 frmt_kcbh;
ub1 spare1_kcbh;
ub1 spare2_kcbh;
krdba rdba_kcbh;
ub4 bas_kcbh; /* base of SCN */
ub2 wrp_kcbh; /* wrap of SCN */
ub1 seq_kcbh; /* seq# of changes at same scn, KCBH_NLCSEQ */
ub1 flg_kcbh; /* see KCBHFNEW etc below */
ub2 chkval_kcbh;
ub2 spare3_kcbh;
} kcbh;
使用print 来更清晰地看出每个字节对应的意义:
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 0x004000aa
ub4 bas_kcbh @8 0x001bf37e //base scn
ub2 wrp_kcbh @12 0x0000
ub1 seq_kcbh @14 0x01
ub1 flg_kcbh @15 0x06 (KCBHFDLC, KCBHFCKV)
ub2 chkval_kcbh @16 0xb42a
ub2 spare3_kcbh @18 0x0000
File: /u02/oradata/ETMCDB.dbf (6)
Block: 71 Offsets: 0 to 511 Dba:0x01800047
------------------------------------------------------------------------
0ba20000 47008001 a3d23200 00000100 00000000 01000000 30da0000 a1d03200
00000000 02003200 41008001 0a001900 b4050000 26028000 47031a00 00800000
71cd3200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 0001dd02 ffffcc05 f70b0700 07000000 dd02921f 8c1f861f 801f7a1f
……………
<32 bytes per line>
0 byte is type:06 means data block
1 byte is FRMT:commonly it’s 0X02
4-7 byte is RDBA:47 00 80 01 = 0X01800047(6/71) ①
8-13 byte is SCN(First 4 byte is BASE the 2 byte left is WRAP):a3 d2 32 00 00 00 : 0×0000.0032cd71
14 byte is SEQ:01 , SEQ=0x01
15 byte is FLAG: 02, FLAG=0x02 BBED结果是0
16-17 byte is CHECKSUM:00 00 :0x0000 -- when db_block_checksum = FALSE, CheckSum=00 00
① select dbms_utility.DATA_BLOCK_ADDRESS_FILE(to_number('01800047','xxxxxxxxxx')) file#,
dbms_utility.DATA_BLOCK_ADDRESS_BLOCK(to_number('01800047','xxxxxxxxxx')) block# from dual;
FILE# BLOCK#
---------- ----------
6 71
---------------------------------2 Transaction Layer [struct ktbbh]---------------------------------------
记录数据块身份信息包含:ITL事务表,这个是行锁和读一致性的基础,记录本数据块中参与到某个事物的一条记录包括UBA,Transaction ID,SCN. oracle对每一次用户查询都要记录查询开始时当前的SCN并和数据块中的SCN对比,如果当前SCN>数据块中的SCN说明这个数据块被修改过,Oracle就会利用UNDO内容制造一个新版本的数据块叫CR数据块(Constant Block)它是利用ITL中的记录UBA信息完成的,CR构造完再继续对比SCN直到数据块的SCN<=查询SCN这个构造才结束,如果无法获得符合要求的CR块就会抛出ORA-0155
分成两部分:
第一部分为固定长度从20字节开始是24字节长度的ktbbh,包含事务相关的一些基本信息
typedef struct ktbbh_ { /* 10201 struct ktbbh block header */
ub1 ktbbhtyp; /* block type */
ub4 ktbbhsid;
kscn ktbbhcsc; /* effective time of last cleanout */
b2 ktbbhict; /* number of itl entries mask 0x00ff*/
ub1 ktbbhflg; /* flags */
ub1 ktbbhfsl; /* free space lock */
krdba ktbbhfnx; /* next block in free list */
}
使用print 来更清晰地看出每个字节对应的意义:
BBED> p ktbbh
File: /u02/oradata/ETMCDB.dbf (6)
Block: 71 Offsets: 0 to 511 Dba:0x01800047
------------------------------------------------------------------------
0ba20000 47008001 a3d23200 00000100 00000000 01000000 30da0000 a1d03200
00000000 02003200 41008001 0a001900 b4050000 26028000 47031a00 00800000
71cd3200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 0001dd02 ffffcc05 f70b0700 07000000 dd02921f 8c1f861f 801f7a1f
……………
<32 bytes per line>
seg/obj: 0xda30 csc: 0x00.32d0a1 itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x1800041 ver: 0x01 opc: 0
inc: 0 exflg: 0
20 byte:01 :typ=01
24-27 byte is OBJECT ID: 30 da 00 00 :0xda30(注意,这里有UB4的字节对齐问题,所以中间空了3个字节) a3 d2 32 00 00 00 : 0×0000.0032cd71
28-35 byte is SCN: a1 d0 32 00 00 00,SCN:
36-37 byte is Num of ITL:用0x00ff掩码:02 00 :有2个ITL槽
38 byte is FLAG: 32
39 byte is FSL:00
40-43 KDBA is the address of the next free block:41 00 80 01, 0x1800041
第二部分为可变长度从44开始是ITL表,每个ITL记录的长度为24,从1可以看到这个块有2个ITL槽,因此ITL占48字节,ITL内部结构名ktbbhitl.这里共占用了48bytes 的空间
struct ktbit {
kxid ktbitxid; /* transaction id */
kuba ktbituba; /* undo address for last change */
b2 ktbitflg; /* num of locks in block */
ktbitun_t _ktbitun;
ub4 ktbitbas; /* sys commit num base */
}
File: /u02/oradata/ETMCDB.dbf (6)
Block: 71 Offsets: 0 to 511 Dba:0x01800047
------------------------------------------------------------------------
0ba20000 47008001 a3d23200 00000100 00000000 01000000 30da0000 a1d03200
00000000 02003200 41008001 0a001900 b4050000 26028000 47031a00 00800000
71cd3200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 0001dd02 ffffcc05 f70b0700 07000000 dd02921f 8c1f861f 801f7a1f
……………
<32 bytes per line>
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000a.019.000005b4 0x00800226.0347.1a C--- 0 scn 0x0000.0032cd71
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
KXID: UB2 :UNDO SEGMENT NUMBER
UB2 :SLOT NUMBER
UB4 :WRAP
44-51 byte is XID(8):0a 00 19 00 b4 05 00 00 :0x0a00.1900.b4050000
52-59 byte is UBA(8):26 02 80 00 47 03 1a 00 :0x00800226.0347.1a 那么最后这个00哪?
60-61 byte is FLAG(2):00 80,0X0800, c--- LOCK 0
62-67 byte is SCN(6): 00 00 71 cd 32 00,0x0000.71cd3200
原文中 62-67(6):scn:00 00 6D 48 25 00 ,0x00254864.00这里是如何换算的
data_block_dump,data header at 0xd071464
===============
tsiz: 0x1f98 total data area size 除了上面的部分和block尾部的个字节剩下的空间0x1fb8就是字节
hsiz: 0x5cc data header size 数据块头个字节+数据块尾个字节=24字节(0x14)
pbl: 0x0d071464 point to buffer holding the block
bdba: 0×01800047 rdba,与 Header 中的 rdba 相同
76543210
--------------3 Data Layer包括Data Header,Table Directory,Row Directory,Free Space和Row Data ---------
包含5部分
3.1 Data Header:长度14字节,内部数据结构名kdbh
这个块有2个ITL槽,今后计算所有的位置都要根据这个来计算。下面一个重要的结构就是KDBH
struct kdbh {
ub1 kdbhflag; /* FLAGs */
ktno kdbhntab; /* Number of TABles in the table index */
ub2 kdbhnrow; /* Number of ROWs in the row index */
sb2 kdbhfrre; /* first FRee Row index Entry */
sb2 kdbhfsbo; /* Free Space Beginning Offset */
sb2 kdbhfseo; /* Free Space Ending Offset */
b2 kdbhavsp; /* AVailable SPace in the block */
b2 kdbhtosp; /* TOtal Space that will be available */
}
使用print 来更清晰地看出每个字节对应的意义:
BBED> p kdbh
struct kdbh, 14 bytes @124
ub1 kdbhflag @124 0x00 (NONE)
b1 kdbhntab @125 1
b2 kdbhnrow @126 733 <--有733行数据
sb2 kdbhfrre @128 -1
sb2 kdbhfsbo @130 1484
sb2 kdbhfseo @132 2943
b2 kdbhavsp @134 7
b2 kdbhtosp @136 7
File: /u02/oradata/ETMCDB.dbf (6)
Block: 71 Offsets: 0 to 511 Dba:0x01800047
------------------------------------------------------------------------
0ba20000 47008001 a3d23200 00000100 00000000 01000000 30da0000 a1d03200
00000000 02003200 41008001 0a001900 b4050000 26028000 47031a00 00800000
71cd3200 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 0001dd02 ffffcc05 f70b0700 07000000 dd02921f 8c1f861f 801f7a1f
……………
<32 bytes per line>
flag=——– N=pctfree hit(clusters), F=don't put on free list K=flushable cluster keys. 当然还有别的标记: A ...
ntab=1 1 byte 表示这个block中有几个table的数据 cluster这个就可能大于1
nrow=733 2 bytes block 中有多少行数据
frre=-1 2 bytes First free row index entry. -1=you have to add one.
fsbo=0x5cc 2 bytes Free Space Begin offset 空闲空间从哪里开始
fseo=0xbf7 ?why the free space of current block is that much?0xbf7-0x5cc= 3063-1484 , therefore the PCTFREE is 0? 2 bytes Free Space End offset 空闲空间到哪里结束
avsp=0×7 2 bytes Available space in the block
tosp=0×7 2 bytes Total available space when all TXs commit 所有事物都提交后,可使用的空间
0xe:pti[0] nrow=733 offs=0
0×12:pri[0] offs=0x1f92
100 byte is: FLAG 0(--------------)
101 byte is: NTAB 1
102-103 byte is: NROW dd 02, 0x2dd (nrow=733) select to_number('2dd','xxxxxxxx') from dual; = 733
104-105 byte is: free ff ff, (free space=-1)
106-107 byte is: fsbo cc 05, 0x5cc = 1484
108-109 byte is: fseo f7 0b, 0xb7f = 2943
110-111 byte is: avsp 07 00, 0x007 = 7
112-113 byte is: tosp 07 00, 0x007 = 7
KDBH的位置的计算方法如下:
对于ASSM:76+(itls-1)*24
对于MSSM:68+(itls-1)*24
本例是使用ASSM的,并且有2个ITL槽,因此是76+24=100
offset 可使用 p kdbr[n] 获得
itl 可通过p ktbbh.ktbbhitc 获得
3.2 Table Directory: 一般table只有一个条目,cluster则有一个或多个条目。每个条目长4字节,内部数据结构名kdbt。
struct kdbt {
b2 kdbtoffs; /* OFFSet in the block from kdbpri */
b2 kdbtnrow; /* Number of Rows in the table */
}
BBED> p kdbt
struct kdbt[0], 4 bytes @138
b2 kdbtoffs @138 0
b2 kdbtnrow @140 733
114-115: 00 00:0x0000
116-117: dd 02, 0x2dd (这个块有733行数据)
下面紧接着是KDBR结构,KDBR结构是一个数组,是sb2类型的,指向每一行的头,这里只有1行,指向0x1f92,
3.3 Row Directory:数目由块中数据的行数决定,每个条目长2字节,内部数据结构名kdbr
BBED> p kdbr 从这里,我们可以观察到这个块一共有733行数据,每一行指针需要2个bytes,说明row# 为1 的行的offset的十进制值为7856他们从偏移量142开始到1606存储在这个数据块中
sb2 kdbr[0] @142 8082
sb2 kdbr[1] @144 8076
..................
sb2 kdbr[731] @1604 1240
sb2 kdbr[732] @1606 1035
BBED> p kdbr[0]
sb2 kdbr[0] @142 8082
BBED> p *kdbr[0]
rowdata[529]
------------
ub1 rowdata[529] @8182 0x2c
我们从以上的个结果可以看出第0行的offset在8082,对于ASSM需要+76+24就得到了8182,对照一下dump结果0x1f92这个值也是8082,就一致了。select to_number('1f92','xxxxxxxx') from dual;
block_row_dump:
tab 0, row 0, @0x1f92
tl: 6 fb: –H-FL– lb: 0×1 cc: 1
col 0: [ 2] c1 02
<----more---->
end_of_block_dump
End dump data blocks tsn: 7 file#: 6 minblk 71 maxblk 71
2c 00 01 02 c1 02 01 06 a3 d2
2c是记录头的flag
00:ITL曹的索引(锁所在的)
01:这个记录有1个字段
后面是第一个字段的数据 02 c1 02
02表示字段长度,后面c1 02就是字符串' '
最后四个字节是
01: SEQ
06: TYPE
最后两个字节是 scn base的低4个字节:0xd2a3 这个块的SCN是:0x????d2a3
注意的是:这个例子是最简单的,如果有字段的长度超过253字节,那么8位是表示不了的,这个时候,会使用前导字符FE
比如FE 03 06表示该字段的长度是0x603,就是1539字节
要注意的是在数据块里面是没有字段类型的,因此如果SYSTEM表空间损坏,需要导出数据,就必须了解表的结构,否则需要根据扫描的结果进行猜测
3.4 Free Space:表示数据块中可用空间,内部数据结构名freespace
BBED> p freespace[4]
ub1 freespace[4] @1588 0x00
所有的freespace'n' 的值都是0x00
3.5 Row Data:表示实际的数据,内部数据结构名rowdata
BBED> p rowdata[5019]
ub1 rowdata[5019] @8182 0x2c
表示放置第5019个数据的字节的位置为8182,值为0x2c
4 Tailchk: 保存在块结尾用于校验的数据,长度4个字节,内部结构名tailchk。
BBED>p tailchk
ub4 tailchk @8188 0xd37a0602
注意到tailchk=bas_kcbh低2字节(d37a)+type_kcbh(06)+seq_kcbh(02)
tailchk 的值为last 2 bytes of base scn +type+ seq
--EOF--