-- File: AltoFilePrivate.mesa -- Last edited by Levin: 30-Apr-81 14:26:40 DIRECTORY AltoDefs USING [BytesPerPage, PageNumber], AltoFile USING [defaultTime, FileTime, FP, Position], DiskIODefs USING [CompletionStatus, DiskRequest, FID, vDA], FileDefs USING [FSInstance], VMDefs USING [FileHandle, OpenOptions, Page, PageNumber]; AltoFilePrivate: DEFINITIONS = BEGIN OPEN AltoFile, FileDefs, DiskIODefs; -- (1) File Manipulation -- -- Types and Related Constants -- AltoPageNumber: TYPE = AltoDefs.PageNumber; LastPageBytes: TYPE = [0..AltoDefs.BytesPerPage); infinityPage: AltoPageNumber = LAST[AltoPageNumber]; FileObject: TYPE = MONITORED RECORD [ fileID: FID, leadervDA: vDA, lengthKnown: BOOLEAN, lastPage: AltoPageNumber, bytes: LastPageBytes, lengthChanged: BOOLEAN, openCount: [0..63], link: FileHandle, seal: FileSeal, nRuns: [1..maxRuns], runTableLock: MONITORLOCK, runTable: POINTER TO RunTable]; FileHandle: TYPE = POINTER TO FileObject; maxRuns: CARDINAL = 1024; maxSeals: CARDINAL = 32768/(maxRuns/2); -- fits in a word with "maxRuns" in a FileObject -- the horrible declaration is to avoid implicit LONG CARDINALs. RunIndex: TYPE = [0..maxRuns); RunCount: TYPE = [0..maxRuns]; FileSeal: TYPE = [0..maxSeals); openSeal: FileSeal = 63B; underwaySeal: FileSeal = 52B; closedSeal: FileSeal = 14B; VdaRun: TYPE = RECORD [page: AltoPageNumber, vda: vDA]; RunTable: TYPE = RECORD [runs: SEQUENCE runSpace: RunCount OF VdaRun]; initialRuns: RunIndex = 10; -- initial vda runs percentToIncrease: CARDINAL = 50; -- percent by which vda run table is extended minUsefulRuns: RunIndex = 3; -- Procedures for the Operations level -- Open: PROCEDURE [ instance: FSInstance, name: STRING, options: VMDefs.OpenOptions ← oldReadOnly] RETURNS [FileHandle]; Close: PROCEDURE [FileHandle]; Abandon: PROCEDURE [FileHandle]; Destroy: PROCEDURE [file: FileHandle]; -- if more than one user has 'file' open, an error is raised. Otherwise, the file -- is closed, then deleted from the disk and directory. GetLength: PROCEDURE [file: FileHandle] RETURNS [Position]; -- returns the number of bytes in the file; that is, the number of the byte -- immediately following the last byte in the file. SetLength: PROCEDURE [file: FileHandle, length: Position]; -- establishes 'length' as the byte number of the byte immediately following the -- last byte of the file. If 'length' does not exceed the current file length -- (as determined by GetFileLength), SetFileLength is equivalent to TruncateFile. -- Otherwise, the file is extended to the specified length and the added bytes have -- undefined contents. Extend: PROCEDURE [file: FileHandle, length: Position, buffer: POINTER]; -- 'length' must exceed the present length (as determined by GetFileLength), but -- must not leave an undefined gap in the file. This implies that either -- length.page = GetFileLength[file].page or length.page = GetFileLength[file].page+1 -- and length.byte = 0. Thus, ExtendFile writes at most one page of data to the file, -- taking this data from 'buffer'. In the event that the last file page is partially -- full, the entire contents of the buffer are written to disk. It is the client's -- responsibility to ensure that the initial portion of 'buffer' contains correct -- data. If 'length' does not satisfy the requirements above, an error is raised. -- These requirements make it possible for ExtendFile to do its work atomically. -- That is, if a crash occurs during ExtendFile and the Scavenger is run, then the -- file will either have its old length (before ExtendFile) or it will have its new -- length and the data from 'buffer' will appear in the extension. Truncate: PROCEDURE [file: FileHandle, length: Position]; -- shortens the file so that the byte immediately following its last significant -- byte is 'length'. If 'length' exceeds the present length (as determined by -- GetFileLength), an error is raised. GetTimes: PROCEDURE [file: FileHandle] RETURNS [read, write, create: FileTime]; -- returns the indicated file times for the argument file. SetCreationTime: PROCEDURE [file: FileHandle, create: FileTime ← defaultTime]; -- sets the creation time of the argument file. If defaulted, the time is set to -- the current time. -- Other File Manipulation Procedures -- InitializeFileList: PROCEDURE; -- initializes open file manipulation facilities. FinalizeFileList: PROCEDURE; -- finalizes open file manipulation facilities. InsertFile: PROCEDURE [ fp: FP, openProc: PROCEDURE [FileHandle, BOOLEAN] RETURNS [BOOLEAN]] RETURNS [FileHandle]; -- maps 'fp' to a FileHandle and returns it. All clients presenting the same fp -- will receive the same handle. 'openProc' will be called at an appropriate point -- and is passed the FileHandle and a boolean which is TRUE if the 'fp' was not -- previously in use. If the openProc returns FALSE, the insertion of the -- FileHandle is aborted and InvalidFP is raised. ReleaseFile: PROCEDURE [file: FileHandle, closeProc: PROCEDURE [FileHandle]]; -- The use count on the indicated file is decremented and, if zero, 'closeProc' -- is called. The FileHandle then becomes invalid. If the use count is still -- greater than zero, closeProc is not called and the FileHandle remains usable. PurgeFile: PROCEDURE [ file: FileHandle, destroyProc: PROCEDURE [FileHandle]]; -- The use count on the indicated file must be zero, otherwise an error occurs. -- 'destroyProc' is called and it is expected to remove all traces of the file. FindEOF: PROCEDURE [file: FileHandle]; -- fills in the page and byte number of the last byte in the file by reading from -- the last known page to the physical end. -- (2) File I/O Support -- DoDiskRequest: PROCEDURE [ req: POINTER TO DiskRequest, file: FileHandle ← NIL, signalError: BOOLEAN ← TRUE] RETURNS [CompletionStatus, vDA, LastPageBytes]; -- performs a synchronous disk request specified by 'req'. The caller supplies only -- the firstPage, firstPagevDA, pagesToSkip, xfers, noRestore, and command fields -- of the request. If 'file' is non-NIL, the vDAs encountered will be entered in -- the file's vDA table. The return values are: final completion status, vDA of -- the page following the last one processed, and the number of bytes in the last -- page seen. If an unrecoverable error occurred and 'signalError' is TRUE, -- DiskError is raised. GetvDAForPage: PROCEDURE [file: FileHandle, page: AltoPageNumber] RETURNS [vDA]; -- looks up page in file's runTable and returns the associated address. EnterPageAndvDA: PROCEDURE [file: FileHandle, page: AltoPageNumber, vda: vDA]; -- enters the pair <page, vda> into the disk address table associated with file. FindLastKnownPage: PROCEDURE [file: FileHandle] RETURNS [AltoPageNumber, vDA]; -- returns the pair <page, vda> corresponding to the last page in the file for -- which vda is not fillInvDA. TruncatevDATable: PROCEDURE [file: FileHandle, page: AltoPageNumber]; -- alters the file's runTable so that 'page' is the last non-fillInvDA entry. -- (3) Disk Space Management -- InitializeKD: PROCEDURE; -- initializes the local disk allocation mechanism. FinalizeKD: PROCEDURE; -- finalizes the local disk allocation mechanism. -- (4) Directory Manipulation -- -- Types and Related Constants -- DirHandle: TYPE = POINTER TO DirObject; DirObject: TYPE = MONITORED RECORD [ file: VMDefs.FileHandle, length: Position, buffer: VMDefs.Page, page: VMDefs.PageNumber, fp: FP, spacePos: Position, spaceNeeded: CARDINAL, spaceFound: CARDINAL, link: DirHandle, useCount: CARDINAL]; -- Procedures -- InitializeDirectory: PROCEDURE; -- initializes directory manipulation facilities. FinalizeDirectory: PROCEDURE; -- finalizes directory manipulation facilities. FlushDirectoryBuffer: PROCEDURE [dir: DirHandle]; -- eliminates any cached page buffer. ResetDirectoryLength: PROCEDURE [dir: DirHandle]; -- recomputes and stores the length of directory 'dir'. sysDir: DirHandle; -- a handle for the directory "SysDir". -- Statistics Logging -- loggingEnabled: BOOLEAN; -- indicates whether statistics logging is enabled. END.