The ASM file number 1 - the ASM File Directory - keeps track of all files in a disk group. As the disk groups are independent storage units, each disk group will have its own ASM file directory.
While this is an internal (ASM metadata) file, it is managed like any other file in the disk group. It will have its own entry in the ASM file directory (yes, pointing to itself), it will be mirrored in a normal and high redundancy disk group and will automatically grow to keep information about new files.
Each ASM 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 has more than 60 extents)
- File creation time-stamp
- File last modification time-stamp
- Pointer to the file name in the ASM Alias Directory
A sequential number is assigned to each new file managed by ASM. That file number corresponds to the block number in the ASM file directory. Thus, block 1 of the ASM 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.
Note that there is no ASM file 0, so block 0 of the ASM file directory is not describing any files.
The ASM file directory and the ASM 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 ASM file directories can be accessed via the V$ASM_FILE view. That view displays one row for every ASM file in every mounted disk group. Note that this view will not show ASM metadata files. The V$ASM_FILE does not have the filename column, so for a meaningful output, we would have to query it together with the V$ASM_ALIAS view.
Here is an example:
SQL> 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
...
34 rows selected.
SQL>
Note that the files in different disk groups can have the same ASM file number.
Locating the ASM file directory
We can query the fixed table X$KFFXP in the ASM instance, to find out which allocation units belong to file 1, in disk group DATA:
SQL> SELECT xnum_kffxp "Virtual extent",
pxn_kffxp "Physical extent",
au_kffxp "Allocation unit",
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;
Virtual extent Physical extent Allocation unit Disk
-------------- --------------- --------------- ----------
0 0 10 0
0 1 10 1
0 2 10 2
1 3 48 2
1 4 46 1
1 5 47 0
6 rows selected.
SQL>
The result shows two things - that the ASM file directory is triple mirrored (note the three physical extents for each virtual extent) and that the current size of the ASM file directory is 2 (virtual) extents.
With the allocation unit size of 1MB and the ASM metadata block size of 4KB, one allocation unit can hold up to 256 directory entries. As numbers 1-255 are reserved for the ASM metadata files, extent 0 will only have enough room for the ASM metadata files. Extent 1 will hold information about next 256 files managed by the 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 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
...
SQL>
As we see my ASM instance is managing a typical set of database files. 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 "File",
block_size "Block size",
block_size*(file_size_blks+1) "File size"
FROM v$controlfile;
File Block size File size
------------------------------------------ ---------- ----------
+DATA/BR/CONTROLFILE/current.262.822925011 16384 17973248
+DATA/BR/CONTROLFILE/current.261.822925013 16384 17973248
SQL>
Let's now look at the ASM file directory entry for ASM file 262 (current.262.822925011). First, we query the X$KFFXP view in the ASM instance, to get the extent and AU distribution:
SQL> SELECT xnum_kffxp "Virtual extent",
pxn_kffxp "Physical extent",
au_kffxp "Allocation unit",
disk_kffxp "Disk"
FROM x$kffxp
WHERE group_kffxp=1 -- Diskgroup 1 (DATA)
and number_kffxp=262 -- File 262 (control file)
and xnum_kffxp <> 2147483648
ORDER BY 1, 2;
Virtual extent Physical extent Allocation unit Disk
-------------- --------------- --------------- ----
0 0 776 3
0 1 778 1
0 2 779 2
1 3 781 0
1 4 777 3
1 5 779 1
2 6 780 2
2 7 780 1
2 8 778 3
...
23 69 795 1
23 70 793 3
23 71 798 0
72 rows selected.
SQL>
We see that there are 24 (virtual) extents allocated for this file and that the file is triple mirrored. The following query gives me the disk numbers and paths for ASM disks in disk group DATA:
SQL> SELECT disk_number, path
FROM v$asm_disk
WHERE group_number=1
ORDER BY 1;
DISK_NUMBER PATH
----------- ---------
0 /dev/sdb1
1 /dev/sdc1
2 /dev/sdd1
3 /dev/sde1
SQL>
Let's now use the kfed tool to look at the ASM file directory entry for this file. Remember, that will be block 262, i.e. block 6 (262-256) in the (virtual) extent 1 of the ASM file directory. The extent 1 is in AU 48 on disk 2, also mirrored in AU 46 on disk 1, and mirrored in AU 47 on disk 0. We only need to look at one of those. Let's look at block 6 in AU 48, on disk 2:
$ kfed read /dev/sdd1 aun=48 blkn=6 | 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: 262 ; 0x004: blk=262
...
kfffdb.node.incarn: 822925011 ; 0x000: A=1 NUMM=0x18866b69
kfffdb.node.frlist.number: 4294967295 ; 0x004: 0xffffffff
kfffdb.node.frlist.incarn: 0 ; 0x008: A=0 NUMM=0x0
kfffdb.hibytes: 0 ; 0x00c: 0x00000000
kfffdb.lobytes: 17973248 ; 0x010: 0x01124000
kfffdb.xtntcnt: 72 ; 0x014: 0x00000048
kfffdb.xtnteof: 72 ; 0x018: 0x00000048
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: 776 ; 0x4a0: 0x00000308
kfffde[0].xptr.disk: 3 ; 0x4a4: 0x0003
kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 S=0
kfffde[0].xptr.chk: 34 ; 0x4a7: 0x22
kfffde[1].xptr.au: 778 ; 0x4a8: 0x0000030a
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: 34 ; 0x4af: 0x22
kfffde[2].xptr.au: 779 ; 0x4b0: 0x0000030b
kfffde[2].xptr.disk: 2 ; 0x4b4: 0x0002
kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 S=0
kfffde[2].xptr.chk: 32 ; 0x4b7: 0x20
...
$
The first part of the kfed output (the kfbh fields) confirm this is an ASM file directory block (kfbh.type=KFBTYP_FILEDIR), for file 262 (kfbh.block.blk=262).
The second part of the kfed output (the kfffdb fields) shows:
- File incarnation number (kfffdb.node.incarn=822925011), which is part of the file name
- File size in bytes (kfffdb.lobytes=17973248)
- Physical extent count (kfffdb.xtntcnt=72)
- File block size in bytes (kfffdb.blkSize=16384)
- File type (kfffdb.fileType=1), i.e. the database control file
The third part of the output (the kfffde fields) shows the physical extent distribution that agrees with the query output from X$KFFXP:
Physical extent 0 is in AU 776 (kfffde[0].xptr.au=776), on disk 3 (kfffde[0].xptr.disk=3)
Physical extent 1 is in AU 778 (kfffde[1].xptr.au=778), on disk 1 (kfffde[1].xptr.disk=1)
Physical extent 2 is in AU 779 (kfffde[2].xptr.au=779), on disk 2 (kfffde[2].xptr.disk=2)
And so on.
File directory entries for large files
NOTE: Large files in this context are the 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
SQL>
Directly addressed extents
For an example of the ASM 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"
FROM 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.
SQL>
We see that there are 1442 physical extents allocated for this file.
Let's now use kfed to look at the ASM file directory entry for this file. Remember, that will be block 256, i.e. block 0 (256-256) in extent 1 of the ASM file directory. Let's look at block 0 in AU 48, on disk 0:
$ kfed read /dev/sdb1 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
...
$
The extents 0-59 (kfffde[0]-kfffde[59]) are called directly addressed as they point directly to data extents. The extents numbers over 59, 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/sdc1 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 the system datafile.
Conclusion
The 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 the database files is externalized via the V$ASM_FILE view.
Thanks Bane. I am glad that I found this blog. Illustration is very good.
ReplyDeleteBy the way I am unclear what 2147483648(xnum_kffxp <> 2147483648) is in your query ? May be it is extent counts ? But why is it needed here ?
-VK
Hi VK,
DeleteI am not sure. I have to say that I blindly copied that query from developers.
That number (2^31) is also seen as the object number in the disk header (kfbh.block.obj=2147483648). About a month ago I had a similar question in a post about ASM file extent map, where in some results we see disk number 65534 and allocation unit number 4294967294. I am yet to solve that mystery...
Cheers,
Bane
Hi VK,
DeleteI was answering the question below and I say that I never answered your question. Extent numbers above 2^31 are for indirect extents. As those do not hold the database data, there is no point including them in the space related queries.
Also see the answer about some other 'large' numbers, in the discussion section of post http://asmsupportguy.blogspot.com.au/2011/06/asm-file-extent-map.html.
Cheers,
Bane
hi, i have an environment with multiple databases supported by a single ASM instance and I want to list all the file allocations in ASM by database. I can do it by going into each database but I was hoping I pull it all from ASM. Any suggestion?
ReplyDeleteThe short answer is that there is no good way to do this from ASM side.
DeleteLong answer is that it depends on what you really want. One way to list files from ASM is with the query from the post about aliases - http://asmsupportguy.blogspot.com.au/2012/01/asm-file-number-6.html.
If you are using Oracle Managed Files (OMF) then the result will probably give you what you want. But you need to keep in mind that a DBA can put a (data)file anywhere they want, so it may not be where you expect it.
You can always check if all files are accounted for with a command like this that will find and display all files in ASM:
$ asmcmd find . "*"
You can also limit the find to a disk group, like this:
$ asmcmd find +DATA "*"
Please let me know if this answers your question.
Cheers,
Bane
perfect. now i just need to get the space allocation for each file. Can i get that from v$asm_file?
ReplyDeleteHi Brian,
DeleteYou can get the size from V$ASM_FILE, so to get what you need you can do something like this:
col "Size (MB)" for 999999.99
select a.NAME "File name", f.BYTES/1024/1024 "Size (MB)"
from V$ASM_ALIAS a, V$ASM_FILE f
where a.FILE_NUMBER = f.FILE_NUMBER;
Cheers,
Bane
hi, i thought it would be as easy as just merging that code with your file 6 code but i seem to be missing something. I suspect it's the connect by? Now I am getting no rows selected. Any thoughts?
ReplyDeleteSELECT
full_path,
dir,
sys,
bytes
FROM
(
SELECT
CONCAT ('+' || gname,
SYS_CONNECT_BY_PATH (aname,
'/')) full_path,
dir,
sys,
bytes
FROM
(
SELECT
g.name gname,
a.parent_index pindex,
a.name aname,
a.reference_index rindex,
a.alias_directory dir,
a.system_created sys,
f.bytes/1024/1024 bytes
FROM
v$asm_alias a,
v$asm_diskgroup g,
v$asm_file f
WHERE a.group_number = g.group_number and a.FILE_NUMBER = f.FILE_NUMBER
)
START WITH
(MOD (pindex,
POWER (2,
24))) = 0 CONNECT BY
PRIOR rindex = pindex
ORDER BY
dir DESC,
full_path ASC
)
Brian, have a look at http://anuj-singh.blogspot.com.au/2012_06_09_archive.html. Anuj has done all the hard work on this.
DeleteCheers,
Bane
works great...thanks!!
ReplyDeleteHi Bane,
ReplyDeleteExtents 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.
How do you know the indirect extents are started from kfffde[60]?
-Peton
Hi Peton,
DeleteSorry if that wasn't clear from the post. That's part of ASM metadata design. First 60 extents (for any file) are directly addressed and the rest are indirectly addressed. So if a file has less than 60 extents all of them are directly addressed. If a file is larger, the first 60 extents will be directly addressed and the rest will be indirectly addressed.
Cheers,
Bane
Thanks Bane for the explanation,I will check it in my environment.Thanks,-Peton
DeleteHey Bane
ReplyDeleteI'm interested in the BLOCK_SIZE column of v$asm_diskgroup. According to the docs, it is the "Automatic Storage Management metadata block size (in bytes)"
I've never seen this show anything else other than 4096. The SECTOR_SIZE column varies depending on the underlying block device's physical and logical sector sizes, but BLOCK_SIZE resolutely stays at 4k.
Does it ever vary?
Correct, this is the ASM metadata block size and it's 4KB in all current ASM versions. That value does not vary.
DeleteCheers,
Bane
please give me correct program in this .asm file
ReplyDeleteORG 0000H
BSF TRISB,2
CLRF TRISD
AGAIN BTFSS PORTB,2
BRA OVER
MOVLW A'Y'
MOVWF PORTD
GOTO AGAIN
OVER MOVLW A'N'
MOVWF PORTD
GOTO AGAIN
END