首页 > 数据库DBA > oracle知识 > oracle存储 >

ASM的文件管理深入解析(内含开源的ASM文件挖掘研究版程序)

作者: 初见博客 分类: oracle存储 发布时间: 2021-06-17 16:26

09年刚到阿里时,研究过一阵子ASM,当时还写了一个ASM文件直接读取的程序,就是本文后面所附的。算起来,这应该是国内首款这方面的程序了。但当时只发在公司内部的邮件组,一直没有时间整理出来。现在终于清闲些了,而且ASM也使用的越来越多,而且以后绝对是Oracle重点发展方向之一,所以决定将此程序整理出来,再配合些详细的介绍,希望可以提升大家对ASM的了解程度。
也是09年初,曾经和朋友一起写过一个Oracle日志解析的程序,取名为日志挖掘研究版( http://www.itpub.net/thread-1160446-1-1.html,算下来,都已经三年了,时间过的好快啊)。这个ASM直接读取程序,我也决定命令为“ASM文件挖掘研究版”,它还并不完善,只是给有需要的人提供一个思路。如果你不懂编号也没关系,本文的重点,除这个程序外,更多的是介绍ASM文件管理的原理。
“ASM文件挖掘研究版”远没有原来的“日志挖掘研究版复杂,也只花了很短时间,去掉一些调试性的注释只有不到300行代码。
好了,闲言少叙,准备好了吗,开始我们的ASM探秘之旅吧。

第一章  ASM文件

ASM中的文件总体上来说,分为两大类,元文件和数据文件。数据文件包含Oracle的数据文件、控制文件、重做日志文件、归档日志文件等等。对于ASM来说,只要是非元文件,就是数据文件。
每一个文件,在ASM中都有一个专门的索引号,也就是编号,ASM文件索引号从1开始。其中,前255个,也就是1至255号文件,都是元文件。256之后的是其他各种文件。
元文件中包含了各种ASM的配置、各类数据文件信息还有目录、别名等等信息,都是在元文件中的。所有V$ASM_开头视图的信息,都来自元文件中。
其中,1号文件包含所有文件的磁盘占用信息,包括元文件、甚至1号文件自身的空间分布信息,也都是在1号文件内部。每个文件在它里面占用一个块(4096字节,元数据块大小为4K)的空间。
从256号文件开始,是数据库的各类文件。假设你放在ASM上的第一个文件是一个控制文件A,第二个文件是一个数据文件B。哪么控制文件A在ASM中的索引号是256,数据文件B的索引号是257。
1号文件总是开始在0号磁盘2号AU,记住这个位置:0号盘2号AU。这是ASM中定位文件的起点,它的作用,有点相当于磁盘上的引导区,在电脑开机后负责将OS启动起来。
1号文件在最少情况下,至少有两个AU。上面我们提到过了,在1号文件中,每个文件占用一个元数据块,存放自身的空间分布信息。每个元数据块大小是4K,一个AU是1M,哪么,每个AU中,可以存储256个文件的空间分布信息。这其中,0号盘2号AU中,全是元文件的信息。再具体一点,0号盘2号AU,第一个元数据块被系统占用,从第二个块开始,到255为止,共255个元数据块,对应索引号1至255的文件。其实,也就是全部的元文件了。也就是说0号盘2号AU,保存了全部元文件的空间分布信息。
1号文件的第二个AU,从第一个块开始,保存256号文件。第二个块对应257号文件,等等。
每次从ASM中读数据时,Oracle都要先读到1号文件,从中找出要读的目标文件在磁盘上的分布位置,然后再去读取相应的文件的数据。
不用太多文字了,文字不是最直接的表达方式,还是换成图形吧。
092153yh3juuw7aga4gu4y
图1
这张图假设某一DiskGroup中有0到N个磁盘。再看下图:
092156vbxbcxgxgkyvycv5
图2
我们把0号盘,2号AU单独拿出来,放大显示。0号盘2号AU,是1号文件第一个AU,共有256个元数据块,编号0至255,0号块留用。1至255号块分别保存了1号文件自身和2、3等等直到255号文件的AU分布信息。
哪下面,如果我想知道某一个文件的AU分布,如何查看呢?

第 二 章   kfed

1、链接kfed
查看ASM磁盘的信息,可以使用KFED,在非Windows操作系统下,kfed已经编译过了,只要链接一下,就可以使用了,步骤如下:
(1)、找到ins_rdbms.mk所在路径,并进入。此步骤不再列出。
(2)、执行如下命令,即可链接kfed。
make -f ins_rdbms.mk ikfed
2、在ASM中确定磁盘 :
SQL> select group_number,name from v$asm_diskgroup;
GROUP_NUMBER NAME
———— ——————————
1 DG1
我目前只有一个DG,名字是DG1,GROUP_NUMBER为1。
SQL> select group_number,disk_number,path from v$asm_disk;
GROUP_NUMBER DISK_NUMBER PATH
———— ———– ——————–
1           0 ORCL:VOL1
1           1 ORCL:VOL2
目前,我DG中,有两个磁盘。但这两个磁盘分别是谁,从ASM的视图中,还看不出来。不过,可以分析一下得出,/dev/sda这个盘,是系统留用的,sdb、sdc很有可能是ASM的VOL1、VOL2。那么,如何确认一下呢?这里,我也没有什么好方法,我们这样:
[root@red1 dev]# dd if=/dev/sdb bs=1 count=45|hexdump -c|more
45+0 records in
45+0 records out
0000000 001 202 001 001  \0  \0  \0  \0  \0  \0  \0 200   ,   ,       m
0000010  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020   O   R   C   L   D   I   S   K   V   O   L   1  \0
000002d
我dd命令,将/dev/sdb的前45个字节输出,其中,我们可以看到O   R   C   L   D   I   S   K   V   O   L   1。那么,/dev/sdb就对应VOL1了。
使用同样的方法,可以确定sdc是VOL2。还可以确定,磁盘没有分区:
[root@red1 dev]# dd if=/dev/sdb1 bs=1 count=45|hexdump -c
dd: opening `/dev/sdb1′: No such file or directory
不存在/dev/sdb1这样的设备。
这种确定方法确实麻烦了一些,大家如果知道有什么简单方法可以补充。
好,我们已经确定,/dev/sdb对应VOL1,是磁盘0,/dev/sdc对应VOL2,是磁盘1。在我们使用kfed时,还用不到这个,如果用程序直接读取ASM文件的话,就需要用到这个信息了。
3、使用Kfed
我们使用Kfed直接读取0号磁盘,2号AU,1号元数据块吧。
0号元数据块是1号文件自身留作文件头的。1号元数据块呢,是1号文件的AU分布,2号元数据块,是2号文件的AU分布。等等。下面,我们用Kfed读取下1号元数据块。
[oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=2 blkn=1|more
kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt:                          1 ; 0x003: 0x01
kfbh.block.blk:                       1 ; 0x004: T=0 NUMB=0x1
kfbh.block.obj:                       1 ; 0x008: TYPE=0x0 NUMB=0x1
kfbh.check:                  4143342569 ; 0x00c: 0xf6f663e9
kfbh.fcn.base:                      268 ; 0x010: 0x0000010c
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
…………………………………………………………………………
等等
Kfed可以帮我们列出很多信息,有了这些,ASM的大部分秘密将被揭开。kfed的信息是这样看的,比如:
kfbh.endian:                          1 ; 0x000: 0x01
kfbh.endian是C语言的结构(struct)中的域。
1 ; 0x000: 0x01 :kfbh.endian的十进值为1,0x000是指它开始自第0个字节处,最后的0x01是十六进制值形式。
此域的意义是主机的大小端。0是大端,1是小端。此处值为1,说明主机是小端。
其他的这里就不再一一列出了,对其中的每个域,我后面有详细的说明。下面,只说相关的,在Kfed中找到如下信息:
kfffde[0].xptr.au:                    2 ; 0x4a0: 0x00000002
kfffde[0].xptr.disk:                  0 ; 0x4a4: 0x0000
kfffde[0].xptr.flags:                 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0
kfffde[0].xptr.chk:                  40 ; 0x4a7: 0x28
kfffde[1].xptr.au:                   27 ; 0x4a8: 0x0000001b
kfffde[1].xptr.disk:                  0 ; 0x4ac: 0x0000
kfffde[1].xptr.flags:                 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0
kfffde[1].xptr.chk:                  49 ; 0x4af: 0x31
kfffde[2].xptr.au:           4294967295 ; 0x4b0: 0xffffffff
kfffde[2].xptr.disk:              65535 ; 0x4b4: 0xffff
kfffde[2].xptr.flags:                 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0
kfffde[2].xptr.chk:                  42 ; 0x4b7: 0x2a
kfffde[3].xptr.au:           4294967295 ; 0x4b8: 0xffffffff
kfffde[3].xptr.disk:              65535 ; 0x4bc: 0xffff
kfffde[3].xptr.flags:                 0 ; 0x4be: L=0 E=0 D=0 C=0 S=0
kfffde[3].xptr.chk:                  42 ; 0x4bf: 0x2a
………………
如果你对C语言熟一点,我们会更容易描述这段信息,如果不太熟又想深入了解,可以回去翻翻谭浩强C语言书中结构体哪一部分,很简单的。kfffde,是结构数组。kfffde[0]的数据元素,存放了1号文件第一个AU的位置。kfffde[1]存放了1号文件第二个AU位置,等等,依次类推。我们来看一下上面的信息:
kfffde[0].xptr.au:                    2 ; 0x4a0: 0x00000002  :2号AU
kfffde[0].xptr.disk:                  0 ; 0x4a4: 0x0000       :0号磁盘
:上两个信息合起来,0号盘2号AU,这就是1号文件第一个AU的位置
kfffde[0].xptr.flags:                 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0 :标志位
kfffde[0].xptr.chk:                  40 ; 0x4a7: 0x28   : 校验码
通过上面kfffde[0]中的信息,我们可以知道,1号文件的第一个AU,位置在0号盘2号AU处。再看kfffde[1],它对应1号文件第二个AU,位置在0号盘27号AU。再往下看kfffde[3],AU编号4294967295,磁盘编号65535。这说明1号文件还没有第三个AU。
通过上面的信息,我们可以得到,1号文件共有两个AU,分别在0号盘2号AU、0号盘27号AU。
再来一张图,帮助理解:
092158avq1h4syr3jsx5hh
图3
4、读取其他文件:读取元文件
再来一个例子,假设我们想要访问3号文件,如何找出3号文件的AU都在哪里分布呢?
根据我们刚才所讲的,3号文件的AU分布,在(0号盘,2号AU,3号块)中,使用Kfed读取它:
[oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=2 blkn=3|more
…………………………
kfffde[0].xptr.au:                    3 ; 0x4a0: 0x00000003
kfffde[0].xptr.disk:                  1 ; 0x4a4: 0x0001
kfffde[0].xptr.flags:                 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0
kfffde[0].xptr.chk:                  40 ; 0x4a7: 0x28
kfffde[1].xptr.au:                    3 ; 0x4a8: 0x00000003
kfffde[1].xptr.disk:                  0 ; 0x4ac: 0x0000
kfffde[1].xptr.flags:                 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0
kfffde[1].xptr.chk:                  41 ; 0x4af: 0x29
kfffde[2].xptr.au:                    4 ; 0x4b0: 0x00000004
kfffde[2].xptr.disk:                  1 ; 0x4b4: 0x0001
kfffde[2].xptr.flags:                 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0
kfffde[2].xptr.chk:                  47 ; 0x4b7: 0x2f
kfffde[3].xptr.au:                    4 ; 0x4b8: 0x00000004
kfffde[3].xptr.disk:                  0 ; 0x4bc: 0x0000
kfffde[3].xptr.flags:                 0 ; 0x4be: L=0 E=0 D=0 C=0 S=0
kfffde[3].xptr.chk:                  46 ; 0x4bf: 0x2e
………………………………………………
根据我们前面我讲的,解读这些信息是很容易的。3号文件的AU有:(1号盘3号AU)、(0号盘3号AU)、(1号盘4号AU)、(0号盘4号AU)、…………。
还是来看张图吧,更加清楚些:
092200sj4k7gkwluwuekk0
图4
5、读取数据文件
我先在ASM中新建一个数据文件,然后,我们再来查看它的AU分布。
创建如下表空间:
create tablespace tbs_tst01 datafile ‘+DG1/data/tbs_tst01_00.dbf’ size 10M autoextend off;
我们创建了一个10M大的数据文件,也就是说,它会有10个AU。如下查询一下它在ASM中的文件索引号:
(在ASM实例中执行如下语句:)
SQL> select name,file_number from v$asm_alias where name like ‘tbs_tst01%’;
NAME                                             FILE_NUMBER
———————————————— ———–
tbs_tst01_00.dbf                                         257
FILE_NUMBER列也是文件号,我们一般称它为ASM文件索引号,在这里 tbs_tst01_00.dbf的索引号是 257。
1号文件的第一个AU(0号盘2号AU)中,只能保存1至255号文件的。从256号文件开始,AU的分布信息保存在1号文件第二个AU中,也就是(0号盘,27号AU)。其中第一个块(0号块),对应256号文件。1号块对应257号文件,等等,依此类推。
照惯例,我们先用Kfed读取一下0号盘27号AU的1号块,查看一下257号文件的AU分布:
[oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=27 blkn=1|more
…………………………………………
kfffde[0].xptr.au:                  278 ; 0x4a0: 0x00000116
kfffde[0].xptr.disk:                  0 ; 0x4a4: 0x0000
kfffde[0].xptr.flags:                 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0
kfffde[0].xptr.chk:                  61 ; 0x4a7: 0x3d
kfffde[1].xptr.au:                  277 ; 0x4a8: 0x00000115
kfffde[1].xptr.disk:                  1 ; 0x4ac: 0x0001
kfffde[1].xptr.flags:                 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0
kfffde[1].xptr.chk:                  63 ; 0x4af: 0x3f
kfffde[2].xptr.au:                  279 ; 0x4b0: 0x00000117
kfffde[2].xptr.disk:                  0 ; 0x4b4: 0x0000
kfffde[2].xptr.flags:                 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0
kfffde[2].xptr.chk:                  60 ; 0x4b7: 0x3c
…………………………………………
…………………………………………
…………………………………………
kfffde[10].xptr.au:                 283 ; 0x4f0: 0x0000011b
kfffde[10].xptr.disk:                 0 ; 0x4f4: 0x0000
kfffde[10].xptr.flags:                0 ; 0x4f6: L=0 E=0 D=0 C=0 S=0
kfffde[10].xptr.chk:                 48 ; 0x4f7: 0x30
kfffde[11].xptr.au:          4294967295 ; 0x4f8: 0xffffffff
kfffde[11].xptr.disk:             65535 ; 0x4fc: 0xffff
kfffde[11].xptr.flags:                0 ; 0x4fe: L=0 E=0 D=0 C=0 S=0
kfffde[11].xptr.chk:                 42 ; 0x4ff: 0x2a
257号文件一共10个AU,所以,kfffde[11]中的AU位置和磁盘位置是0xffffffff、0xffff。但kfffde[10]还有是明确的值的。257号文件的10号AU位置:0号磁盘283号AU,这其实是257的第11个AU。
tbs_tst01表空间使用的是“系统管理区大小”,也就是说区大小有64K、1M、8M等多种选择。但是无论区大小,每个ASM中的文件,比原大小总会多出一个AU。就像这里的257号文件,原大小是10M,但实际是11M,共11个AU。
再来一张图吧,有图清楚些:
0922023kpzpmomfkpxzigg
图5
092205ldg0tg03zg80rtg8
图6
上面图5和图6,具体描述了在ASM中读取257号文件的步骤。在这里,257号文件创建大小是10M,实际在ASM中大小为11M,共11个AU。这11个AU的信息,都在0号盘、27号AU、1号块中。假设有一个非常大的文件,AU数也非常多,一个块中存不完,Oracle是如何处理的呢?下面,我们继续。
6、读取特别大的文件:间接AU
创建一个稍大一点的数据文件,比如200M:
create tablespace tbs_tst02 datafile ‘+DG1/data/tbs_tst02_00.dbf’ size 200M autoextend off;
根据我们前面所讲的,200M的数据文件,在ASM中实际将占用201M空间(201个AU)。下面,我们查找一下此文件的AU分布。首先在ASM中执行如下命令:
SQL> select name,file_number from v$asm_alias where name like ‘tbs_tst02%’;
NAME                                             FILE_NUMBER
———————————————— ———–
tbs_tst02_00.dbf                                         258
确定一下,tbs_tst02_00.dbf的文件号是258。它的AU分布信息,应该在1号文件的第二个AU的第3个块(2号块)中,老规距,先用Kfed读取1号文件第二个AU第3个块,也就是0号盘、27号AU、2号块:
[oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=27 blkn=2|more
………………………………………………………………
kfffde[0].xptr.au:                  282 ; 0x4a0: 0x0000011a
kfffde[0].xptr.disk:                  1 ; 0x4a4: 0x0001
kfffde[0].xptr.flags:                 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0
kfffde[0].xptr.chk:                  48 ; 0x4a7: 0x30
kfffde[1].xptr.au:                  284 ; 0x4a8: 0x0000011c
kfffde[1].xptr.disk:                  0 ; 0x4ac: 0x0000
kfffde[1].xptr.flags:                 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0
kfffde[1].xptr.chk:                  55 ; 0x4af: 0x37
………………………………………………………………
这些信息我们都熟悉了,是说明258号文件的AU分布,第一个AU在1号盘、282号AU处。第二个AU是0号盘、284号AU。等等。一直向下翻页,你会发现在kfffde[61]处,AU信息和Disk信息就已经没有了。kfffde[60]是最后一个有效AU,位置是0号盘、314号AU处:
………………………………………………………………
kfffde[60].xptr.au:                 314 ; 0x680: 0x0000013a
kfffde[60].xptr.disk:                 0 ; 0x684: 0x0000
kfffde[60].xptr.flags:                0 ; 0x686: L=0 E=0 D=0 C=0 S=0
kfffde[60].xptr.chk:                 17 ; 0x687: 0x11
kfffde[61].xptr.au:          4294967295 ; 0x688: 0xffffffff
kfffde[61].xptr.disk:             65535 ; 0x68c: 0xffff
kfffde[61].xptr.flags:                0 ; 0x68e: L=0 E=0 D=0 C=0 S=0
kfffde[61].xptr.chk:                 42 ; 0x68f: 0x2a
………………………………………………………………
其实,kfffde[60]已经不是258号文件实际存放数据的AU了,直到kfffde[59]还是。也就是说kfffde[0]到kfffde[59],第258号文件的前60个AU的位置信息(也就是前60M了),保存在此处。258号文件共201个AU呢,后面141个AU的位置信息在哪儿呢?就在kfffde[60]对应的,0号盘、314号AU中。
再来读取一下它:0号盘、314号AU。
[oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=314 blkn=0|more
………………………………………………………………
kfbh.block.obj:                     258 ; 0x008: TYPE=0x0 NUMB=0x102
………………………………………………………………
kffixe[0].xptr.au:                  312 ; 0x00c: 0x00000138
kffixe[0].xptr.disk:                  1 ; 0x010: 0x0001
kffixe[0].xptr.flags:                 0 ; 0x012: L=0 E=0 D=0 C=0 S=0
kffixe[0].xptr.chk:                  18 ; 0x013: 0x12
kffixe[1].xptr.au:                  315 ; 0x014: 0x0000013b
kffixe[1].xptr.disk:                  0 ; 0x018: 0x0000
kffixe[1].xptr.flags:                 0 ; 0x01a: L=0 E=0 D=0 C=0 S=0
kffixe[1].xptr.chk:                  16 ; 0x01b: 0x10
kffixe[2].xptr.au:                  313 ; 0x01c: 0x00000139
kffixe[2].xptr.disk:                  1 ; 0x020: 0x0001
kffixe[2].xptr.flags:                 0 ; 0x022: L=0 E=0 D=0 C=0 S=0
kffixe[2].xptr.chk:                  19 ; 0x023: 0x13
………………………………………………………………
我多显示了一个域的信息:kfbh.block.obj,它代表此数据块属于哪个文件,此处的值为258,代表此数据块、此AU属于258号文件。
kffixe[0]是258号文件的第61个AU,它的位置是1号盘312号AU。注意,它就是一个间接AU。后面的kffixe[1]、kffixe[2],……,等等也都是间接AU了。
好,258号文件AU分布的查找过程,我用三幅图总结:
092206w2w2dkzbw5w842yd
图7
092209llffvjyifze69bbv
图8
092212avmd8t8et11am8z7
图9
ASM文件管理模式到这里就差不多了。我们使用Kfed,直接读取磁盘,描述了查找、定位文件AU分布的方式。如果只是想看看某个文件的AU分布,当然不用每次都使用Kfed,我们可以在ASM实例中,查询X$KFFXP视图。

第 三 章X$KFFXP

这个视图很容易理解,我把它的主要列介绍一下:
GROUP_KFFXP   :磁盘组编号
NUMBER_KFFXP  :文件编号
PXN_KFFXP     :物理区号
XNUM_KFFXP    :逻辑区号
LXN_KFFXP     :0=primary, 1=first mirror, 2=second mirror
DISK_KFFXP    :磁盘编号
AU_KFFXP      :AU号
通常,一个AU就是一个区。逻辑区和物理区的区别是,如果冗余模式是Nomarl,有两个FailGroup,那么文件的每一个AU,可以称为一个逻辑区。它在两个FailGroup中分别各自对应一个AU,每个AU称为物理区。

我想,这个视图不用我再过多介绍了吧。

第四章 ASM文件直接读取

终于到本文的压轴戏了,绕过Oracle,直接读取ASM文件。阅读本章,你就需要点编程基础了。程序不长,一共只不过300多行而已。其实如查你仔细阅读了本文前面的内容,而且也都理解了,那么,你应该感觉到了,自己开发一个这样的程序并非难事。
如果你曾经是专业的C程序员,看到Kfed的输出,你应该就感觉到了,它输出的结果就是Struct。比如AU的位置信息,直接AU的Struct叫kfffde,间接AU叫kffixe,结构都一样,可以如下定义:

typedef struct XPTR
{
unsigned int au;
unsigned short int disk;
unsigned char flags;
unsigned char chk;
}XPTR;
XPTR *kfffde,* kffixe;

这个结构会占用8个字节,一个4096字节的块,是可以保存很多AU的。但是,不知出于什么原因,每个文件的AU位置信息在1号文件所占用的第一个块中,只保存前60个AU的位置,编号分别为0至59。这60个AU就是前文中提到的直接AU了。而第61个AU(编号为60),保存文件其他AU的位置分布信息,其他的AU就是间接AU了。

我们只需要参照Kfed的输出结果,定义各种Struct,然后根据直接Open磁盘设备文件,将信息读入各种Struct就行了。
哪么,还有一个难点,如何解读Kfed的输出结果?没关系,我已经考虑到这个问题了,各种Struct的解读,我已经放在本文的后几章。
程序非常简单,我不再过多说明,有问题可以给我留言,请记住我的永久域名:www.MythData.com
如果哪个公司有进一步完善、开发成产品的需求,只要有钱赚都可以联系我,大家一起合作、一起发财。
不过,说实话,仔细看看我这篇文章,再做做测试,找个廉价的C程序员(刚过二级考试哪种),就能把这个程序写出来,其实根据不需要找我的。

下面测试一下程序,将附件中的程序直接编译:

[root@red1 asm]# gcc -o rdasm rdasm.c

我这里没有报任何错,如果你编译不过去,可以给我留言。下面测试一下:
步1:查看表空间
SQL> select file_name,tablespace_name from dba_data_files where tablespace_name=’RDASM’;

FILE_NAME                                          TABLESPACE_NAME
————————————————– ——————————
+DG1/data/rdasm.dbf                                RDASM

以RDASM表空间唯一的数据文件+DG1/data/rdasm.dbf为例,一会儿把它从ASM中读出来。

步2:创建检测表:
SQL> create table test1 (id int,cc varchar2(20)) tablespace rdasm;

Table created.

SQL> insert into test1 select rownum,’abc’ from dba_objects;

9904 rows created.

SQL> commit;

Commit complete.

在RDASM中创建一个9904行的表,把+DG1/data/rdasm.dbf文件从ASM中读出来后,可以再对查询一下此表的行数,验证读取是否成功。

步3:把RDASM表空间脱机:
SQL> alter tablespace rdasm offline;

Tablespace altered.

也可以把表空间设置为热备状态。

步4:查询在ASM中此数据文件的编号:
[oracle@red1 ~]$ export ORACLE_SID=myasm
[oracle@red1 ~]$ sqlplus / as sysdba

SQL> select name,file_number from v$asm_alias where name=’rdasm.dbf’;

NAME                                             FILE_NUMBER
———————————————— ———–
rdasm.dbf                                                304

在ASM中,rdasm.dbf的编号为304。

步5:将ASM中的304号文件读取到/home/oracle/304.dbf中:
[root@red1 drasm]# ./rdasm 304 /home/oracle/304.dbf

目前我的程序只支持根据文件编号读取。更进一步的,可以只提供文件名,这个功能还没有实现。

步6:改变一下读出文件的属主:
[root@red1 drasm]# ls -lF /home/oracle/304.dbf
-rw-r—–  1 root root 6299648 Oct 19 09:44 /home/oracle/304.dbf

[root@red1 drasm]# chown oracle.oinstall /home/oracle/304.dbf

步7:在数据库中改名:
SQL> alter database rename file ‘+DG1/data/rdasm.dbf’ to ‘/home/oracle/304.dbf’;

Database altered.

将+DG1/data/rdasm.dbf改为/home/oracle/304.dbf 。

步8:恢复、并联机表空间
SQL> alter tablespace rdasm online;
alter tablespace rdasm online
*
ERROR at line 1:
ORA-01113: file 18 needs media recovery
ORA-01110: data file 18: ‘/home/oracle/304.dbf’

把RDASM表空间联机,虽然报出了错误,但并不是文件损坏,而是需要恢复,下面把/home/oracle/304.dbf恢复一下:

SQL> recover datafile 18 ;
ORA-00279: change 431943 generated at 09/15/2009 05:04:28 needed for thread 1
ORA-00289: suggestion : +DG1/archive/1_54_693785914.dbf
ORA-00280: change 431943 for thread 1 is in sequence #54

Specify log: {<RET>=suggested | filename | AUTO | CANCEL}

Log applied.
Media recovery complete.

恢复完成后再次联机RDASM表空间,这次可以成功联机:
SQL> alter tablespace rdasm online;

Tablespace altered.

步9:测试:
SQL> select count(*) from test1;

COUNT(*)
———-
9904

查询一下TEST1表,可以正确把9904行读出来。

怎么样,简单吧,动心了吧,赶快试一下吧:

第五章  磁盘头格式
位于每个磁盘第一个AU,AU编号0,可以用如下Kfed命令读取:
[oracle@red1 disks]$ kfed read /dev/oracleasm/disks/VOL1 aun=0 blkn=0|more
kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            1 ; 0x002: KFBTYP_DISKHEAD
……………………
具体内容如下:

00 endian_kfbh:
Little Endian = 1
Big Endian = 0

01 hard_kfbh:
KFBH_HARD      0x02     /* expected magic number */
KFBH_HARD_4K   0x80     /* 4K metadata block size */
KFBH_HARD_8K   0xa0     /* 8K metadata block size */
KFBH_HARD_16K  0xc0     /* 16K metadata block size */
KFBH_HARD_32K  0xe0     /* 32K metadata block size */

02 type_kfbh:
磁盘头总是KFBTYP_DISKHEAD

03 datfmt_kfbh:
04 to 07 block_kfbh.blk:
磁盘头总是为0

08 to 0B block_kfbh.obj:
Since this is a little endian architecture this represents the number “0x80000000”. The high order byte will always be 0x80 and the lower bytes represent the disk number which is 0x0 here meaning this is the first disk in the diskgroup.

0C to 0F check_kfbh:
校验码,写到磁盘前计算。

10 to 13 fcn_kfbh.base
14 to 17 fcn_kfbh.wrap
18 to 1B fspare1_kfbh
1C to 1f fspare2_kfbh
磁盘头无意义。

20 to 27 driver_kfdhdb.driver_kfdhdb:
没有使用Lib包的时候显示为ORCLDISK。

28 to 3F driver_kfdhdb.reserved_kfddrb:
kfdhdb.driver.reserved[0]:            0 ; 0x008: 0x00000000
kfdhdb.driver.reserved[1]:            0 ; 0x00c: 0x00000000
kfdhdb.driver.reserved[2]:            0 ; 0x010: 0x00000000
kfdhdb.driver.reserved[3]:            0 ; 0x014: 0x00000000
kfdhdb.driver.reserved[4]:            0 ; 0x018: 0x00000000
kfdhdb.driver.reserved[5]:            0 ; 0x01c: 0x00000000
为0。

40 to 43 compat_kfdhdb:
版本号

44 and 45 dsknum_kfdhdb:
可以看到占两个字节:
kfdhdb.dsknum:                        0 ; 0x024: 0x0000
一个DG中,最多只能有65536块盘。

46 grptyp_kfdhdb:
冗余策略:
KFDGTP_INVALID     ((kfdgtp)0)  /* Illegal value                     */
KFDGTP_EXTERNAL    ((kfdgtp)1)  /* External redundancy               */
KFDGTP_NORMAL      ((kfdgtp)2)  /* Normal redundancy                 */
KFDGTP_HIGH        ((kfdgtp)3)  /* High redundancy                   */

47 hdrsts_kfdhdb:
KFDHDR_INVALID     ((kfdhdr)0)  /*   Illegal value                   */
KFDHDR_UNKNOWN     ((kfdhdr)1)  /*   Disk header block unreadable    */
KFDHDR_CANDIDATE   ((kfdhdr)2)  /*   No OSM or OS disk header found  */
KFDHDR_MEMBER      ((kfdhdr)3)  /*   Normal member of the group      */
KFDHDR_FORMER      ((kfdhdr)4)  /*   Disk dropped cleanly from group */
KFDHDR_CONFLICT    ((kfdhdr)5)  /*   Header conflicts                */
KFDHDR_INCOMPAT    ((kfdhdr)6)  /*   Written by incompatible software*/
KFDHDR_PROVISIONED ((kfdhdr)7)  /*   Disk was prepared beforehand    */
参见V$asm_disk

48 to 67 dskname_kfdhdb

68 to 87 grpname_kfhdb:

88 to A7 fgname_kfdhdb:

A8 to C7 capname_kfdhdb:
未使用

kfdhdb.crestmp.hi:             32956296 ; 0x0a8: HOUR=0x8 DAYS=0x1c MNTH=0x7 YEAR=0x7db
kfdhdb.crestmp.lo:            978288640 ; 0x0ac: USEC=0x0 MSEC=0x3e0 SECS=0x24 MINS=0xe
创建时的时间戳

kfdhdb.mntstmp.hi:             32956352 ; 0x0b0: HOUR=0x0 DAYS=0x1e MNTH=0x7 YEAR=0x7db
kfdhdb.mntstmp.lo:             95641600 ; 0x0b4: USEC=0x0 MSEC=0xd8 SECS=0x1b MINS=0x1
Mount时的时间戳

kfdhdb.secsize:                     512 ; 0x0b8: 0x0200
扇区大小

kfdhdb.blksize:                    4096 ; 0x0ba: 0x1000
块大小

kfdhdb.ausize:                  1048576 ; 0x0bc: 0x00100000
AU大小。

kfdhdb.mfact:                    113792 ; 0x0c0: 0x0001bc80
版本相关,无意义

kfdhdb.dsksize:                     102 ; 0x0c4: 0x00000066
本磁盘包含的AU数量。kfdhdb.ausize * dsksize_kfdhdb = disk size

kfdhdb.pmcnt:                         2 ; 0x0c8: 0x00000002
AU的物理地址空间。

kfdhdb.fstlocn:                       1 ; 0x0cc: 0x00000001
说明第一个AU后,是用户可用空间。

kfdhdb.altlocn:                       2 ; 0x0d0: 0x00000002
说明文件目录开始自第二个AU

kfdhdb.f1b1locn:                      2 ; 0x0d4: 0x00000002
File Directory block 1 Allocation Unit number

第六章    PST – Partnership and Status Table
位于每个磁盘第二个AU,AU编号为1。

PST – Partnership and Status Table contains the status information about
the ASM disks in a disk group – disk number, status (either online or offline),
partner disk number, failure group info (11g) and heartbeat info.  AU number 1
in every disk within a disk group is reserved for PST.  Only a few disk actually
have a PST – in external redundancy group we only have one PST table, in normal
redundancy group (double mirroring) we have up to 3 PST and in high redundancy
we have up to 5 PST.  The GMON process is responsible for PST processing. See
kfdp source code for more informaiton.

kfbh.endian
Little endian = 1
Big endian = 0

kfbh.hard
H.A.R.D. magic # and block size

kfbh.type
metadata block type,对PST为KFBTYP_PST_META。

kfbh.datfmt
metadata block data format

kfbh.block
blk :T=0 NUMB=0x100,共四个字节,其中一个字节为T=0,剩余的为NUMB=0x100
obj — Disk header should have TYPE=0x8 NUMB=<disknumber>

kfbh.check
校验码

kfbh.fcn.base:                        0 ; 0x010: 0x00000000
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
PST最后改变的时间。

kfdpHdrB.time.hi:              32956296 ; 0x000: HOUR=0x8 DAYS=0x1c MNTH=0x7 YEAR=0x7db
kfdpHdrB.time.lo:             978361344 ; 0x004: USEC=0x0 MSEC=0x27 SECS=0x25 MINS=0xe
PST最后被UPDATE的时间

kfdpHdrB.last:                        1 ; 0x008: 0x00000001
kfdpHdrB.next:                        1 ; 0x00c: 0x00000001
版本号:

kfdpHdrB.copyCnt:                     2 ; 0x010: 0x02
1:外部冗余。2:正常冗余。等等

kfdpHdrB.incarn:                      0 ; 0x014: 0x00000000
化身号,PST发生移动时增加

kfdpHdrB.copy[0]:                     0 ; 0x018: 0x0000
kfdpHdrB.copy[1]:                     2 ; 0x01a: 0x0002
kfdpHdrB.copy[2]:                     0 ; 0x01c: 0x0000
kfdpHdrB.copy[3]:                     0 ; 0x01e: 0x0000
kfdpHdrB.copy[4]:                     0 ; 0x020: 0x0000
冗余模式:
[0]    — external redundancy
[0-2]  — normal redundancy
[0-4]  — high redundancy

kfdpHdrB.dtaSz:                       4 ; 0x022: 0x0004
kfdpHdrB.dtaSz
kf3.h    /* # dta entries in PST  */
This is the number of disks that it needs to keep track of.

第七章  目录结构
磁盘头中的kfdhdb.f1b1locn位,指明了文件目录的开始位置。
下面读取sdd中2号Au的1号块(第三个Au的第二个块),1号块中是1号文件的AU分布。2号块中是2号文件的AU分布。以此类推。每个块是4096字节,第一个块被占作别用,一个AU可以保存255个文件。所以,此DG的0号磁盘、2号AU中保存1至255个文件的AU分布。256号文件在第二个AU中。
$ kfed read /dev/sdd aun=2 blkn=1 | more
kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            4 ; 0x002: KFBTYP_FILEDIR // block type = file directory block…
kfffdb.node.incarn:         1 ; 0x000: A=1 NUMM=0x0 // 文件化身号。参见V$ASM_ALIAS.FILE_INCARNATION
kfffdb.node.frlist.number:   4294967295 ; 0x004: 0xffffffff
kfffdb.node.frlist.incarn:            0 ; 0x008: A=0 NUMM=0x0
kfffdb.hibytes:                       0 ; 0x00c: 0x00000000 // 文件大小
kfffdb.lobytes:                 2097152 ; 0x010: 0x00200000 // 文件大小(此处是2M,两个AU)
kfffdb.xtntcnt:                       2 ; 0x014: 0x00000002 // 文件一共有两个区
kfffdb.xtnteof:                       2 ; 0x018: 0x00000002 // 在EOF标志前有两个区
kfffdb.blkSize:                    4096 ; 0x01c: 0x00001000 // 标准ASM块大小
kfffdb.flags:                         1 ; 0x020: O=1 S=0 S=0 D=0 C=0 I=0 R=0 A=0
// Flag definitions
O – File is original, not snapshot
S – File is striped
S – Strict allocation policy
D – File is damaged
C – File creation is committed
I – File has empty indirect block
R – File has known at-risk value
A – The at-risk value itsefl
kfffdb.fileType:                     15 ; 0x021: 0x0f //文件类型为元数据
kfffdb.dXrs:                         17 ; 0x022: SCHE=0x1 NUMB=0x1 // 直接区冗余方案
kfffdb.iXrs:                         17 ; 0x023: SCHE=0x1 NUMB=0x1 // 间接区冗余方案
kfffdb.dXsiz[0]:             4294967295 ; 0x024: 0xffffffff // # 直接区的大小
kfffdb.dXsiz[1]:                      0 ; 0x028: 0x00000000
kfffdb.dXsiz[2]:                      0 ; 0x02c: 0x00000000
kfffdb.iXsiz[0]:             4294967295 ; 0x030: 0xffffffff // # 间接区的大小
kfffdb.iXsiz[1]:                      0 ; 0x034: 0x00000000
kfffdb.iXsiz[2]:                      0 ; 0x038: 0x00000000
kfffdb.xtntblk:                       2 ; 0x03c: 0x0002 // 直接区和间接区的总数
kfffdb.break:                       300 ; 0x03e: 0x012c // 间接区的索引
kfffdb.priZn:                         0 ; 0x040: 0x00 // Primary extent allocation zone
kfffdb.secZn:                         0 ; 0x041: 0x00 // Secondary extent allocation zone
kfffdb.ub2spare:                      0 ; 0x042: 0x0000 // Spare
kfffdb.alias[0]:             4294967295 ; 0x044: 0xffffffff // No alias pointers for this file
kfffdb.alias[1]:             4294967295 ; 0x048: 0xffffffff
kfffdb.strpwdth:                      0 ; 0x04c: 0x00 // Stripe width in extents
kfffdb.strpsz:                        0 ; 0x04d: 0x00 // Stripe size in 2^N bytes
kfffdb.usmsz:                         0 ; 0x04e: 0x0000 // User metadata size
kfffdb.crets.hi:               32855344 ; 0x050: HOUR=0x10 DAYS=0x9 MNTH=0x5 YEAR=0x7d5
kfffdb.crets.lo:               28766208 ; 0x054: USEC=0x0 MSEC=0x1bc SECS=0x1b MINS=0x0
// 文件的创建日期: 9 May 2005 16:00:27
kfffdb.modts.hi:               32855344 ; 0x058: HOUR=0x10 DAYS=0x9 MNTH=0x5 YEAR=0x7d5
kfffdb.modts.lo:               28766208 ; 0x05c: USEC=0x0 MSEC=0x1bc SECS=0x1b MINS=0x0
// 文件的修改日期
kfffdb.spare[0]:                      0 ; 0x060: 0x00000000 // Pad to leave room for 360 kfxp

kfffdb.spare[15]:                     0 ; 0x09c: 0x00000000
kfffdb.usm:                             ; 0x0a0: length=0 // User metadata

接下来是1号文件的AU分布
kfffde[0].xptr.au:                    2 ; 0x4a0: 0x00000002
kfffde[0].xptr.disk:                  0 ; 0x4a4: 0x0000
kfffde[0].xptr.flags:                 0 ; 0x4a6: L=0 E=0 D=0 C=0 S=0
kfffde[0].xptr.chk:                  40 ; 0x4a7: 0x28
kfffde[1].xptr.au:                   92 ; 0x4a8: 0x0000005c
kfffde[1].xptr.disk:                  0 ; 0x4ac: 0x0000
kfffde[1].xptr.flags:                 0 ; 0x4ae: L=0 E=0 D=0 C=0 S=0
kfffde[1].xptr.chk:                 118 ; 0x4af: 0x76
kfffde[2].xptr.au:           4294967295 ; 0x4b0: 0xffffffff // no more extents
kfffde[2].xptr.disk:              65535 ; 0x4b4: 0xffff
kfffde[2].xptr.flags:                 0 ; 0x4b6: L=0 E=0 D=0 C=0 S=0
kfffde[2].xptr.chk:                  42 ; 0x4b7: 0x2a

第八章  重要的文件
一、1号文件,文件目录。记录所有其他文件的AU分布
二、2号文件,磁盘目录。记录所有磁盘状态
其中的标志位信息如下:kfddde[0].state:
#define KFDSTA_INVALID ((kfdsta)0)  /* Illegal value */
#define KFDSTA_UNKNOWN ((kfdsta)1)  /* ASM disk state not known */
#define KFDSTA_NORMAL ((kfdsta)2)   /* Happy disk */
#define KFDSTA_UNUSED ((kfdsta)3)   /* Unused State – Open */
#define KFDSTA_DROPPING ((kfdsta)4) /* Disk being dropped from group */
#define KFDSTA_HUNG ((kfdsta)5)     /* Disk drop operation hung */
#define KFDSTA_FORCING ((kfdsta)6)  /* Disk beinng drop forced */
#define KFDSTA_DROPPED ((kfdsta)7)  /* Disk no longer part of group */
#define KFDSTA_ADDING ((kfdsta)8)   /* Disk being globally validated */
三、3号文件,ACD
四、4号文件:COD。相当于ASM中的回滚段
五、5号文件:模版目录
六、别名目录

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注