Environment:
Oracle 10.0.2.1.0
Linux kernal 2.6.18-92.el5PAE
ASSM Tablespace
Important: 9i and 10g's root dba are different
FILE HEADER:
status:0x4 root dba: 0x004001a1 chkpt cnt: 75 ctl cnt:74 --9i point to a cache block, cache block point to bootstrap$
FILE HEADER:
status:0x4 root dba: 0x00400179 chkpt cnt: 75 ctl cnt:74 --10g direct point to bootstrap$, this object is no more cached, that's the why database can't be started when SYSTEM tablespace corrupted
Introduction
Each Oracle database has a SYSTEM tablespace, and each SYSTEM tablespace has a Super Block which is file 1 block 1, the Super Block has it's struct KCVFH 676 bytes(10g)
struct kcvfh {
kcbh kcvfhbfh; -- Block Header, like every single block, 20bytes
kccfhg kcvfhhdr;
krdba kcvfhrdb; -- point ot bootstrap$ RDBA address, ONLY exist in FILE#1
kscn kcvfhcrs; -- SCN when datafile created
ub4 kcvfhcrt; --Timestamp when datafile created
………}
Bootstrap$ including those main system dictionary, such as OBJ$, and segment HDR address
What is Bootstrap: Bootstrap is a technique for loading the first few instructions of a computer program into active memory and then using them to bring in the rest of the program.
What is Bootstrap in Oracle: In Oracle, Bootstrap refers to loading of metadata (data dictionary) before we OPEN the database. Bootstrap objects are classified as the objects (tables / indexes / clusters) with the object_id below 56 as bootstrap objects. These objects are mandatory to bring up an instance, as this contains the most important metadata of the database.
After all, before analysis Oracle database structure, we need to use Super Block to find the position of Bootstrap$, through Bootstrap$ we can find those main system dictionaries, such as OBJ$, C_OBJ$, TAB$, COL$, etc…
Bootstrap$ is created by script $ORACLE_HOME/RMDBS/ADMIN/sql.bsq, the position of this script is defined by a Hidden Parameter _init_sql_file
SQL> @ GetHiddenParameter.sql
Enter value for par: init_sql_file
old 8: where x.inst_id = userenv('Instance') and y.inst_id = userenv('Instance') and x.indx = y.indx and x.ksppinm like '%_&par%'
new 8: where x.inst_id = userenv('Instance') and y.inst_id = userenv('Instance') and x.indx = y.indx and x.ksppinm like '%_init_sql_file%'
NAME VALUE ISDEFAULT ISMOD ISADJ
--------------------- ------------------------------------- ------------------ ------------------- -----------
_init_sql_file ?/rdbms/admin/sql.bsq TRUE FALSE FALSE
Before sql.bsq there is another script $ORACLE_HOME/RMDBS/ADMIN/CreateDB.sql which called to create Bootstrap$
Started to analysis 1) Super Block (set dba 1,1) -> kcvfhrdb -> Dump File# 1 Block# 377; 2) Trace Oracle database startup process
1) Super Block (set dba 1,1) -> kcvfhrdb -> Dump File# 1 Block# 377
BBED> set dba 1,1
DBA 0x00400001 (4194305 1,1)
BBED> map /v
File: /u01/app/oracle/oradata/orcl/system01.dbf (1)
Block: 1 Dba:0x00400001
------------------------------------------------------------
Data File Header
struct kcvfh, 676 bytes @0
struct kcvfhbfh, 20 bytes @0
struct kcvfhhdr, 76 bytes @20
ub4 kcvfhrdb @96
struct kcvfhcrs, 8 bytes @100
ub4 kcvfhcrt @108
ub4 kcvfhrlc @112
struct kcvfhrls, 8 bytes @116
ub4 kcvfhbti @124
struct kcvfhbsc, 8 bytes @128
ub2 kcvfhbth @136
ub2 kcvfhsta @138
struct kcvfhckp, 36 bytes @484
ub4 kcvfhcpc @140
ub4 kcvfhrts @144
ub4 kcvfhccc @148
struct kcvfhbcp, 36 bytes @152
ub4 kcvfhbhz @312
struct kcvfhxcd, 16 bytes @316
word kcvfhtsn @332
ub2 kcvfhtln @336
text kcvfhtnm[30] @338
ub4 kcvfhrfn @368
struct kcvfhrfs, 8 bytes @372
ub4 kcvfhrft @380
struct kcvfhafs, 8 bytes @384
ub4 kcvfhbbc @392
ub4 kcvfhncb @396
ub4 kcvfhmcb @400
ub4 kcvfhlcb @404
ub4 kcvfhbcs @408
ub2 kcvfhofb @412
ub2 kcvfhnfb @414
ub4 kcvfhprc @416
struct kcvfhprs, 8 bytes @420
struct kcvfhprfs, 8 bytes @428
ub4 kcvfhtrt @444
ub4 tailchk @8188
BBED> print kcvfhrdb
ub4 kcvfhrdb @96 0x00400179
SQL> select dbms_utility . DATA_BLOCK_ADDRESS_FILE ( to_number ( '400179' , 'xxxxxxxxxx' )) file# ,
dbms_utility . DATA_BLOCK_ADDRESS_BLOCK ( to_number ( '400179' , 'xxxxxxxxxx' )) block#
from dual;
FILE# BLOCK#
---------- ----------
1 377
SQL> select segment_name,file_id,block_id from dba_extents where block_id=377;
SEGMENT_NAME FILE_ID BLOCK_ID
--------------------------------------------------------------------------------- ---------- ----------
BOOTSTRAP$ 1 377
I_DIR$INSTANCE_JOB_NAME 3 377
SYS_C005392 4 377
PRODUCT_INFORMATION 5 377
SQL> alter system dump datafile 1 block 377;
System altered.
Start dump data blocks tsn: 0 file#: 1 minblk 377 maxblk 377
buffer tsn: 0 rdba: 0x00400179 (1/377)
scn: 0x0000.0000014e seq: 0x01 flg: 0x04 tail: 0x014e1001
frmt: 0x02 chkval: 0xe733 type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x0DCE4400 to 0x0DCE6400
<---- More ----> >
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 7
last map 0x00000000 #maps: 0 offset: 4128
Highwater:: 0x0040017d ext#: 0 blk#: 3 ext size: 7
#blocks in seg. hdr's freelists: 1
#blocks below: 3
mapblk 0x00000000 offset: 0
Unlocked
Map Header:: next 0x00000000 #extents: 1 obj#: 56 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x0040017a length: 7
nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 3
SEG LST:: flg: USED lhd: 0x0040017c ltl: 0x0040017c
End dump data blocks tsn: 0 file#: 1 minblk 377 maxblk 377
SQL> select name from sys.obj$ where obj#=56;
NAME
------------------------------
BOOTSTRAP$
SQL> desc sys.bootstrap$
Name Null? Type
--------------------------------------------------------
LINE# NOT NULL NUMBER
OBJ# NOT NULL NUMBER
SQL_TEXT NOT NULL VARCHAR2(4000)
SQL> select * from sys.bootstrap$;
LINE# OBJ# SQL_TEXT
---------- -------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-1 -1 8.0.0.0.0
0 0 CREATE ROLLBACK SEGMENT SYSTEM STORAGE ( INITIAL 112K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 32765 OBJNO 0 EXTENTS (FILE 1 BLOCK 9))
…………………
53 53 CREATE INDEX I_CDEF4 ON CDEF$(ENABLED) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 53 EXTENTS (FILE 1 BLOCK 353))
57 rows selected.
2) Trace Oracle database startup process & 10046 events
先通过 direct path read 从每个数据文件头读取第一个 Block 信息 , 然后通过 db file sequential read 的单块读方式分别读取了数据文件 1 的 417 和 377block, 417 上放着 1.417 号对象 , 从而找到bootstrap$ 对象 , 找到了 377, 并且在内存中建立了这个对象
shutdown immediate
startup mount ;
alter session set sql_trace = true ;
alter database open ;
alter database open
END OF STMT
PARSE #1:c=3000,e=2948,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=1245077587182259
tkcrrsarc: (WARN) Failed to find ARCH for message (message:0x1)
tkcrrpa: (WARN) Failed initial attempt to send ARCH message (message:0x1)
=====================
PARSING IN CURSOR #2 len=188 dep=1 uid=0 oct=1 lid=0 tim=1245077587762182 hv=1365064427 ad='4174f3ec'
create table bootstrap$ ( line# number not null,obj# number not null,
sql_text varchar2(4000) not null)
storage (initial 50K objno 56 extents (file 1 block 377))
=====================
PARSING IN CURSOR #2 len=55 dep=1 uid=0 oct=3 lid=0 tim=1245077587770912 hv=2111436465 ad='4174ec78'
select line#, sql_text from bootstrap$ where obj# != :1
END OF STMT
PARSE #2:c=4999,e=4673,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=1245077587770907
EXEC #2:c=7999,e=7697,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=1245077587778793
FETCH #2:c=6999,e=6763,p=4,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=1245077587785627
关于 bootstrap$ 定位由 System 表空间的文件头的 root dba 数据结构来定位的
FILE HEADER:
status:0x4 root dba:0x004001a1 chkpt cnt: 75 ctl cnt:74 --9i
FILE HEADER:
status:0x4 root dba: 0x00400179 chkpt cnt: 75 ctl cnt:74 --10g 直接指向了 bootstrap$ 从而取消了 Cache 这个唯一对象 , 这就是为什么 system 坏了就完了
select * from dba_segments where header_file = 1 and header_block = 417; --10g 已经查不到 type 是 cache 了
在数据库 bootstrap 过程中所有文件 1 的 417 以及之前所有对象都需要来 bootstrap
select b . object_id , a . segment_name , a . segment_type , a . header_block
from dba_segments a , dba_objects b
where a . segment_name = b . object_name (+) and a . header_file = 1 and a . header_block <= 417
order by a . header_block; --10g 已经没有 1.417 这个对象了
alter system dump datafile 1 block 417 ;
Start dump data blocks tsn: 0 file#: 1 minblk 417 maxblk 417
buffer tsn: 0 rdba: 0x004001a1 (1/417)
scn: 0x0000.0005f26d seq: 0x01 flg: 0x04 tail: 0xf26d1001
frmt: 0x02 chkval: 0x264f type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x0DBF2400 to 0x0DBF4400
AA84E40 00400179 [y.@.] -- 这个传说中 9i 中有的 10g 中没有了的这个 377 的指向
--EOF--