Operating System - OpenVMS
Showing results for 
Search instead for 
Did you mean: 

Possible to read deleted/erased records from a relative record file?

Mark Corcoran
Frequent Advisor

Possible to read deleted/erased records from a relative record file?

A while ago, there was a problem with one of our systems whereby restarting of processes and even a reboot didn't fix a problem, and it was only once a new version of a relative file was created (it's used as a kind of on-disk queue file), that things started working again.

It was only some processes that appeared to have a problem with the file, but others were fine (I don't know if the problem-having processes were readers, writers or updaters to the file).

Someone took a copy of the file at the time, though unfortunately, this was a BACKUP/IGN=INTER whilst it was still in use by other processes, so it's not an exact replica of the problem file.

As I've indicated, the file is an RMS relative file, and from the limited information I have been able to glean about relative files, it appears that:

a) they have a mysterious 1-block header; absolutely no idea what is contained in this

b) given that this fie contains fixed-length records, after the 1-block header, you any number of fixed-length records, each of which are preceded by a single status byte that indicates whether or not the record is deleted (I can't find out any information on valid values for this byte, so I've no way of telling if RMS differentiates between "never been used" and "deleted/erased")

c) consequently the file would have 512-byte header, (1 byte + fixed-length_record_size)*no_of_records_ever_created_in_the_file

'c' above, is an approximation, because you then have to take "buckets" into account.

What I wanted to do, was to process this file, to see if any of the data contained within the records, was cr*p, to try and ascertain why there might've been a problem (the supplier doesn't have resource to look at this until January some time).

However, I encountered a few problems:
1) With the exception of the first record after the 512-byte header, it seems like all of the other records in the file are in a "deleted/;erased" state

2) This means that you can't DUMP /RECORD=(START=x,COUNT=y) other than where START=1,COUNT=1

3) I was under the impression that in the relative file, records would be laid out in record number order, so record 2 would also be the 2nd record in the file after the header block, irrespective of whether or not it had been deleted (i.e. if you have 3 records in the file, and delete record 2, then record 3 isn't suddenly renumbered to record #2).

However, when attempting to do a DUMP /RECORD=(START=2,COUNT=1), it seems like DUMP is scanning the entire file to find record #2 (i.e. it's as if the record number - in addition to a status byte - is present in the file, and that DUMP has to examine each record to see whether or not the record number embedded within the record matches the /START= value).

As I understood it, it was like having an array on disk, so if you specified record #2, then you'd go to array[2] position on disk, which - given that the records are fixed size - should be virtually instantaneous.

Any ideas?

4) I also tried knocking up a program that called the rather archaic code which (eventually) calls RMS to read records from the file; it encounters pretty much the same scenario as #3

5) I finally decided that I would just try a simple fopen(filename, "rb") and then fread() calls; this works for reading the first 513 bytes (header block plus record status byte for record #1), but the freadto read the first 1024-byte record just "hangs" (well, actually, it doesn't - repeated CTRL-T shows the I/O count going up, so I'm guessing that something like #3 is happening.

Does anyone have any thoughts on how to convert a relative file of deleted fixed-length records to a not-deleted state (I did try looking at HELP CONVERT, but nothing jumped out at me), so I can process them and see if there's anything wrong with any of the records?

Also, any pointers to a better understanding of how the files are physically laid out on-disk (and maybe an idea of the status byte values, and what this 512-byte header is that relative files appear to have?) - from the CD condist and comp.os.vms postings, I couldn't really find anything.

I was sure that I had seen somewhere, where this kind of stuff was laid out diagrammatically, but if it is, it's not something I can find (maybe VMS file internals manual has it, but it's no longer available (for new supply; not sure if second hand ones I've seen are still relevant, or are not out of date (the 1990 edition)).

The few postings on comp.os.vms that even mention the status byte indicate that "users" need not concern themselves with its value (well, arguably, in normal circumstances, perhaps yes; what if the value were set to be something "invalid" that would then cause RMS problems, however?

[The above probably doesn't format correctly; it was extracted from an M$ Outlook email]

Again, any suggestions/help much appreciated.

Volker Halle
Honored Contributor

Re: Possible to read deleted/erased records from a relative record file?


you can use ANAL/RMS/INTERACTIVE filename to play around and look at the various RMS data structures of the file. Use DOWN, UP, NEXT commands to navigate.

Volker Halle
Honored Contributor

Re: Possible to read deleted/erased records from a relative record file?


it's really easy ;-)

$ ANAL/RMS/INTER filename

enter 4x DOWN to reach the first record in the relative file. Then type NEXT to go to the next record. If a record does exist, it's contents will be dumped on your screen. It you hit a deleted record, it shows the cell control flags as:

RECORD CELL (VBN 6, offset %X'0000'):

Cell Control Flags:
(3) DLC$V_REC 1

You could then issue> DUMP 6 (=VBN) to dump the contents of the block this record is in. Add the above record offset to locate the bytes of this deleted record.

Hein van den Heuvel
Honored Contributor

Re: Possible to read deleted/erased records from a relative record file?

Relative file are about as simple as they get, but folks manage to not figure them out regardless.

Like indexed file they have a sequential and keyed access mode.
DUMP just uses SEQ access mode, counting (valid) records, whether the file is sequential, relative or indexed.
When you DUMP /STA=4 for an indexed file it starts at the fourth record, not the record with key=4.

NEVER use C IO calls to try figure out what is happening to RMS file.
Just call RMS directly (from C or MACRO or COBOL or whatever).
Or use DCL!.
Here is an example of DCL in KEYED mode:

$ convert/fdl="fil; org rel; rec; siz 200" sys$input tmp.rel
$ dump/rec=(cou=1,sta=2) tmp.rel
Record number 2 (00000002), 4 (0004) bytes, RFA(0002,0000,0000)
746F6F6E noot............................ 000000
$ open/read/write file tmp.rel
$ key="1234" ! Make sure it is a 4 byte variable
$ key[0,32]=2 ! Pick a value, any value that does not have a byte that looks like a quote
$ read/key=&key/del file record ! Use post-poned substitution operator
$ show symb record
RECORD = "noot"
$ close file
$ reca dump
$ dump/rec=(cou=1,sta=2) tmp.rel
Record number 2 (00000002), 5 (0005) bytes, RFA(0003,0000,0000)
20 7365696D mies ........................... 000000

As Volker points out, use ANAL/RMS/INT to egt an idea how it all looks like and what control bytes and blocks which are not visible to the application are used.

The defintion can be found as:

$ libr /out=tt:/extr=$plgdef sys$library:lib.mlb
$ libr /out=tt:/extr=$dlcdef sys$library:lib.mlb

The only relevant pieces being pretty much
the DELETED and REC(ord_valid) bits and


Good luck!
Hein van den Heuvel
HvdH Performance Consulting.
Hein van den Heuvel
Honored Contributor

Re: Possible to read deleted/erased records from a relative record file?

To standard too to 'see' deleted records is DUMP/BLOCK=(cou=x,sta=y).
You'll have to do the de-bucketing yourself.

That is:
recs_per_bucket = int ( 512 * bks / ( mrs + 1 )
bucket_number = int ( record_number / recs_per_bucket )
bucket_start_vbn = 1 + bucket_number * bks

Record_start_byte = (mrs + 1) * mod ( record_number, recs_per_bucket )

If you want to do this ins a program then your best bet is to use SYS$READ or SYS$QIO with the formula above.

Or you could use my dinky STRINGS tools and replace its $GET with $READ.

Or... take a copy and lie about ti:
Then you can dump/recor or use c or dcl sequential reads and de-block the potential record yourself.

But before you blow several days on this, you may want to consider enlisting a professional resource to help you with this.

Hein van den Heuvel
HvdH Performance Engineering and RMS Hacking.

Hein van den Heuvel
Honored Contributor

Re: Possible to read deleted/erased records from a relative record file?

Ooops, sorry 'bout the multipel replies.

One last bit of free advice...

>> BACKUP/IGN=INTER whilst it was still in use by other processes, so it's not an exact replica of the problem file.

Yeah there is a risk, but typically relative file are accessed in shared mode and RMS will write-through any changes requested. The odds to catch it 'mid flight' are pretty darn slim. Furthermore, unlike an indexed file, the structure is stays exactly the same, so you will get a good copy but perhaps stale. You just do not know the time (before or after that 'last' update).


Honored Contributor

Re: Possible to read deleted/erased records from a relative record file?

>The odds to catch it 'mid flight' are pretty darn slim.

True. Those odds Hein refers to here, for those of you placing your wagers, apply to single isolated writes involving single files.

These same odds do not apply to sequences of non-careful writes, nor for multi-file write operations. YMMV.

One of the more interesting and degenerate cases of the single write case involves a single multi-block write that encounters a power loss with the data in flight; some StorageWorks shelves will get all that data to disk, and some won't get the full multiple block sequence out. Typically all will get a full data block out, but it won't necessarily be the last full block of the transfer.

We'd all like to see an on-line BACKUP that works reliably. I usually end up coding that into the application; following the model of Rdb and of transactional systems.
Robert Gezelter
Honored Contributor

Re: Possible to read deleted/erased records from a relative record file?


I concur with Hein and Hoff, and then some.

If an RMS Bucket is a single block, the cases are fairly simple.

If there are multiple disk blocks in the bucket, then there are many possibilities.
- the blocks may not be (or been at some time) contiguous, thus the write may have been split.
- checking the first and last blocks of the bucket does not guarantee that the intermediate blocks were written.

Conceptually, when looking at this, one needs to remember about mirror and stripe sets, non-contiguous files, disk defragmenters, and other entities.

There is a LARGE difference between "works much of the time" and "guaranteed". As Hoff said, YMMV (it is also easy to presume incorrectly that something is always true since it is ALMOST always true.

I just dug out my copy of "VMS File Systems Internals" (McCoy, 1990). The RMS Bucket format is not described there.

- Bob Gezelter, http://www.rlgsc.com
John Gillings
Honored Contributor

Re: Possible to read deleted/erased records from a relative record file?


Just an observation... you've posted a few questions recently, and it seems to me the approaches your taking are attempting to solve problems in the most difficult and least likely to succeed way.

In each case you're looking at low level system data structures in the hope that they will reveal a clue as to what's going wrong at an application level.

To me this is a bit like doing a detailed chemical analysis of the fuel to determine why a car won't start, when the real problem is a flat battery.

Rather than diving straight into the bits and bytes, I'd suggest you step back and look at your symptoms from an application perspective.

>It was only some processes that appeared
>to have a problem with the file, but
>others were fine (I don't know if the
>problem-having processes were readers,
>writers or updaters to the file).

Exactly my point! Find out. Was it the readers or writers? What was "the problem"? An error? What was the message? What operation was being attempted? Unless the file was actually corrupt, how is delving into the mysteries of RMS file structures going to help?

Except in highly unusual circumstances, you can assume that RMS and OpenVMS services are working correctly. Always suspect the application first, and even if you think you've eliminated all possible errors, you're probably wrong! If you find yourself reaching for the IDSM or other internals, when you're not writing kernel mode code, you're on the wrong track.

Look at the application.

(in this particular case, if you're using a relative file as a queue, you should have application specific diagnostic tools to do things like examine the queue, insert or delete entries, clear it out, save and restore etc... this is not rocket science, just good engineering practice).
A crucible of informative mistakes