09-Apr-2012

RMS new feature request

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 AM
Tag Set:

Comments are closed