Back in the dim dark days when disk was expensive and small, VMS had the concept of volume sets. This was a method whereby you could "bind" two or more disks into a loosely coupled set to store files that were larger than either physical disk.
Volume sets have fallen out of favour over time as disks have become larger, things like RAID have allowed us to combine physical disks into larger disks, and OpenVMS 8.4 support of 2 TiB disks. However, there's one thing that still requires as input an RVN (Relative Volume Number): areas in RMS indexed files.
Before you read on, please be aware that the downside of managing bound volume sets usually outweighs their benefits, Hoff has an article discussing some of the drawbacks. Please understand what you're doing before you do it, particularly in a production environment.
Having said that, wouldn't it be nice if the allocation XAB (and the assocated FDL clauses) allowed you to place RMS areas on different disk drives without those disks being in a volume set?
Of course, I want this feature so that I can place index areas on an SSD and hence justify the expense of buying some :-)
If you'd like to see an example of the currently supported way that this works, and what I'd like as a new feature, read on.
You can construct a volume set from differently sized disks. In the examples here, I'll demonstrate with LD disks, but imagine the speed of RMS index lookups if LDA1 was an SSD.
$ ld create disk1.dsk/size=5000
$ ld create disk2.dsk/size=20000
$ ld connect disk1.dsk lda1:
$ ld connect disk2.dsk lda2:
$ init/sys/nohigh/noerase lda1: disk1
$ init/sys/nohigh/noerase lda2: disk2
$ mount/bind=test lda1:,lda2: disk1,disk2 test
%MOUNT-I-MOUNTED, DISK1 mounted on _$6$LDA1: (xxxxxx)
%MOUNT-I-MOUNTED, DISK2 mounted on _$6$LDA2: (xxxxxx)
$ show log test
"TEST" = "$6$LDA1:" (LNM$JOB_8923B000)
$ show dev/full test
Disk $6$LDA1: (NODE), device type Foreign disk type 1, is online, allocated,
deallocate on dismount, mounted, file-oriented device, shareable.
Error count 0 Operations completed 760
Owner process "xxxxxxxxxxxxxxx" Owner UIC [xxxxxx,xxxxxx]
Owner process ID 250C347D Dev Prot S:RWPL,O:RWPL,G:R,W
Reference count 2 Default buffer size 512
Total blocks 5000 Sectors per track 8
Total cylinders 79 Tracks per cylinder 8
Logical Volume Size 5000 Expansion Size Limit 8192
Allocation class 6
Volume label "DISK1" Relative volume number 1
Cluster size 1 Transaction count 1
Free blocks 4899 Maximum files allowed 1250
Extend quantity 5 Mount count 1
Mount status Process Cache name "_DSA301:XQPCACHE"
Extent cache size 64 Maximum blocks in extent cache 489
File ID cache size 64 Blocks in extent cache 490
Quota cache size 0 Maximum buffers in FCP cache 7241
Volume owner UIC [1,1] Vol Prot S:RWCD,O:RWCD,G:RWCD,W:RWCD
Volume Status: ODS-2, subject to mount verification, write-back caching
enabled.
Members of this volume set are $6$LDA1: (rvn 1), $6$LDA2: (rvn 2).
Disk $6$LDA2: (NODE), device type Foreign disk type 1, is online, allocated,
deallocate on dismount, mounted, file-oriented device, shareable.
Error count 0 Operations completed 518
Owner process "xxxxxxxxxxxxxxx" Owner UIC [xxxxxx,xxxxxx]
Owner process ID 250C347D Dev Prot S:RWPL,O:RWPL,G:R,W
Reference count 2 Default buffer size 512
Total blocks 20000 Sectors per track 11
Total cylinders 152 Tracks per cylinder 12
Logical Volume Size 20000 Expansion Size Limit 20480
Allocation class 6
Volume label "DISK2" Relative volume number 2
Cluster size 1 Transaction count 1
Free blocks 19896 Maximum files allowed 5000
Extend quantity 5 Mount count 1
Mount status Process Cache name "_DSA301:XQPCACHE"
Extent cache size 64 Maximum blocks in extent cache 1989
File ID cache size 64 Blocks in extent cache 0
Quota cache size 0 Maximum buffers in FCP cache 7241
Volume owner UIC [1,1] Vol Prot S:RWCD,O:RWCD,G:RWCD,W:RWCD
Volume Status: ODS-2, subject to mount verification, write-back caching
enabled.
Members of this volume set are $6$LDA1: (rvn 1), $6$LDA2: (rvn 2).
$
Here we have created a two member volume set. Note the relative volume numbers of 1 and 2.
Let's create a multi-area indexed file, with an area on each volume of the volume set:
$ type create.c
#define __NEW_STARLET
#include <stdio.h>
#include <stdlib.h>
#include <ssdef.h>
#include <stsdef.h>
#include <string.h>
#include <rms.h>
#include <lib$routines.h>
#include <starlet.h>
#define errchk_sig(arg) if (!$VMS_STATUS_SUCCESS(arg)) (void)lib$signal(arg);
int main (void) {
static struct {
unsigned short int key;
char data[18];
} record;
static int r0_status;
static struct FAB fab;
static struct RAB rab;
static struct XABALL xaball0;
static struct XABALL xaball1;
static struct XABKEY xabkey;
static char filename[] = "TEST:[000000]T.ISM";
fab = cc$rms_fab;
fab.fab$b_fns = strlen (filename);
fab.fab$l_fna = filename;
fab.fab$b_org = FAB$C_IDX;
fab.fab$w_mrs = 20;
fab.fab$b_rat = FAB$M_CR;
fab.fab$b_rfm = FAB$C_FIX;
fab.fab$l_xab = &xabkey;
/*
** Note the key specifies ian (index area number) is zero, and dan (data
** area number) is 1.
*/
xabkey = cc$rms_xabkey;
xabkey.xab$b_dan = 1;
xabkey.xab$b_dtp = XAB$C_BN2;
xabkey.xab$b_ian = 0;
xabkey.xab$w_pos0 = 0;
xabkey.xab$b_siz0 = 2;
xabkey.xab$l_nxt = &xaball0;
/*
** Define area 0 on relative volume number 1
*/
xaball0 = cc$rms_xaball;
xaball0.xab$l_alq = 1000;
xaball0.xab$b_aid = 0;
xaball0.xab$b_aln = XAB$C_CYL;
xaball0.xab$w_vol = 1;
xaball0.xab$l_nxt = &xaball1;
/*
** Define area 1 on relative volume number 2
*/
xaball1 = cc$rms_xaball;
xaball1.xab$l_alq = 2000;
xaball1.xab$b_aid = 1;
xaball1.xab$b_aln = XAB$C_CYL;
xaball1.xab$w_vol = 2;
/*
** Define the record access block
*/
rab = cc$rms_rab;
rab.rab$l_fab = &fab;
rab.rab$l_rbf = (char *)&record;
rab.rab$w_rsz = sizeof (record);
rab.rab$l_kbf = (char *)&record.key;
rab.rab$b_ksz = sizeof (record.key);
/*
** Create the file and insert a record.
*/
r0_status = sys$create (&fab);
errchk_sig (r0_status);
r0_status = sys$connect (&rab);
errchk_sig (r0_status);
for (int i = 0; i < sizeof (record.data); i++) {
record.data[i] = '*';
}
record.key = 1;
r0_status = sys$put (&rab);
errchk_sig (r0_status);
r0_status = sys$close (&fab);
errchk_sig (r0_status);
}
$ cc create
$ link create
$ run create
$
So this accomplishes what we want; index on LDA1 and data on LDA2. But it'd be really nice to have those area definitions read:
static char indexarea[] = "INDEX;[DIR]T.INDEX";
static char filename[] = "DATA:[DIR]T.DATA";
/*
** The default area. Default to the FAB (or NAM) filename.
*/
xaball0 = cc$rms_xaball;
xaball0.xab$l_alq = 1000;
xaball0.xab$b_aid = 0;
xaball0.xab$l_nxt = &xaball1;
/*
** Define area 1 on a completely different disk with a different filename.
** ans = area name size (equivalent of fns)
** ana = area name address (equivalent of fna)
*/
xaball1 = cc$rms_xaball;
xaball1.xab$l_alq = 2000;
xaball1.xab$b_aid = 1;
xaball1.xab$w_ans = strlen (indexarea);
xaball1.xab$l_ans = indexarea;
This would accomplish the same thing without requiring bound volume sets.
Posted at April 9, 2012 10:12 AMComments are closed