-- 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.