The MDL Programming Environment
Chapter 4. The Library System
A coherent unified library system serves to facilitate the sharing of algorithms and data by imposing a discipline appropriate for the particular environment. The MDL Library System provides:
- A uniform access method for referring to functions and data outside of the current logical group;
- Lexical blocking, eliminating difficulties arising from overlap of names between different logical groups;
- Automatic loading of functions for the user who knows only the name of the function which is wanted;
- A facility whereby functions which may be necessary only in unusual situations are loaded only in the event that they are needed.
The MDL Library System may be divided into distinct parts. These are:
-
'The Package System, the collection of routines used to provide lexical blocking for a logical group (see section 2);
-
The 'explicit' loading facility, the routines used to explicitly indicate that references are being made to a particular logical group;
-
The 'implicit' (or 'dynamic') loading facility, the machinery for automatically loading functions when they are needed during console interaction.
4.1. Program Libraries
In the previous discussion of the Package System and USE (see section 2.3.2), we glossed over the mechanism by which a PACKAGE is loaded when another PACKAGE (or the user at his terminal) refers to it. We will now give the details.
There are two types of loading common in MDL programming: 'explicit' loading, such as USE may initiate, and 'implicit' or 'dynamic' loading, initiated by attempting to call or examine a function that is not currently loaded.
In the case of 'explicit' loading, it is necessary somehow to map the name of a PACKAGE into a file name which contains the body of that PACKAGE. 'The mechanism for doing so must be flexible enough to allow both 'installed' programs (those that have been debugged and submitted to the library) and developmental programs to be loaded. It must also be tailorable for special needs, such as libraries for specific systems and personal libraries for individual users.
In the case of 'implicit' loading, the further mapping from the specific ENTRY of a PACKAGE referenced to the PACKAGE itself must be performed. It must deal with the case of two or more PACKAGEs each containing an ENTRY with the same PNAME. For programs that are 'public' or 'installed', both of these mappings are performed by a library. A library is a file which contains pointers between the names of ENTRYs of PACKAGEs and the PACKAGEs containing them, and from PACKAGE and DATUM names to the files containing them. The standard library is named LIBMUD and lives on a directory named LIBMUD (on ITS) or MDLLIB (on Tenex/Tops-20), but other libraries, personal or special purpose, may also exist; the mechanisms for creating and maintaining them are the same in both cases.
4.1.1. Library Searching
When a PACKAGE is USEd, MDL first checks to see if the PACKAGE is already loaded, by looking up the PACKAGE name on the PACKAGE OBLIST. If the PACKAGE is not yet loaded, MDL must search for the file containing the body of the PACKAGE. When MDL searches, it does so under the direction of a search path stored as the LVAL of the ATOM L-SEARCH-PATH. This LVAL is a LIST, each element of which specifies 'a place to look' for the PACKAGE. These elements may be:
"file-name"A STRING refers to a library file; "LIBMUD;LIBMUD" for example.[]An empty VECTOR refers to thedirectory. The directory will be searched for files whose names are the name of the PACKAGE being loaded (truncated to six characters on ITS) and second names from the LVAL of the ATOM L-SECOND-NAMES, which is a VECTOR of STRINGs which are possible second names for the file. [dir:string-or-false]A non-empty VECTOR specifies a directory. The first element of the VECTOR gives the directory as a STRING or a FALSE, the latter case meaning. If that is the only element, L-SECOND-NAMES specifies the file names to look for. If there are other elements, they should be STRINGs to use in place of L-SECOND-NAMES. A search path may consist of any number of such elements. The loader will examine them sequentially, attempting to find the PACKAGE being loaded.
The initial LVAL of L-SEARCH-PATH (on ITS) is
("LIBMUD" "LIBMUD;LIBMUD" [] ["MBPROG"] ["MPROG" ">"])
and on Tenex/TOPS-20, it is
("LIBMUD" "<MDLLIB>LIBMUD" [] ["MDLLIB"])
This instructs the loader to first search the user's personal library (if it exists), then the 'public' library. Next, search the user's directory for a file whose first name is the PACKAGE name, and whose second name is specified by L-SECOND-NAMES. If that fails, perform the same search on the library directory, and finally (on ITS), look for a source version of the PACKAGE on the source directory. The initial LVAL of L-SECOND-NAMES (on ITS) is
["FBIN" "GBIN" "NBIN" ">"]
and on Tenex/TOPS-20, it is
["FBIN" "GBIN" "NBIN" "MUD"]
To give a simple example of how this mechanism may be tailored for individual needs, consider a programmer debugging a subsystem. If he wants his debugging versions of various PACKAGEs to be loaded before the installed versions, he CONSes a new element onto L-SEARCH-PATH so that it contains
([] "LIBMUD" "LIBMUD;LIBMUD" [] ["MBPROG"] ["MPROG" ">"])
(assuming the files with his debugging versions are on the
4.1.2. Dynamic Loading
To ease the use of "top level' routines from the console, a feature is provided whereby the Library System can load a PACKAGE of functions automatically when one of the functions which is an ENTRY in that PACKAGE is invoked by name. This facility is not available for use by other PACKAGEs of functions, which must refer explicitly, via USE, to PACKAGEs which they require: while a human can resolve the difficulty of possible multiple PACKAGEs with ENTRYs of the same name, a program cannot. When an error is generated because a FORM is evaluated, and the first element of that FORM is an ATOM which has no value, and the particular ATOM is in the INITIAL OBLIST, an error handler established by the Library System determines if there are any PACKAGEs in the current libraries which contain an ENTRY with the same name as the PNAME of that ATOM. If there is one such PACKAGE, it is loaded, and the evaluation which got the error is continued with the correct value. If there is more than one such PACKAGE, the possible choices are displayed, the user is asked which is the desired PACKAGE, and it is loaded. If there are no PACKAGEs with ENTRYs of the correct name, the error is not handled, and so it will fall into the standard error mechanism. This same procedure is also invoked when GVAL is applied to an ATOM on the INITIAL OBLIST and the ATOM has no value.
4.1.3. USE-DEFER
It is sometimes desirable to have available functions that are rarely invoked. but are nonetheless available. (One example would be certain error handling routines.)
The USE-DEFER function sets up the OBLIST path so that, when a reference is made to an ENTRY in the specified file, the correct ATOM is found, but the PACKAGE is not actually loaded at that time. When a function at a later time tries to call the function which is the value of one of the entries in this PACKAGE, the whole PACKAGE will be automatically loaded. USE-DEFER has two constraints which USE does not. First, the PACKAGE must be in one of the currently active libraries; it may not simply be a file as in the case of USE. Second, no reference may be made to ATOMs which are entries but do not have values which are applicable. In other words, ATOMs which are entries because they are data (rather than functions) may not be referenced when USE-DEFER is employed instead of USE.
Because USE-DEFER utilizes the dynamic loader, which utilizes the ERROR interrupts, USE-DEFER will not work in a demon or any other MDL program which sets up its own error handlers. All such MDL programs should SETG the ATOM L-NO-DEFER to a non-FALSE, which (as explained previously) will cause USE-DEFER to behave exactly like USE. Then, PACKAGEs containing a USE-DEFER can be used without modification in demons and the like.
4.1.4. USE-TOTAL
USE-TOTAL is analogous to USE, but instead of splicing in only the ENTRY OBLIST of the PACKAGE, it additionally splices in the internal OBLIST. This is useful in some debugging situations, as it reduces the number of trailers printed and also makes the internal identifiers of the PACKAGE more accessible,
4.1.5. Translations
It is occasionally useful to have more than one copy of a particular PACKAGE loaded at once. One example that comes to mind is the case of debugging a debugging PACKAGE. 'The library System contains a mechanism for 'translating' a PACKAGE name into another one. More specifically, it is possible to tell USE: 'If you ever load the PACKAGE named foo, pretend it was named bar instead.' Note that this does not change the searching and loading procedure described above, only the names of the OBLISTs and so on used to store the ATOMs in the PACKAGE.
<TRANSLATE old:string new:string-or-false>
causes the PACKAGE old, when it is USEd, to behave as if it were named new. If new is FALSE, it means that old should be loaded as though it were not a PACKAGE at all: its ATOMs will appear on the DEFAULT OBLIST or <1 .OBLIST> (normally INITIAL).
<UNTRANSLATE old:string>
causes any translation of old to be removed.
<TRANSLATIONS>
lists all translations currently in existence.
.L-TRANSLATIONS
is a LIST containing all the translations.
4.1.6. The Library Data File
In addition to its ability to map between PACKAGEs, ENTRYs, and the files which contain them, the library serves another purpose, If a user is compiling a function which USEs a given PACKAGE, that PACKAGE is not usually going to be run. All that is necessary is to examine the calling sequences of its functions, and make sure that all 'side-effects' (such as the definition of new TYPEs) occur. If only these necessary parts of the
PACKAGE are loaded, a great saving of time and space is effected.
. The library data file provides a way of achieving this end. When a PACKAGE is added to the library, more information than the list of ENTRYs and the file containing the PACKAGE is collected. In particular, MANIFEST GVALs, NEWTYPE definitions, some MACROs, and RSUBR DECLs are stored. Since this is the information used by the compiler, one can save a great deal of space and time by using information from the library where possible.
If .L-USE-DATFILE is true, USE of a PACKAGE will load from the data file if possible. It is impossible if the PACKAGE has changed since the data file entry was created. In those cases, the PACKAGE itself is loaded instead. If .L-ALWAYS-DATFILE is true, an ERROR will result if the data file entry is outdated: one can ERRET T to cause the real PACKAGE to be loaded.
USE-DATFILE is just like USE, except that it temporarily SETGs L-USE-DATFILE and L-ALWAYS-DATFILE to T.
The data file contains, for each PACKAGE, information for each interesting ENTRY: MANIFEST GVALs, NEWTYPE definitions, RSUBR DECLs, and MACROs. It also has, of course, the lists of ENTRYs and RENTRYs needed by the dynamic loader. It does not contain other structures, nor does it contain functions. When a
PACKAGE is loaded from the data file, it is effectively USE-DEFERed: if you end up needing to run part of the PACKAGE, it will be loaded dynamically. Some PACKAGES can not have data file entries. If a PACKAGE defines MACROs that use data not stored in the data file (iF the MACRO calls a FUNCTION, for example}, the PACKAGE will not get a data file entry: it would normally end up being loaded from the file anyway. It is possible for a data file entry two become obsolete (if a new version of a PACKAGE is created without the library entry being updated). For this reason, the library is examined periodically for such entries and an attempt is made to update the appropriate entries.
4.1.7. Run-time Switches
There are a number of variables which may be set dynamically to tailor the Library System's performance.
.L-SEARCH-PATH
as described above (see section 4.1.1) is a LIST specifying the libraries and directories to look in, and the files to look for when trying to load a PACKAGE. This variable is used by USE, USE-DEFER, USE-DATUM, and the dynamic loader.
.L-SECOND-NAMES
as described above (see section 4.1.1) is a VECTOR of the second names of files to look for when attempting to load a PACKAGE from a directory.
.L-NOISY
If the GVAL of L-NOISY is non-FALSE, the names of PACKAGEs and DATUMs are printed whenever they are loaded, dynamically or otherwise. This feature may be turned off by SETGing L-NOISY to #FALSE (). L-NOISY has an initial GVAL of T.
.L-NO-MAGIC
Dynamic loading may be disabled by SETGing L-NO-MAGIC to a non-FALSE. L-NO-MAGIC has an initial GVAL of a FALSE.
.L-ALWAYS-INQUIRE
If the GVAL of L-ALWAYS-INQUIRE is non-FALSE, the dynamic loader will always ask the user before it loads anything. The GVAL of L-ALWAYS-INQUIRE is initially a FALSE.
.L-NO-DEFER
If the GVAL of L-NO-DEFER is non-FALSE, USE-DEFER will work exactly like USE. L-NO-DEFER is initially SETGed to #FALSE ().
4.1.8. Library Utility Functions
A number of functions exist which allow the user to examine libraries, list their contents, and retrieve their
entries. All of the functions below except L-PATH and L-OBL accept an optional STRING argument, a
library specification. If it is defaulted, they operate on the public library, specified by the string "LIBMUD;
LIBMUD" or "
<L-LOAD package:string library:string>
L-LOAD requires a STRING (the name of a PACKAGE or DATUM) and attempts to load it from library (if given) or the current libraries, as per L-SEARCH-PATH.
<L-FIND function-name:string library:string>
L-FIND requires a STRING (the name of an ENTRY), returning a UVECTOR of two-element VECTORs of the form:
[package-in-which-function-exists:string
library-in-which-package-exists:string]
This finds all of the entries which have the same PNAME but are in different PACKAGEs.
The remaining functions are in the PACKAGE "L", rather than in the PACKAGE "PKG". For each of
these, the optional library argument is by default the library: that is, "LIBMUD;LIBMUD" or
"
<L-FILE package:string library:string>
L-FILE requires a STRING (the name of a PACKAGE or DATUM) and returns a STRING which is the file specification of the file, pointed to by the library, which contains the body of that PACKAGE or DATUM.
<L-WHERE package:string library:string>
L-WHERE is similar to L-FILE but returns a VECTOR of STRINGs which is the actual complete file specification of the file containing the PACKAGE (i.e., the 'real' slots in a CHANNEL open to the file).
<L-LISTE library:string>
L-LISTE prints the names of all of the entries of all of the PACKAGEs in the library.
<L-LISTP library:string>
L-LISTP prints the names of all of the PACKAGEs and DATUMs in the library.
<L-COUNTE library:string>
L-COUNTE returns a FIX, the number of entries defined by all of the PACKAGEs in the library.
<L-COUNTP library:string>
L-COUNTP returns a FIX, the number of PACKAGEs and DATUMs in the library.
<L-LISTPE package:string library:string>
L-LISTPE requires a STRING (the name of a PACKAGE) and prints the names of all of its entries.
<L-PATH>
L-PATH prints a list of the names of all of the OBLISTs in the user's current OBLIST path.
<L-OBL atom>
L-OBL requires an ATOM and returns an ATOM, the name of the first ATOM's OBLIST. L-OBL is in fact
<GET <OBLIST? atom> OBLIST>
4.1.9. Internal Library Functions
There are several internal functions used for searching libraries (which is, after all, all the Library System ever does).
<PACKAGE-FIND package:string library:string>
searches library for package. If there is no such PACKAGE or DATUM in library, it returns a FALSE. Otherwise, it returns a STRING, which is the name of the file containing package.
<ENTRY-FIND entry:string-or-atom library:string>
searches library for PACKAGEs containing entry. It returns a FALSE if there are none, otherwise a LIST some multiple of four elements long, where each set of four elements describes a package containing an ENTRY with that PNAME. These elements are:
-
package:string is the PACKAGE being described.
-
file-name:string is the file-name containing the package.
-
rpackage?:atom-or-false indicates, if non-FALSE, that the package is in fact an RPACKAGE.
-
rentry?:atom-or-false indicates, if non-FALSE, that the entry is an RENTRY.
returns a FALSE if the PACKAGE or DATUM is not found, or a VECTOR of five elements describing the package:
- rpackage?:atom-or-false indicates, as above, whether the package is an RPACKAGE.
- name:string is the name of the package.
- file-name:string is the file containing the package.
- entries:list is a LIST of the PNAMEs of the ENTRYs of the package.
- rentries:list is a LIST of the PNAMEs of the RENTRYs of the package.
This is all the information about the package that the library contains.
4.1.10. Library Maintenance
The PACKAGE called "LUP" contains functions used to modify libraries, and to add, update and delete PACKAGEs and DATUMs. It should be noted that libraries do not contain the bodies of PACKAGEs and DATUMs. Rather, they point to files which contain these.
<LUP-ACT library:string>
requires one argument, a library specification STRING, and activates the library so specified. If the library doesn't exist, it is created. In order to protect the library from loss due to system or MDL crashes, activating a library for modification copies the library data files and locks the library so that no one else may modify it. Modifications are made to the copies, which are renamed back over the originals only when the library is explicitly deactivated. Obviously, PACKAGEs added to a library aren't available, even to the person adding them, until the library is deactivated.
<LUP-DCT>
deactivates the currently active library.
<LUP-ADD-PACK package-file:string
update?:boolean
datfile-entry?:boolean>
package-file is a file specification of the file containing the body of the PACKAGE to be added. LUP-ADD-PACK will find the PACKAGE statement within the file (or complain if it can't).
update? is optional, and if non-FALSE, it allows the PACKAGE to update an older version of itself, something which is not otherwise allowed. Note that, since the library points to the file which contains the body of the PACKAGE, that file should not be deleted later, else the library won't be able to find it.
datfile-entry? is by default T, but if it is FALSE, no entry will be created in the datfile for this PACKAGE. Since datfile entries are generally useful only in the compiler (and similar environments), it doesn't do much good to have them for PACKAGEs that are only called from top level (e.g., FINDATOM).
When adding a PACKAGE to the public library, the PACKAGE's object file should be copied to the
appropriate library directory ("LIBMUD" on ITS, or "
<LUP-ADD-DATUM name:string
file:string
update?:boolean>
is analogous to LUP-ADD-PACK, adding a DATUM to the active library. LUP-ADD-DATUM requires two STRING arguments, the name of the DATUM and the specification of the file which contains the body of the DATUM. LUP-ADD-DATUM will accept the same optional argument that LUP-ADD-PACK accepts, with the same meaning and default. The same restrictions concerning the file which contains the DATUM also apply.
<LUP-DEL package:string>
LUP-DEL requires one STRING argument, the name of a PACKAGE or data set, and deletes that PACKAGE or DATUM from the currently active library. LUP-DEL does not touch the file containing the body of the PACKAGE or DATUM.
<LUP-MOVE package:string file:string>
causes the file pointer of package to be changed to point to file. This is a faster operation than re-adding the PACKAGE, and it is intended for situations in which an existing library file has been moved for some reason.
<LIB-GC library:string>
garbage-collects the library in question, if this is required. Garbage-collection is occasionally useful since it causes all the elements of each hash bucket to live near each other in the library file, thus improving performance during searches. It also allocates some free storage in each page of the file.
4.2. The Pure-mapping Library
'The basic idea behind MDL pure mapping is to separate out the code part of RSUBRs in compiled programs. 'The RSUBRs themselves are kept in a file known as an FBIN (see 6.3). These RSUBRs do not contain the code but instead point to a file which contains the code. This scheme has several advantages. First, the code can be dynamically mapped in when needed. 'This allows MDL to use more code than will fit in the virtual address space of the machine it is running on. Secondly, since the code is pure it can be shared between several MDLs using it. Finally, the FBIN file itsclf is smaller than a corresponding NBIN file and therefore FLOADs more rapidly.
In the most basic implementation of FBINs, there are three files: the FBIN, the SAV file (which contains the code), and the FIXUP file, which contains the information necessary to update the SAV FILE for new releases of MDL. As is obvious, this entails a lot of files, and potentially a lot of file directories. 'The MDL Pure-mapping Library reduces this storage overhead by collecting all of the SAV and F LXUP files together.
The scheme uses two large data bases, each contained in one file. The data bases are called "SAV" and ! 'FIXUP'. 'These files store all currently existent SAVs and FIXUPs for all existing versions of MDL. Each data
base is structured like a file system. There is a main 'directory' that points to a number of other 'directories', each of which points to a number of 'files' inside the data base. In this section the word 'file' or 'directory' in
a quotes refers to an object inside a data base. The files containing the data bases are named (on IT'S)
"3 "MUDSAV;SAV) FILE" and "MUDSAV:FIXUP FILE". On Tenex/TOPS-20, they are
i "
4.2.1. The Demon
i While all Midis can read from the Pure-mapping | ibrary, there is only one program which can write into
it. This is a maintainer demon which runs once a day to keep the Library updated. This demon can add 'files',
| delete 'files', and add 'subdirectories' to both data bases.
'To facilitate updating of the | ibrary there is a directory on which to put files to be added as well as files to
indicate what is to be deleted. 'his is the "MUDTMP" directory on ITS and the "
d FIXUPS" exist, then they will be used to delete 'files' from the data bases. These files must be ASCII files of
; the form
A filename 1 [SPACE] filename 2 [CRLF]
; An example of a valid delete file is as follows
Pm INCODGE SAV53 P The demon will ignore any deletion requests for 'files' not in the data base. Te f The demon does its work in several passes, The basic passes are the delete pass, the planning pass, the update pass, and the salvage pass. The delete pass deletes 'files' if either a "DELETE SAVS" or "DELETE | FIXUPS" file exists on its working directory. The planning pass builds a plan file by examining the working : directory and calculating where new 'files' will be placed in the data bases, 'I'he planning pass builds two files using a special internal format, These files will be used by the update puss to add 'files' to the duta bases. The planning pass also enlarges the data base files as much as necessary Lo accommodate the new 'files'. The update phase reads the plan files and adds new SAV and FIXUP 'files' tu the data bases. If a 'directory' overflows, a new 'directory' is added during this pass, and all the 'directories' arc recreated (i.c., all the "files" have to be rehashed, since they were originally placed in a 'directory' according to a hashing algorithm based on the humber of 'directories'). The salvage pass is used to pick up any free storage that has been lost through system crashes or lost through holes created during the updating of the data bases,
Throughout the entire processing of the data bases attempts are made tu keep the data bases in a consistent state. ")irectories' are updated only after 'files' are guaranteed to be in the data bases. The plan files described are used to keep the data bases consistent in case the system crashes while the demon is in the update pass. A major goal in the design of the data bases is to allow recovery in case of demon errors or system disk crashes. To this end the data bases are backed up on tape every other week. (It would be dumped more often but the file is currently over two million words long). This of course leaves the problem that 'files' added to the data bases between dumps could be lost in a disk crash. To aid in recovery from such a crash, all 'files' added between dumps are copied to the "MUDRST" directory (on ITS) or the "<MDL.S$V>" directory (on Tenex/TOPS-20). Moreover a file is kept listing all the 'files' added during the previous week. This file is called "ADDED FILES". All this information is deleted once the data base is dumped to tape.
4.2.2. User Programs
Occasionally it is useful for a user to list the data base 'directories', to see if certain 'files' are in it. and copy 'files' out of the data base. DBMA IN is a program which allows the user to do these things. The following are functions available to the user.
4.2.2.1. Listing Functions
<CLISTF data-base:string>
is used to list all the 'files' in a data base. It takes one optional argument which is the name of the data base (either "SAV" or "FIXUP"). If no argument is supplied, "SAV" is used by default. (This is always the default whenever a function takes an optional argument specifying the data base.) CLISTF prints each 'file', its length, and where it is located. The format of a line of listing is as follows:
fn1 fn2 size block
where fn1 is the first 'file' name, fn2 is the second 'file' name, size is the length of the 'file' in blocks (1024. words for SAVs, 256. words for FIXUPs), and block is the block at which the 'file' starts. This is the format used whenever listing 'files'.
<LISTF data-base:string directories>
is used to list all the 'directories' of an entire data base. It takes two optional arguments, the data-base to be listed, and a specification of which 'directories' to list. The 'directories' may be:
-
a FIX: list the 'directory' specified by the FIX;
-
a LIST of FIXes: list the 'directories' specified in the LIST;
-
the ATOM ALL: list all the 'directories' (this is the default).
lists free areas of storage in the data base. It lists the free storage in the form:
length block
where length is the length of the area of free storage and block is the block number of the starting block. This function takes one optional argument which is the name of the data base to be examined. At the end of the listing it will tell the total amount of free storage.
4.2.2.2. Find Functions
<FIND-FILE file:string data-base:string>
is used to find a specific 'file'. It takes as its argument a 'file' specification and prints the 'file' name along with the information printed by the listing functions if the 'file' exists, otherwise it returns an object of type FALSE. The 'file' specification must be of the form:
"dir fn1 fn2"
where dir is either SAV or FIXUP and fn1 and fn2 are the first and second 'file' names respectively.
<SPEC-FIND fn1:string data-base:string>
is used to find all 'files' with the same basic name, disregarding the leading digit(s) which are added to make 'file' names unique. It takes one required argument which is the fn1 to look for. It takes an optional second argument which is the data-base to look in. For example the call
<SPEC-FIND "MAIL">
might print:
1MAIL SAV53 8 360
4.2.2.3. Other Functions
<DELETE file:string data-base:string>
allows the user to delete a 'file' from a data base. It takes the same type of 'file' specification that FIND-FILE takes. The 'file' you specify will be deleted the next time the demon that maintains the data base runs.
<GET-FILE file:string output:string data-base:string>
allows the user to retrieve a 'file' from the data base. It takes two arguments. The first is the 'file' specification of the file to retrieve out of the data base and the second is the output file you wish to copy it to.
<STATUS>
gives the information about the state of the data bases. It tells the number of 'files' and the amount of free storage in each data base. STATUS takes no arguments.
4.2.3. Using DBMAIN
There are several ways to use DBMAIN. Itcan be used by typing :DBMAIN function arg! ... argn to DDT. The jcF-line is of the form function arg! ... argn, where function is the name of the function to be used. For example :DBMAIN FLIST "FIXUP" will list the free storage block for the "FIXUP" data base, DBMAIN will kill itsclf after finishing and can be killed carlicr by typing tS.
'The jel-line mentioned above can be modified to allow output to be routed to a file. This can be done by preceding the normal jel-line with a string specifying the file name of the output file.
:-DBMAIN ""LISTOF SAVS" CLISTF will produce a listing of the files in the SAV data base and will print this in formation to the file "LISTOF SAVS".
4.2.4. Garbage Collection
One problem of the MDL Pure-mapping Library is that many useless SAV and FIXUP 'files' remain as new revisions of user programs are created. 'l'o alleviate this problem there is a garbage collection system for the dita bases.
The major goal of this scheme is to determine which 'files' in the data bases are no longer useful. To do this all files in the system are scanned to see what SAV files are still pointed to (nor including those pointed to only from within ITS archive files). A SAV 'file' can be pointed to from FBIN files and SAVE files. A SAVE file contains pointers in its PURVEC (Pure VECTOR). All FBIN files should begin with something of the form
<<PCODE _file:string>
where file is the name of the SAV 'file' associated with this FBIN. If an FBIN has more than one SAV 'file' associated with it then there can be several PCODE FORMs at the beginning of the file. For purposes of garbage collection, this FORM (or FORMs) wus be retained whenever an FBIN file is edited. If these PCODE FORMs disappear, their pointers to the SAV 'files' will go with them, and the SAV 'files' might be garbage collected. :
Garbage collections proceed by looking at every file on the disk, building a list of all 'files' pointed to. 'The program then examines the data bases and any 'files' which are not pointed to are deleted.
It is possible that deletions can fragment the free arca in the data bases, If compaction becomes necessary,
there exists a routine to do in-place compaction of the data bases,
4.2.5. Internal Structure
The "SAV" and "FIXUP" data bases have similar formats, The 'files' in the data base are pointed to by
entries in what is essentially a hash table. Associated with each data base is a main 'directory' (the hash table). This 'directory' is located in the first 1024 words of the file. This main 'directory' points to other 'directories' in the data base (the hashing buckets). Each of these 'directories' is 1024 words long. The first 'file' name is used to determine which 'directory' the 'file' is on. 'The structure of the main 'directory' is as follows,
word 0/ number # of entries in the main 'directory'
words I-n/ block number of each 'directory'
There can be up to 1023 'directories' and each of these can contain approximately 500 'files'. This provides a virtually unlimited 'directory',
Word 0 of each "directory" gives its length in words. From Word 1 on are 'directory' entries. All entries have the same two word format. 'The first word contains the the first 'file' name in SIXBIT, 'The second word contains the following fields: length of the 'file' iu blocks (a block for a SAV 'file' is 1024 words long while a block for a FIXUP 'file' is 256
words long) (bits 1-6) version revision of MDL this 'file' belongs to (bits 8-17) block in the data base where this 'file' starts (bits 18-35)
The 'directories' are sorted by strict numerical order (<.g., AAA SAV53 comes before 1AAA SAV53). Fach data base contains a free storage table. This table occupies the second 1024 words of the data base, The first word of the table is the number of entries in the free storage table. The remaining entries define arcas of free storage. These arc of the form | length,, block where length is the number of blocks for this free area, and block is the block number at which it starts.
There are two major differences between the "SAV" data base and the "FIXUP" data base. The first deals with block sizes. In the "SAV" data base the block sive is 1024 words. In the "FIXUP" data base the block size is 256 words. This smaller size allows for more compaction of these small 'files'.
| The second major difference is that while there can be many versions of the same 'file' in the "SAV" data , base (c.g. NCODGE SAV53 and NCODGE SAV54), there can only be one version in the "FIXUP" data base.