The views expressed on this blog are my own and do not necessarily reflect the views of Oracle

January 1, 2012

ASM file number 1

ASM file number 1 - the file directory - keeps track of all files in the disk group. As disk groups are independent storage units, each will have its own file directory.

While this is an internal file, part of ASM metadata, it is managed like any other file in the disk group. It will have its own entry in the file directory, it will be mirrored in a normal and high redundancy disk group and will automatically grow to accommodate more files.

Each file directory entry maintains the following information:
  • File size
  • File block size
  • File type 
  • File redundancy level
  • File striping configuration
  • Direct extent pointers for up to 60 extents
  • Indirect extent pointers (if the file takes more than 60 extents)
  • File creation time-stamp
  • File last modification time-stamp
  • Pointer to the file name in the alias directory
A sequential number is assigned to each file managed by ASM. That file number corresponds to a block number in the ASM file directory. Thus, block 1 of the file directory describes itself - the file number 1. Block 2 is about file 2, block 300 is about file 300, block 4000 is about file 4000 and so on.

The file directory and the allocation table are complementary data structures. The ALTER DISKGROUP CHECK command checks if those two data structures are in agreement.

V$ASM_FILE and V$ASM_ALIAS views

Most of the information maintained in the disk group's file directories can be accessed via V$ASM_FILE view. It displays one row for every ASM file in every mounted disk group. Note that this view will not show ASM metadata files. V$ASM_FILE does not have the file name column, so for the meaningfull output, we would have to query it together with V$ASM_ALIAS view.

Here is an example:

SELECT f.group_number, f.file_number, a.name, f.type
FROM v$asm_file f, v$asm_alias a
WHERE f.group_number=a.group_number and f.file_number=a.file_number
ORDER BY 1, 2;

GROUP_NUMBER FILE_NUMBER NAME                             TYPE
------------ ----------- -------------------------------- ------------------------
           1         253 REGISTRY.253.769023761           ASMPARAMETERFILE
           1         256 SYSTEM.256.769030243             DATAFILE
           1         257 SYSAUX.257.769030245             DATAFILE
           1         258 UNDOTBS1.258.769030245           DATAFILE
           1         259 USERS.259.769030245              DATAFILE
           1         260 Current.260.769030435            CONTROLFILE
           1         261 Current.261.769030431            CONTROLFILE
           1         262 group_1.262.769030439            ONLINELOG
           1         263 group_1.263.769030445            ONLINELOG
           1         264 group_2.264.769030453            ONLINELOG
...
           3         256 Current.256.771527253            CONTROLFILE
           3         257 group_1.257.771527259            ONLINELOG
           3         258 group_1.258.771527263            ONLINELOG
...
           3         270 SYSAUX.270.771527407             DATAFILE
           3         271 SYS_UNDOTS.271.771527409         DATAFILE
           3         272 spfile.272.771536207             PARAMETERFILE

34 rows selected.

Note that files in different disk groups can have the same ASM file number.

Locating the file directory

We can query fixed table X$KFFXP in ASM instance, to find out which allocation units belong to file 1:

SQL> SELECT xnum_kffxp "Extent", au_kffxp "AU", disk_kffxp "Disk"
FROM x$kffxp
WHERE group_kffxp=1 -- Diskgroup 1 (DATA)
and number_kffxp=1  -- File 1 (file directory)
ORDER BY 1,2;

    Extent         AU       Disk
---------- ---------- ----------
         0          2          0
         0          2          1
         0          2          2
         1         44          3
         1         47          2
         1         48          0

6 rows selected.

The result shows two things - that the file directory is triple mirrored (note 3 physical extents for each virtual extent) and that the current size of the file directory is 6 extents, which equals to 6 allocation units.

With allocation unit size of 1MB and ASM metadata block size of 4KB, one allocation unit can hold up to 256 directory entries. As numbers up to 255 are reserved for ASM metadata files, extent 0 will only have enough room for ASM metadata files. Extent 1 will hold information about next 256 files managed by ASM and so on.

ASM file directory entries for database files

Let's see which files are managed by my ASM instance. To find out, I will run the following query against the ASM instance:

SQL> SELECT file_number "ASM file number", name "File name"
FROM v$asm_alias
WHERE group_number=1
ORDER BY 1;

ASM file number File name
--------------- ----------------------
            253 REGISTRY.253.769023761
            256 SYSTEM.256.769030243
            257 SYSAUX.257.769030245
            258 UNDOTBS1.258.769030245
            259 USERS.259.769030245
            260 Current.260.769030435
            261 Current.261.769030431
            262 group_1.262.769030439
            263 group_1.263.769030445
            264 group_2.264.769030453
            265 group_2.265.769030461
            266 group_3.266.769030471
            267 group_3.267.769030479
            268 TEMP.268.769030503
            269 EXAMPLE.269.769030517
            270 spfile.270.769030977
...

As we see my ASM instance is managing a typical set of database files (and its own SPFILE, but more on that at some other time). Let's have a closer look at those files.

File directory entries for control files

Query the database for its control files.

SQL> SELECT name, block_size, block_size*file_size_blks+block_size "File size"
FROM v$controlfile;

NAME                                         BLOCK_SIZE  File size
-------------------------------------------- ---------- ----------
+DATA/br/controlfile/current.261.769030431        16384    9748480
+DATA/br/controlfile/current.260.769030435        16384    9748480

Let's now look at the file directory entry for ASM file 260 (current.260.769030435). First, query X$KFFXP in ASM instance, for extent and AU distribution:

SQL> SELECT xnum_kffxp "Extent", au_kffxp "AU", disk_kffxp "Disk"
FROM x$kffxp
WHERE group_kffxp=1 and number_kffxp=260 and xnum_kffxp <> 2147483648
ORDER BY 1,2;

    Extent         AU       Disk
---------- ---------- ----------
         0        668          3
         0        671          1
         0        672          0
         1        669          3
         1        673          0
         1        675          2
         2        672          1
         2        674          0
         2        676          2
...
        14        681          1
        14        683          0
        14        685          2
        15        679          3
        15        682          1
        15        684          0

48 rows selected.

We see that there are 48 physical extents allocated for this file and that the file is triple mirrored. The following query will give me disk names:

SQL> SELECT disk_number, name
FROM v$asm_disk
WHERE group_number=1
ORDER BY 1;

DISK_NUMBER NAME
----------- --------------------------------
          0 ASMDISK1
          1 ASMDISK2
          2 ASMDISK3
          3 ASMDISK4

Let's now use kfed to look at the file directory entry for this file. Remember, that will be block 260, i.e. block 4 (260-256) in extent 1 of the file directory. Extent 1 is in AU 44 on disk 3 and also mirrored in AU 47 on disk 2 and AU 48 on disk 0. We only need to look at one of those. Let's look at block 4 in AU 48, on disk 0:

$ kfed read /dev/oracleasm/disks/ASMDISK1 aun=48 blkn=4 | 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:                     260 ; 0x004: blk=260
...
kfffdb.node.incarn:           769030435 ; 0x000: A=1 NUMM=0x16eb3c91
kfffdb.node.frlist.number:   4294967295 ; 0x004: 0xffffffff
kfffdb.node.frlist.incarn:            0 ; 0x008: A=0 NUMM=0x0
kfffdb.hibytes:                       0 ; 0x00c: 0x00000000
kfffdb.lobytes:                 9748480 ; 0x010: 0x0094c000
kfffdb.xtntcnt:                      48 ; 0x014: 0x00000030
kfffdb.xtnteof:                      48 ; 0x018: 0x00000030
kfffdb.blkSize:                   16384 ; 0x01c: 0x00004000
kfffdb.flags:                        19 ; 0x020: O=1 S=1 S=0 D=0 C=1 I=0 R=0 A=0
kfffdb.fileType:                      1 ; 0x021: 0x01
...
kfffde[0].xptr.au:                  672 ; 0x4a0: 0x000002a0
kfffde[0].xptr.disk:                  0 ; 0x4a4: 0x0000
kfffde[0].xptr.flags:                 0 ; 0x4a6: L=0 E=0 D=0 S=0
kfffde[0].xptr.chk:                 136 ; 0x4a7: 0x88
kfffde[1].xptr.au:                  671 ; 0x4a8: 0x0000029f
kfffde[1].xptr.disk:                  1 ; 0x4ac: 0x0001
kfffde[1].xptr.flags:                 0 ; 0x4ae: L=0 E=0 D=0 S=0
kfffde[1].xptr.chk:                 182 ; 0x4af: 0xb6
kfffde[2].xptr.au:                  668 ; 0x4b0: 0x0000029c
kfffde[2].xptr.disk:                  3 ; 0x4b4: 0x0003
kfffde[2].xptr.flags:                 0 ; 0x4b6: L=0 E=0 D=0 S=0
kfffde[2].xptr.chk:                 183 ; 0x4b7: 0xb7
...
kfffde[47].xptr.au:                 684 ; 0x618: 0x000002ac
kfffde[47].xptr.disk:                 0 ; 0x61c: 0x0000
kfffde[47].xptr.flags:                0 ; 0x61e: L=0 E=0 D=0 S=0
kfffde[47].xptr.chk:                132 ; 0x61f: 0x84
...

The firt part of the kfed output (kfbh fields) confirm this is a file directoy block (kfbh.type=KFBTYP_FILEDIR) for file 260 (kfbh.block.blk=260).

The second part of the kfed output (kfffdb fields) shows:
  • File incarnation number (kfffdb.node.incarn=769030435), which is part of the file name
  • File size (kfffdb.lobytes=9748480)
  • Extent count (kfffdb.xtntcnt=48)
  • File block size (kfffdb.blkSize=16384)
  • File type (kfffdb.fileType=1), which means the database control file

The third part of the output (kfffde fields) shows the physical extent distribution that agrees with the query output from X$KFFXP:

Extent 0 (kfffde[0]) is in allocation unit 672 (kfffde[0].xptr.au=672), on disk 0 (kfffde[0].xptr.disk=0)
Extent 1 (kfffde[1]) is in allocation unit 671 (kfffde[1].xptr.au=671), on disk 1 (kfffde[1].xptr.disk=1)
Extent 2 (kfffde[2]) is in allocation unit 668 (kfffde[2].xptr.au=668), on disk 3 (kfffde[2].xptr.disk=3)
...
Extent 47 (kfffde[47]) is in allocation unit 684 (kfffde[47].xptr.au=684), on disk 0 (kfffde[47].xptr.disk=0)

File directory entries for large files

NOTE: Large files in this context are files with more than 60 extents.

Query the database to find some large files:

SQL> SELECT name, bytes/1024/1024 "Size (MB)"
FROM v$datafile;

NAME                                          Size (MB)
-------------------------------------------- ----------
+DATA/br/datafile/system.256.769030243              720
+DATA/br/datafile/sysaux.257.769030245              590
+DATA/br/datafile/undotbs1.258.769030245            105
+DATA/br/datafile/users.259.769030245                 5
+DATA/br/datafile/example.269.769030517         345.625

Directly addressed extents

For an example of the file directory entry for a large file, we will look at the system datafile (system.256.769030243). Note the datafile ASM file number (256) and size (720 MB).

SQL> SELECT xnum_kffxp "Extent", au_kffxp "AU", disk_kffxp "Disk"
x$kffxp
WHERE group_kffxp=1 and number_kffxp=256 and xnum_kffxp <> 2147483648
ORDER BY 1,2;

    Extent         AU       Disk
---------- ---------- ----------
         0         42          1
         0         48          2
         1         43          1
         1         49          0
         2         44          1
         2         45          3
...
       720       1111          1
       720       1119          2

1442 rows selected.

We see that there are 1442 physical extents allocated for this file.

Let's now use kfed to look at the file directory entry for this file. Remember, that will be block 256, i.e. block 0 (256-256) in extent 1 of the file directory. Let's look at block 0 in AU 48, on disk 0:

$ kfed read /dev/oracleasm/disks/ASMDISK1 aun=48 blkn=0 | more

kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            4 ; 0x002: KFBTYP_FILEDIR
...
kfffdb.node.incarn:           769030243 ; 0x000: A=1 NUMM=0x16eb3c31
kfffdb.node.frlist.number:   4294967295 ; 0x004: 0xffffffff
kfffdb.node.frlist.incarn:            0 ; 0x008: A=0 NUMM=0x0
kfffdb.hibytes:                       0 ; 0x00c: 0x00000000
kfffdb.lobytes:               754982912 ; 0x010: 0x2d002000
kfffdb.xtntcnt:                    1442 ; 0x014: 0x000005a2
kfffdb.xtnteof:                    1442 ; 0x018: 0x000005a2
kfffdb.blkSize:                    8192 ; 0x01c: 0x00002000
kfffdb.flags:                        17 ; 0x020: O=1 S=0 S=0 D=0 C=1 I=0 R=0 A=0
kfffdb.fileType:                     12 ; 0x021: 0x0c
...
kfffde[0].xptr.au:                   48 ; 0x4a0: 0x00000030
kfffde[0].xptr.disk:                  2 ; 0x4a4: 0x0002
kfffde[0].xptr.flags:                 0 ; 0x4a6: L=0 E=0 D=0 S=0
kfffde[0].xptr.chk:                  24 ; 0x4a7: 0x18
kfffde[1].xptr.au:                   42 ; 0x4a8: 0x0000002a
kfffde[1].xptr.disk:                  1 ; 0x4ac: 0x0001
kfffde[1].xptr.flags:                 0 ; 0x4ae: L=0 E=0 D=0 S=0
kfffde[1].xptr.chk:                   1 ; 0x4af: 0x01
kfffde[2].xptr.au:                   49 ; 0x4b0: 0x00000031
kfffde[2].xptr.disk:                  0 ; 0x4b4: 0x0000
kfffde[2].xptr.flags:                 0 ; 0x4b6: L=0 E=0 D=0 S=0
...
kfffde[60].xptr.au:                  58 ; 0x680: 0x0000003a
kfffde[60].xptr.disk:                 1 ; 0x684: 0x0001
kfffde[60].xptr.flags:                0 ; 0x686: L=0 E=0 D=0 S=0
kfffde[60].xptr.chk:                 17 ; 0x687: 0x11
kfffde[61].xptr.au:                  64 ; 0x688: 0x00000040
kfffde[61].xptr.disk:                 0 ; 0x68c: 0x0000
kfffde[61].xptr.flags:                0 ; 0x68e: L=0 E=0 D=0 S=0
kfffde[61].xptr.chk:                106 ; 0x68f: 0x6a
kfffde[62].xptr.au:                  63 ; 0x690: 0x0000003f
kfffde[62].xptr.disk:                 2 ; 0x694: 0x0002
kfffde[62].xptr.flags:                0 ; 0x696: L=0 E=0 D=0 S=0
kfffde[62].xptr.chk:                 23 ; 0x697: 0x17
kfffde[63].xptr.au:          4294967295 ; 0x698: 0xffffffff
kfffde[63].xptr.disk:             65535 ; 0x69c: 0xffff
kfffde[63].xptr.flags:                0 ; 0x69e: L=0 E=0 D=0 S=0
...

Extents 0-59 (kfffde[0]-kfffde[59]) are called directly addressed as they point directly to data extents. Extents from kfffde[60] and on, are called indirectly addressed as they point to extents holding the information about the rest of the file extents.

Indirectly addressed extents

Let's look at allocation unit 58 (kfffde[60].xptr.au=58) on disk 1 (kfffde[60].xptr.disk=1).

$ kfed read /dev/oracleasm/disks/ASMDISK2 aun=58 | more
kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                           12 ; 0x002: KFBTYP_INDIRECT
...
kffixe[0].xptr.au:                   59 ; 0x00c: 0x0000003b
kffixe[0].xptr.disk:                  3 ; 0x010: 0x0003
kffixe[0].xptr.flags:                 0 ; 0x012: L=0 E=0 D=0 S=0
kffixe[0].xptr.chk:                  18 ; 0x013: 0x12
kffixe[1].xptr.au:                   64 ; 0x014: 0x00000040
kffixe[1].xptr.disk:                  2 ; 0x018: 0x0002
kffixe[1].xptr.flags:                 0 ; 0x01a: L=0 E=0 D=0 S=0
kffixe[1].xptr.chk:                 104 ; 0x01b: 0x68
kffixe[2].xptr.au:                   59 ; 0x01c: 0x0000003b
kffixe[2].xptr.disk:                  1 ; 0x020: 0x0001
kffixe[2].xptr.flags:                 0 ; 0x022: L=0 E=0 D=0 S=0
kffixe[2].xptr.chk:                  16 ; 0x023: 0x10
...

We see that this is indeed an indirect extent block (kfbh.type=KFBTYP_INDIRECT) and that it holds the extent distribution information for the rest of our system datafile.

Conclusion

ASM file directory maintains the information about all files in a disk group - both internal, ASM metadata files, and user or database files. The information about user (database) files is externalized via V$ASM_FILE view but can also be accessed via fixed view X$KFFXP and kfed utility.