0
点赞
收藏
分享

微信扫一扫

asm底层原理

概念描述

# 能使用dd从asmcmd中抽取数据文件,在前2个AU(AU0和AU1)被完全破坏的情况下,需要磁盘组asm的元数据FDIR完整
# 同样的功能,AMDU也能实现
# 使用dd,可以模拟asmcmd的cp,解析amdu的抽取过程,更加直观的了解数据文件在磁盘组中的底层组织结构

测试验证

# 本次模拟测试步骤:
# 1 使用3个磁盘组成的Normal磁盘组,再添加一块磁盘(raw4)之后,进行表空间创建,插入数据,
# 2 offline掉新添加的那个磁盘4
# 3 进行更新数据,提交到磁盘
# 4 进行关库,使用dd抽取文件,
# 5 使用抽取出来的数据文件进行使用验证

开始之前准备

# 在磁盘组上创建表空间TS1,新建一个测试表cog.t1
SYS@DB(db): 1> @tbsfile ts1
FILE_ID FILE_NAME                           
------- ------------------------------------
      5 +FRA/db/datafile/ts1.256.1123912897 

SYS@DB(db): 1> select count(1) from cog.t1;
COUNT(1)
--------
   25000

# offline表空间
# 查到的ext#map,由于3号磁盘被offline,所有AU号在Fdir中被修改为了4294967294,需要读其它镜像
alter tablespace ts1 offline;

# 更新cog.t1表数据
insert ...
update ...
commit;

# 关闭数据库
shutdown immediate

实验过程

1 遍历磁盘头,找出FDIR所在的AU

# 1 遍历磁盘头,找出FDIR所在的AU
# 元数据NORMAL默认是3副本
# 读前100个AU的0号块
# cat dsk.list
/dev/raw/raw1
/dev/raw/raw2
/dev/raw/raw3
/dev/raw/raw4

aus=1M
autypefile=dsk_autype.list; > dsk_autype.list
while read line   
do
  for (( i=0; i<=100; i++ )) ; do
   au_type=`kfed read $line aus=${aus} aun=${i} blkn=0 | grep "^kfbh.type" | awk '{print $5}'`
   echo "disk: ${line} aun: ${i} type: "${au_type}  >> ${autypefile}
  done
done < dsk.list

2 过滤出FDIR

# 
cat ${autypefile} | egrep "KFBTYP_LISTHEAD|KFBTYP_FILEDIR" 
# disk: /dev/raw/raw1 aun: 29 type: KFBTYP_LISTHEAD
# disk: /dev/raw/raw1 aun: 42 type: KFBTYP_FILEDIR
# disk: /dev/raw/raw2 aun: 2 type: KFBTYP_LISTHEAD
# disk: /dev/raw/raw2 aun: 22 type: KFBTYP_FILEDIR
# disk: /dev/raw/raw3 aun: 2 type: KFBTYP_LISTHEAD
# disk: /dev/raw/raw3 aun: 35 type: KFBTYP_FILEDIR

# KFBTYP_LISTHEAD 元数据全部是这个AU中
# KFBTYP_FILEDIR  用户数据从这个AU开始

3 读FDIR,找出数据文件的AU分布

# 用kfed读(抽取)出来 调用下面的函数(0号dsk的 29和42号AU)
> file1.list
kfed_read_fdir /dev/raw/raw1 29 1 file1.list  #  先抽1号ext#,即1号文件 1号ext#全部是

### file: 1 flg: 1 ftype: 15 dxrs: 3 ixrs: 3
#File# PhyExt# VirtExt# copy#  dsk#   AU#
    1        0        0     0     2     2
    1        1        0     1     1     2
    1        2        0     2     0    29 --> 1号ext# (副本号2)
    1        3        1     0     0    42 --> 2号ext# (副本号0)
    1        4        1     1     1    22
    1        5        1     2     2    35



# 用户文件,读取file1的第2个AU就可以了
aus=1M
fdir_file=fdir.list;>${fdir_file}
for (( i=0; i<=255; i++ )) ; do   
 kfed_read_fdir /dev/raw/raw1 42 $i ${fdir_file}
done

# 下面是要调用的shell函数
# 需要找的是文件号和ext号,还有冗余(用于计算是否是副本:2副本还是3副本)
kfed_read_fdir(){
# kfed read /dev/raw/raw1 aus=1M aun=29 blkn=1 | awk '/^kfbh.block.blk/{fno=$2}
# 传参  kfed_read_fdir /dev/raw/raw1 29 1   
kfed read $1 aus=${aus} aun=$2 blkn=$3 | awk '/^kfbh.block.blk/{fno=$2}
/^kfffdb.lobytes/{bs=$2}
/^kfffdb.flags/{flg=$2}
/^kfffdb.fileType/{ftype=$2}
/^kfffdb.dXrs/{dxrs=substr($6,8,1)}
/^kfffdb.iXrs/{iXrs=substr($6,8,1);
 if(bs>0 && ftype>0){print "### file: "fno" flg: "flg" ftype: "ftype" dxrs: "dxrs" ixrs: "iXrs"\n#File# PhyExt# VirtExt# copy#  dsk#   AU#"} }
/kfffde.*.xptr.au/{au=$2}
/kfffde\[.*\].xptr.disk/{match($1,/[0-9]+/);ext=substr($1,RSTART,RLENGTH); 
 dsk=$2; if(dxrs>0){vext=ext/dxrs;copy=ext%dxrs}fi;  
 if( ftype>0 && au<4294967295 && au>0 ){printf("%5d %8d %8d %5d %5d %5d\n",fno,ext,vext,copy,dsk,au) }} 
' >> ${4}
}

cat ${fdir_file}
### file: 256 flg: 17 ftype: 2 dxrs: 2 ixrs: 3
#File# PhyExt# VirtExt# copy#  dsk#   AU#
  256        0        0     0     0    20
  256        1        0     1     1    25
  256        2        1     0     3    39
...
  256       56       28     0     0    60
  256       57       28     1     2    59
  256       58       29     0     3 4294967294  --> offline的磁盘,需要读副本
  256       59       29     1     1    61
  256       60       30     0     1    62
  256       61       30     1     2    60
  256       62       31     0     0    61
### file: 257 flg: 17 ftype: 2 dxrs: 2 ixrs: 3  --> 257号文件也读出来了
#File# PhyExt# VirtExt# copy#  dsk#   AU# 
  257        0        0     0     1    15
  257        1        0     1     3    40
  257        2        1     0     2    21
  257        3        1     1     3    41
  257        4        2     0     3    42
  257        5        2     1     1    16
  257        6        3     0     0    50
  257        7        3     1     3    43

4 继续处理间接AU分布

# 60号以上的au处理-继续roll KFBTYP_INDIRECT
# 物理extent计算公式:e_ind=ext+e_ind+ofblk*480;
# 1M的  480*256=122880个AU=120G,所以只读1个就可以了
# 物理extent号必须连续,跳号则后续不处理
# 虚拟extent号的AU不能是4294967294,否则读其它副本


d0=/dev/raw/raw1
d1=/dev/raw/raw2
d2=/dev/raw/raw3
d3=/dev/raw/raw3
aus=1M
fdir2=fdir2.list;>${fdir2}
while read line   
do
  v_rem=`echo $line | awk '{if(index($1,"#")>0){print 1}else{print 0}}'`
  if [ "${v_rem}" = 1 ] ; then
    v_rem1=`echo $line | awk '{if(index($1,"###")>0){print 1}else{print 0}}'`
    if [  "${v_rem1}" = 1 ] ; then
      dxrs=`echo "$line" | awk '{print $9}'`
    fi
    echo "$line";per_ext=-1;per_ext1=0;
  else
    per_ext1=`expr ${per_ext} + 1`;read v_file v_ext v_vext v_cop v_dsk v_au  <<< $line
    # 为防止前60个AU物理ext#跳号,跳号则终止
    if [ "${per_ext1}" = "${v_ext}" ] ; then  per_ext=${per_ext1};
      # 如果遇到offline的磁盘,输出副本所在的AU  前60个ext#
      if [ ${v_cop} -eq 0 ] && [ ${v_au} -lt 4294967294 ] ; then       copy_ture=0;
      elif [ ${v_cop} -eq 0 ] && [ ${v_au} -eq 4294967294 ] ; then     copy_ture=1;
      elif [ ${v_cop} -eq 1 ] && [ ${v_au} -eq 4294967294 ] ; then     copy_ture=2;  fi
      if [ ${v_ext} -eq 61 ] ; then v_cop=1; elif [ ${v_ext} -eq 62 ]; then v_cop=2; fi
      if [ ${v_ext} -le 59 ] && [ ${v_cop} -eq ${copy_ture} ] ; then
        echo "$line" >> ${fdir2};                   copy_ture=0;
      elif [ ${v_ext} -ge 60 ] && [ ${v_cop} -eq ${copy_ture} ] ; then
        eval v_d=\${d${v_dsk}};         copy_ture=0
        #echo "##exact indirect FDIR";bk=0
        for (( i=0; i<=255; i++ )) ; do 
         kfed read ${v_d} aus=${aus} aun=${v_au} blkn=$i | awk -v file="${v_file}" -v ext="${v_ext}" -v dxrs="${dxrs}" '\
         /^kfbh.block.blk/{ofblk=substr($5,4)}
         /kffixe\[.*\].xptr.au/{match($1,/[0-9]+/);e_ind=substr($1,RSTART,RLENGTH);e_ind=ext+e_ind+ofblk*480;au=$2}
         /kffixe\[.*\].xptr.disk/{dsk=$2;if(dxrs>0){vext=e_ind/dxrs;copy=e_ind%dxrs}fi;
         if( au<4294967295 && au>0 ){printf("%d %8d %8d %5d %5d %5d\n",file,e_ind,vext,copy,dsk,au) }
        }' >> ${fdir2}
        done
      # else echo "$line  -- error  \${v_ext}:${v_ext}-gt59  \${v_cop}=${v_cop} \${copy_ture}=${copy_ture}"
      fi
    else
     continue;
    fi
  fi
done < ${fdir_file}

5 过滤掉1次offline磁盘

# 每个虚拟extent,只保留1条有效记录
# 如果遇到offline的磁盘,输出副本所在的AU  前60个ext#   
fdir3=fdir3.list;>${fdir3}
while read line   
do
read v_file v_ext v_vext v_cop v_dsk v_au  <<< $line
if [ ${v_ext} -le 60 ]; then 
 echo "$line"  >> ${fdir3}; 
else 
  if   [ ${v_cop} -eq 0 ] && [ ${v_au} -lt 4294967294 ] ; then     copy_ture=0;
  elif [ ${v_cop} -eq 0 ] && [ ${v_au} -eq 4294967294 ] ; then     copy_ture=1;
  elif [ ${v_cop} -eq 1 ] && [ ${v_au} -eq 4294967294 ] ; then     copy_ture=2;       fi;
  if [ "${v_cop}" = "${copy_ture}" ] ; then
    echo "$line" >>${fdir3};  copy_ture=0;
  fi
fi
done < fdir2.list

cat ${fdir3}


# 最终91个extent
[grid@db2 ~]$cat fdir3.list 
256        0        0     0     0    20
256        2        1     0     3    39
256        4        2     0     1    12
256        6        3     0     2    25
256        8        4     0     0    51
256       11        5     1     0    52
256       12        6     0     1    53
256       14        7     0     2    53
256       16        8     0     0    54
256       19        9     1     1    54
256       20       10     0     1    55
256       22       11     0     2    54
256       24       12     0     0    96
256       27       13     1     0    97
256       28       14     0     1    97
256       30       15     0     2    96
256       32       16     0     0    98
256       35       17     1     1    99
256       36       18     0     1    56
256       38       19     0     2    98
256       40       20     0     0    56
256       43       21     1     2    99
256       44       22     0     1    57
256       46       23     0     2    56
256       48       24     0     0    58
256       51       25     1     0    59
256       52       26     0     1    59
256       54       27     0     2    58
256       56       28     0     0    60
256       59       29     1     1    61
256       60       30     0     1    63
256       62       31     0     2    61
256       64       32     0     0    63
256       67       33     1     2    62
256       68       34     0     1    64
256       70       35     0     2    63
256       72       36     0     0    65
256       75       37     1     0    66
256       76       38     0     1    66
256       78       39     0     2    65
256       80       40     0     0    67
256       83       41     1     1    68
256       84       42     0     1    69
256       86       43     0     2    67
256       88       44     0     0    69
256       91       45     1     2    68
256       92       46     0     1    70
256       94       47     0     2    69
256       96       48     0     0    71
256       99       49     1     0    72
256      100       50     0     1    72
256      102       51     0     2    71
256      104       52     0     0    73
256      107       53     1     1    74
256      108       54     0     1    75
256      110       55     0     2    73
256      112       56     0     0    75
256      115       57     1     2    74
256      116       58     0     1    76
256      118       59     0     2    75
256      120       60     0     0    77
256      123       61     1     0    78
256      124       62     0     1    78
256      126       63     0     2    76
256      128       64     0     0    80
256      131       65     1     2    77
256      132       66     0     1    80
256      134       67     0     2    78
256      136       68     0     0    82
256      139       69     1     1    81
256      140       70     0     1    82
256      142       71     0     2    81
256      144       72     0     0    83
256      147       73     1     0    84
256      148       74     0     1    83
256      150       75     0     2    82
256      152       76     0     0    86
256      155       77     1     2    84
256      156       78     0     1    85
256      158       79     0     2    85
256      160       80     0     0    88
256      163       81     1     1    87
256      164       82     0     1    88
256      166       83     0     2    87
256      168       84     0     0    89
256      171       85     1     0    90
256      172       86     0     1    89
256      174       87     0     2    88
256      176       88     0     0    92
256      179       89     1     2    90
256      180       90     0     1    91
257        0        0     0     1    15
257        2        1     0     2    21
257        4        2     0     3    42
257        6        3     0     0    50

6 进行dd文件拼接

d0=/dev/raw/raw1
d1=/dev/raw/raw2
d2=/dev/raw/raw3
d3=/dev/raw/raw4
aus=1M
# 注意虚拟extents不能跳号
# 开始使用dd拼接文件
mkdir dd_output
while read line   ;do
read v_file v_ext v_vext v_cop v_dsk v_au  <<< $line
eval v_d=\${d${v_dsk}};    
dd if=${v_d} of=./dd_output/dbf_${v_file}.dbf bs=1M count=1 skip=${v_au} seek=${v_vext} conv=notrunc
done < fdir3.list 

[grid@db2 ~]$ls -l dd_output
total 97284
-rw-r--r--. 1 grid oinstall 95420416 Dec 23 22:33 dbf_256.dbf
-rw-r--r--. 1 grid oinstall  4194304 Dec 23 22:18 dbf_257.dbf  --> 257号文件也抽出来了

文件验证,坏块检查

SYS@: > select bytes/1024/1024 from v$datafile_header where file#=5;
BYTES/1024/1024
---------------
             90

dbv file=dbf_256.dbf
dbv验证:128号块开始(128号extent#),出现1M坏块

[grid@db2 ~]$cat fdir3.list 
256        0        0     0     0    20
256        2        1     0     3    39 --> 4号文件不是offline了吗?怎么跑这里来了 ,换成其它副本进行抽取
256        4        2     0     1    12 
# 是3号磁盘(raw4)offline之后更新的数据,这里并不能识别出是坏块
# 参照fdir.list 更新fdir3.list 重新执行dd拼接或者使用单独使用dd拼接这个块
line="256        3        1     1     2    28"
read v_file v_ext v_vext v_cop v_dsk v_au  <<< $line
eval v_d=\${d${v_dsk}};  
dd if=${v_d} of=./dd_output/dbf_${v_file}.dbf bs=1M count=1 skip=${v_au} seek=${v_vext} conv=notrunc


# 再次进行数据文件校验
# 已经成功了,没有坏块
cd dd_output/
dbv file=dbf_256.dbf

[grid@db2 dd_output]$dbv file=dbf_256.dbf
DBVERIFY: Release 11.2.0.4.0 - Production on Fri Dec 23 22:34:42 2022
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
DBVERIFY - Verification starting : FILE = /home/grid/dd_output/dbf_256.dbf

DBVERIFY - Verification complete

Total Pages Examined         : 11520
Total Pages Processed (Data) : 370
Total Pages Failing   (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing   (Index): 0
Total Pages Processed (Other): 141
Total Pages Processed (Seg)  : 0
Total Pages Failing   (Seg)  : 0
Total Pages Empty            : 11009
Total Pages Marked Corrupt   : 0
Total Pages Influx           : 0
Total Pages Encrypted        : 0
Highest block SCN            : 1209783 (0.1209783)

8 数据库切换文件进行使用测试验证

chown -R oracle.oinstall dd_output/
startup mount
select name from v$datafile where name like '%256%';
SYS@: > alter database rename file '+FRA/db/datafile/ts1.256.1123912897'  to '/data/dd_output/dbf_256.dbf';
Database altered.

SYS@: > alter database open;
Database altered.

# 数据文件能正常使用,说明使用dd的抽取是成功的
SYS@: > select count(1) from cog.t1;

COUNT(1)
--------
   25000

1 row selected.

知识总结

对asm底层原理的理解,非常有帮助,很多恢复工具恢复也是根据oracle的底层原理进行编写的

举报

相关推荐

0 条评论