ASM Active Change Directory
When the ASM instance needs to make an atomic change to multiple metadata blocks, a log record is written into the ASM active change directory (ACD), which is the ASM metadata file number 3. These log records are written in a single I/O.
The ACD is divided into chunks or threads, and each running ASM instance has its own 42 MB chunk. When a disk group is created, a single chunk is allocated for the ACD. As more instances mount the disk group, the ACD grows (by 42 MB) to accommodate every running instance with its own ACD chunk.
The ACD components are:
- ACDC - ACD checkpoint
- ABA - ACD block address
- LGE - ACD redo log record
- BCD - ACD block change descriptor
Locating ASM active change directory
We can query the X$KFFXP to find the ACD allocation units. The ACD is ASM file number 3 hence number_kffxp=3 in our query:
SQL> SELECT x.xnum_kffxp "Extent",
x.au_kffxp "AU",
x.disk_kffxp "Disk #",
d.name "Disk name"
FROM x$kffxp x, v$asm_disk_stat d
WHERE x.group_kffxp=d.group_number
and x.disk_kffxp=d.disk_number
and x.group_kffxp=1
and x.number_kffxp=3
ORDER BY 1, 2;
Extent AU Disk # Disk name
---------- ---------- ---------- ---------
0 4 0 ASMDISK5
1 2 1 ASMDISK6
2 5 0 ASMDISK5
...
39 21 1 ASMDISK6
40 24 0 ASMDISK5
41 22 1 ASMDISK6
42 rows selected.
SQL>
The query returned 42 rows, i.e. 42 allocation units. As the allocation unit size for this disk group is 1MB, that means the total size of the ACD is 42 MB.
If I recreate the disk group with the larger allocation unit size, say 4 MB, we should still end up with a 42 MB ACD. Let's have a look:
SQL> create diskgroup RECO external redundancy
disk 'ORCL:ASMDISK5', 'ORCL:ASMDISK6'
attribute 'au_size'='4M';
Diskgroup created.
SQL>
Now the same query from X$KFFXP and V$ASM_DISK_STAT returns 11 rows, showing that the ACD size is still 42 MB:
SQL> SELECT x.xnum_kffxp "Extent"...
Extent AU Disk # Disk name
---------- ---------- ---------- ---------
0 3 1 ASMDISK6
1 3 0 ASMDISK5
2 4 1 ASMDISK6
...
10 8 1 ASMDISK6
11 rows selected.
SQL>
Closer look at ASM active change directory
Let's look at the ACD using the kfed utility. The last query shows that the ACD starts at AU 3 on disk ASMDISK6. Note that with the allocation unit size of 4 MB, I have to specify ausz=4m on the kfed command line:
$ kfed read /dev/oracleasm/disks/ASMDISK6 ausz=4m aun=3 | more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 7 ; 0x002: KFBTYP_ACDC
...
kfracdc.eyec[0]: 65 ; 0x000: 0x41
kfracdc.eyec[1]: 67 ; 0x001: 0x43
kfracdc.eyec[2]: 68 ; 0x002: 0x44
kfracdc.eyec[3]: 67 ; 0x003: 0x43
kfracdc.thread: 1 ; 0x004: 0x00000001
kfracdc.lastAba.seq: 4294967295 ; 0x008: 0xffffffff
kfracdc.lastAba.blk: 4294967295 ; 0x00c: 0xffffffff
kfracdc.blk0: 1 ; 0x010: 0x00000001
kfracdc.blks: 11263 ; 0x014: 0x00002bff
kfracdc.ckpt.seq: 2 ; 0x018: 0x00000002
kfracdc.ckpt.blk: 2 ; 0x01c: 0x00000002
kfracdc.fcn.base: 16 ; 0x020: 0x00000010
kfracdc.fcn.wrap: 0 ; 0x024: 0x00000000
kfracdc.bufBlks: 512 ; 0x028: 0x00000200
kfracdc.strt112.seq: 0 ; 0x02c: 0x00000000
kfracdc.strt112.blk: 0 ; 0x030: 0x00000000
$
The output shows that this is indeed an ACD block (kfbh.type=KFBTYP_ACDC). The only interesting piece of information here is kfracdc.thread=1, which means that this ACD belong to ASM instance 1. In a cluster, this would match the ASM instance number.
That was block 0, the beginning of the ACD. Let's now look at block 1 - the actual ACD data.
$ kfed read /dev/oracleasm/disks/ASMDISK6 ausz=4m aun=3 blkn=1 | more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 8 ; 0x002: KFBTYP_CHNGDIR
...
kfracdb.lge[0].valid: 1 ; 0x00c: V=1 B=0 M=0
kfracdb.lge[0].chgCount: 1 ; 0x00d: 0x01
kfracdb.lge[0].len: 52 ; 0x00e: 0x0034
kfracdb.lge[0].kfcn.base: 13 ; 0x010: 0x0000000d
kfracdb.lge[0].kfcn.wrap: 0 ; 0x014: 0x00000000
kfracdb.lge[0].bcd[0].kfbl.blk: 0 ; 0x018: blk=0
kfracdb.lge[0].bcd[0].kfbl.obj: 4 ; 0x01c: file=4
kfracdb.lge[0].bcd[0].kfcn.base: 0 ; 0x020: 0x00000000
kfracdb.lge[0].bcd[0].kfcn.wrap: 0 ; 0x024: 0x00000000
kfracdb.lge[0].bcd[0].oplen: 4 ; 0x028: 0x0004
kfracdb.lge[0].bcd[0].blkIndex: 0 ; 0x02a: 0x0000
kfracdb.lge[0].bcd[0].flags: 28 ; 0x02c: F=0 N=0 F=1 L=1 V=1 A=0 C=0
kfracdb.lge[0].bcd[0].opcode: 212 ; 0x02e: 0x00d4
kfracdb.lge[0].bcd[0].kfbtyp: 9 ; 0x030: KFBTYP_COD_BGO
kfracdb.lge[0].bcd[0].redund: 17 ; 0x031: SCHE=0x1 NUMB=0x1
kfracdb.lge[0].bcd[0].pad: 63903 ; 0x032: 0xf99f
kfracdb.lge[0].bcd[0].KFRCOD_CRASH: 1 ; 0x034: 0x00000001
kfracdb.lge[0].bcd[0].au[0]: 8 ; 0x038: 0x00000008
kfracdb.lge[0].bcd[0].disks[0]: 0 ; 0x03c: 0x0000
...
$
We see that the ACD block 1 is of type KFBTYP_CHNGDIR, and contains the elements of kfracdb.lge[i] structure - the ASM redo records. Some of the things of interest here are the operation being performed (opcode) and the operation type (kfbtyp). None of this is very useful outside of the ACD context, so we will leave it at that.
Conclusion
This is an informational post only, to complete the ASM metadata story, as there are no practical benefits of understanding the inner works of the ASM active change directory.