MFS PROGRAMMING & USAGE
Published By | Date | Version | Knowledge Level | Keywords |
---|---|---|---|---|
Revelation Technologies | 14 NOV 1989 | 2.X | EXPERT | %RECORDS%, @-variables, @LIST.ACTIVE, @NEXT.FS, sample, program, Next, Aborting, Disabling, Accessing, file+, also, Calling,, Direct, call, different, files, Accounts,, Non-SYSPROG, Arguments, modifying+, names, Assembly, language, Attaching, after, changing, file, handle, installation, using, volume, name, Audit, trail, calling, system, argument, during, FLUSH, INSTALL, BFS,, definition, BFS-bound, Branching+, Btree, index, Buffers, caching, Bypassing, with, direct, calls, Caching, Calling, directly, from, R/BASIC, next, list, CASE, statement, Cataloging, Changing, CLEARSELECT, CODE, Compatibility, Compiling, Compression, CREATE.FILE, CREATE.MEDIA, Current, accessing, Cursors, Data, passing, De-installing, object, code, Debugger, Debugging,during, development, Decryption, Encryption, DELETE.FILE, Detaching, DICT.MFS, Dictionary, problems, with+, current, Direction,READNEXT, function+, Dispatching+, Environmental, Bond, Example |
MFS's - PART II
File Operation Logic
Once the dispatch operation has branched to the proper logic, the MFS can examine or manipulate the arguments available to that operation. It is at this point that the MFS accomplishes the tasks it was written to perform.
In a compression MFS, for example, the developer's logic would be concentrated under the labels for READ.RECORD and WRITE.RECORD. When the MFS has branched to the write logic, the developer's routines can compress the record passed to the MFS. During a read, the MFS branches to a different location, and the developer's code can then decompress the record.
Call to Next MFS
Under most circumstances, when an MFS has finished, it calls the next filing system, passing it all arguments, including those that have been modified. The next filing system operates on those arguments as if they had come directly from R/BASIC.
The next filing system may be the BFS, or it might be an additional MFS. If there is another MFS installed on the file, the current MFS calls the next MFS. If there are no more MFSs for the file, the MFS calls the BFS directly.
BFS Argument
The BFS argument (the second argument passed to the MFS) contains a list of all the MFSs and of the BFS for the file being accessed. If a Linear Hash dictionary file were indexed, for instance, the BFS argument would initially contain the full list of MFSs and the BFS name associated with the file: DICT.MFS, SI.MFS and RTP57. This list is a dynamic array (subvalue-mark-delimited) of all MFSs, with the proper BFS as the last value in the array.
To call the next file system routine, the MFS derives the name of the next MFS from this list, and then calls it using the "@variable" syntax for the R/BASIC CALL statement.
Deriving the name of the next MFS is a two-step process. The MFS must first remove its own name from the list. After this is accomplished, the first element of the BFS array then contains the name of the next filing system routine, and can be extracted simply.
The full R/BASIC logic to strip the current MFS name from the list, derive the next routine name, and call the next routine looks like this:
FS = DELETE(BFS,1,1,1) ; * strip current name NEXT.FS = FS<1,1,1> ; * derive name of next routine * now call next routine. Note that all seven * arguments are passed CALL @NEXT.FS(CODE,FS,HANDLE,NAME,FMC,RECORD, STATUS)
For example, if an MFS called SAMPLE.MFS has been installed onto a Linear Hash file, the BFS argument will be passed to SAMPLE.MFS with this structure:
SAMPLE.MFSnRTP57
When SAMPLE.MFS has finished processing, it executes the DELETE function to strip its own name from the list. The result is a one-element array containing simply the name RTP57. The subsequent extract derives the name and passes it to the CALL statement. As a result, SAMPLE.MFS calls RTP57, passing it the seven required arguments.
Return from the BFS
Since an MFS calls the next filing system using a CALL statement, the MFS remains resident while filing systems that follow are executing. As with any subroutine calls, however, when routines (other MFSs and the BFS) are finished with the call, control returns to the statement following the CALL @NEXT.FS( … ) statement.
An MFS thus has two opportunities with each operation to manipulate the data: when the call and arguments first come down from R/BASIC, and again when the arguments are being returned from the BFS. In effect, this gives an MFS a "pre-file-operation" and a "post-file-operation" capability.
For example, an MFS that encrypts and decrypts data would modify the data differently depending on whether a read or write operation were being performed. If the data were being written to the file, the MFS would encrypt the data before calling the next filing system routine in line. All subsequent MFSs, and the BFS, would be passed a record that was already encrypted.
However, when reading the data, the MFS would decrypt the record after it had returned from the BFS and from any MFSs that came after the encryption MFS. In this way, the encryption MFS could pass clear data back to the R/BASIC READ statement.
The fact that MFSs can be stacked in this way affects the design of an MFS. In some instances, the order of MFSs is critical, since the output from one MFS is the input for the next, or since one MFS might terminate a file operation before subsequent MFSs get an opportunity to examine the data.
Compiling and Cataloging the MFS
Once the MFS has been created, it should be compiled and either cataloged or placed in a file that requires no catalog entry (VERBS or SYSOBJ).
It is important that the MFS be placed in a file that will never be detached after the MFS has been called for the first time in the current session. Once loaded, the MFS will be called by certain filing system operations, even if the files it is installed on are no being accessed or are no longer attached.
It is therefore advisable to copy the finished MFS to a file such as VERBS or SYSOBJ. Programs loaded into these files do not need to be cataloged, and are guaranteed to stay available to the system at all times. Programs in SYSOBJ are loaded into the program stack when Advanced Revelation is initialized, and are not removed. Programs in VERBS do not need to be cataloged, as the program loader will always look in the VERBS file before checking for a catalog entry.
Warning: VERBS and SYSOBJ are considered system files, and may be overwritten by an Upgrade or Update process. Be sure to save any additions to these files before updating them with any release from Revelation Technologies, and to restore the saved code after the update.
Expendable Subroutine
While developing an MFS, it is a good idea to make the MFS subroutine expendable (using the syntax EXPENDABLE SUBROUTINE in the first line instead of just SUBROUTINE). Expendable subroutines are removed from the program stack after executing a RETURN statement.
Making an MFS expendable while developing it insures that changes made to the MFS are reflected the next time it is called. If the MFS remains on the program stack, changes are not reflected until the next Advanced Revelation session.
When development of the MFS has finished, the MFS can be made into a non-expendable subroutine by removing the word EXPENDABLE from the first line.
MFS/BFS Independence
When creating an MFS, a programmer must consider carefully the environment and purpose of the MFS. Developers should remember that an MFS can (and should) function generically within the Advanced Revelation system.
In an ideal system, an MFS is compatible with all possible BFSs. At the same time, an MFS should be prepared to handle the full range of calls that might pass to it from higher levels of the system.
To maintain true independence of an MFS, it is important that MFS programmers not assume information that is unique to a BFS. For example, each BFS uses a unique structure for its file handles, lock semaphores, and select pointers. An MFS that is designed to manipulate any of these based on a specific structure will become BFS- bound, and will not be installable on files associated with different BFSs.
As another example, it would be very inflexible to build direct calls to RTP57 (the Linear Hash BFS) into an MFS. Doing so would preclude installing additional an MFS for the file, and would prevent the MFS from being used for other filing systems.
Of course, there is no restriction on the creation of such a BFS-bound MFS. Particular applications will occasionally require precisely this type of MFS for reasons of efficiency or security, or for other reasons. Under these circumstances, an MFS programmer is wise to build checks into the MFS (such as testing the BFS argument) to insure that if the MFS is inadvertently linked to the wrong BFS, it is able to recover and proceed.
INSTALLING AN MFS
Once the MFS is complete, it can be added to any file. There are several options for installing the MFS. Each offers slightly different capabilities.
Developers can install any number of MFSs onto a file, and can mix their own MFSs with system MFSs such as SI.MFS and QUICKDEX.MFS. Some MFSs, however, are sensitive to the sequence in which they are called. For example, SI.MFS absorbs several BFS calls in their entirety, and does not pass them on to the next MFS or to the BFS.
Because of this, developers need to be aware of the effect of other MFSs that precede or follow their own MFS, and place their MFS accordingly. Information about the position sensitivity of system MFSs is available in Appendix 2.
Manual MFS Installation
If intended to be a permanent addition to the file, the MFS is installed by adding its name to the media map entry for the file. A manual installation consists of updating the media map entry for a file with the MFS name, and (re)attaching the file. After the file has been attached, the MFS will be called for all access to the file. To install an MFS manually, follow the instructions listed below.
Because it requires that the REVMEDIA file be attached, the manual installation procedure can only be performed from the SYSPROG account. However, this procedure can be performed to install an MFS onto a file that belongs to any account.
Note: for more information on media maps, see the Advanced Revelation documentation. Information about media maps also appears under the topic "Media Calls" in the chapter "MFS Programming Notes" later in this book.
Note: In Version 1.13 and earlier of Advanced Revelation, an MFS cannot be installed on Revelation G (ROS and LINK) files using a manual procedure, because of limitations in the structure of the media map. However, an MFS can be added dynamically or via a volume pointer. Both of these techniques are described later in this chapter.
Attach target media map
Determine the volume name for the file onto which the MFS is to be installed. For example, if the file is on the default directory, the volume name is REVBOOT. Attach the media map for the volume by entering this command at TCL:
ATTACH volume.name REVMEDIA
Edit media map entry for file
Determine the name of the account with which the file is associated. This can be accomplished by using the LISTMEDIA command. When the account name is available, edit the media map entry for the file by calling the editor with this syntax:
EDIT REVMEDIA file.name*account.name
For example, to edit the media map entry for the CUSTOMER file in the TUTOR account, enter this command:
EDIT REVMEDIA CUSTOMER*TUTOR
Add MFS name
Field 1 of the media map entry is reserved for MFS names. If the field is empty, simply enter the name of the MFS to be associated with the file.
If more than one MFS is associated with the file, the field uses value marks to separate the MFSs. Add the MFS name and any required value marks to field 2. Each MFS will be called in the order it appears in field 2, left to right. For example, field 2 of the media map entry might look like this after two MFSs have been installed:
SAMPLE.MFS2SI.MFS
File the record away.
Caution: Exercise care whenever editing records in the media map. Errors made in editing the map can result in map corruption, resulting in loss of access to files stored on that volume.
Note: When multiple MFSs are installed onto a file, the order in which they are called can be critical. For information on position sensitivity of Advanced Revelation system MFSs, see Appendix 2.
(Re)attach the file
Even if the file has already been attached, it must be reattached before the MFS will be recognized. Use the ATTACH command, including the name of the file in the command:
ATTACH volume.name file.name
Installing an MFS Using an R/BASIC Program
An R/BASIC program can be created to automate the steps described above for manual installation. An R/BASIC program to install an MFS lessens the possibility of edit errors when accessing the REVMEDIA file, and provides a means for end users to install an MFS without concern about the integrity of the media map.
An R/BASIC program can also use information available in the FILES and VOLUMES files to construct a file handle for the media map to be updated with MFS information. A program can then read and write directly to the media map using the handle, bypassing the requirement to attach and then open the media map. As a result, the installation procedure will be faster, and is not restricted to the SYSPROG account.
Note: Information about a media map is BFS-specific. An MFS installation procedure written for a specific BFS may not work properly with all BFSs.
The following sample program fragment illustrates the essentials of constructing and using a media map handle. The technique illustrated here works with media maps for ROS and Linear Hash files (RTP51 and RTP57).
OPEN 'FILES' TO FILES.FILE ELSE STOP OPEN 'VOLUMES' TO VOLUMES.FILE ELSE STOP FILENAME = '' CALL MSG("Install MFS onto what file?","R",FILENAME,"") READ FILES.REC FROM FILES.FILE, FILENAME ELSE CALL MSG("201","","",FILENAME) ; * not attached STOP END VOLUME.NAME = FILES.REC<1> ; * get the name of the volume READ VOLUME.REC FROM VOLUMES.FILE, VOLUME.NAME ELSE MSG(VOLUME.NAME:" unavailable.",'','','') STOP END * construct the file handle for the REVMEDIA map in question MEDIA.HANDLE = VOLUME.REC<4> : @VM : VOLUME.REC<5> * construct the key (file.name*account.name) for the file. * this information is stored in the FILES file MEDIA.MAP.KEY = FILES.REC<2> :"*": FILES.REC<3> * update the media map entry with the MFS info. MFS lists are * stored as the 2nd attribute of the media map entry for a file READ MEDIA.MAP.REC FROM MEDIA.HANDLE, MEDIA.MAP.KEY THEN * put new MFS name on front of existing MFS list OLD.MFS.LIST = MEDIA.MAP.REC<2> NEW.MFS.LIST = MFS.NAME : @VM : OLD.MFS.LIST MEDIA.MAP.REC<2> = NEW.MFS.LIST WRITE MEDIA.MAP.REC TO MEDIA.HANDLE, MEDIA.MAP.KEY * reattach file to update FILES entry PERFORM "ATTACH ":FILES.REC<1>:" ":FILES.REC<2>:" (S)" END ELSE MSG("Cannot read ":MEDIA.MAP.KEY,'','','') STOP END ; * read media.map rec RETURN