-- File: DBFilePilotImpl.mesa
-- Last edited by:
--   Rick Cattell on January 14, 1983 5:37 pm
--   MBrown on February 22, 1983 5:51 pm
--   Willie-Sue on February 22, 1983 5:51 pm
-- Last Edited by: Donahue, January 20, 1983 2:53 pm

  DIRECTORY
    DBCommon,
    DBEnvironment,
    DBFile,
    DBFilePilot,
    DBStats,
    DCSFileTypes USING [tLeaderPage],
    Directory USING [Lookup, ignore, CreateFile, Error, PutProperty],
    Environment USING [bytesPerPage],
    File USING [Capability, nullCapability, GetSize, grow, PageCount, Permissions,
      read, SetSize, shrink, write],
    Inline,
    PropertyTypes USING [tByteLength],
    Rope,
    Space,
    Transaction USING [Handle, nullHandle, Begin, Commit, Abort];

DBFilePilotImpl: PROGRAM
  IMPORTS
    DBEnvironment,
    DBStats,
    Directory,
    File,
    Inline,
    Rope,
    Space,
    Transaction
  EXPORTS
    DBFilePilot
  SHARES
    File
  = BEGIN
  VersionOptions: TYPE = DBCommon.VersionOptions;

  -- Work around Space.CopyIn/CopyOut and uniform swap units crock ...
  space: Space.Handle;
  longPointer: LONG POINTER;

  PilotTrans: TYPE = DBFilePilot.PilotTrans;
  PilotTransRecord: TYPE = DBFilePilot.PilotTransRecord;

  PilotOpenFileHandle: TYPE = DBFilePilot.PilotOpenFileHandle;
  PilotOpenFileRecord: TYPE = DBFilePilot.PilotOpenFileRecord;


  CreateTransaction: PUBLIC PROC [] RETURNS [t: PilotTrans] = {
    DBStats.Starting[PilotFileCreateTransaction];
    t ← NEW[PilotTransRecord ← [trans: Transaction.Begin[]]];
    DBStats.Stopping[PilotFileCreateTransaction];
    RETURN[t]
    };

  FinishTransaction: PUBLIC PROC [t: PilotTrans, abort: BOOL, continue: BOOL] = {
    IF t.trans = Transaction.nullHandle THEN RETURN;
    DBStats.Starting[PilotFileFinishTransaction];
    IF abort THEN Transaction.Abort[t.trans] ELSE Transaction.Commit[t.trans];
    IF NOT abort AND continue THEN t.trans ← Transaction.Begin[];
    DBStats.Stopping[PilotFileFinishTransaction];
    };
    
  RightBracket: Rope.ROPE = Rope.FromChar[']];

  StripDirectory: PROC [name: Rope.ROPE] RETURNS [result: Rope.Text] = {
    -- removes everything preceding the last '] in name, returns a TEXT rope.
    currentIndex: LONG INTEGER ← 0;
    nextIndex: LONG INTEGER ← -1;
    size: LONG INTEGER = Rope.Size[name];
    UNTIL (nextIndex ← Rope.Index[s1: name, pos1: currentIndex, s2: RightBracket]) = size DO
      currentIndex← nextIndex+1
      ENDLOOP;
    RETURN [Rope.Flatten[base: name, start: currentIndex]] }; 

  OpenFile: PUBLIC PROC [
    t: PilotTrans, file: Rope.Text, version: VersionOptions, nPagesInitial: INT]
    RETURNS [f: PilotOpenFileHandle, createdFile: BOOL] = {
    nameWithoutDirectory: Rope.Text;
    DBStats.Starting[PilotFileOpen];
    f ← NEW[PilotOpenFileRecord ← [trans: t, file: File.nullCapability]];
    createdFile ← FALSE;
    nameWithoutDirectory ← StripDirectory[file];
    f.file ← Directory.Lookup[
      fileName: LOOPHOLE[nameWithoutDirectory], permissions: Directory.ignore !
      Directory.Error => SELECT type FROM
	     fileNotFound => { createdFile ← TRUE; CONTINUE };
        invalidFileName, fileIsSD => ERROR DBEnvironment.Error[IllegalFileName];
        volumeNotFound => ERROR DBEnvironment.Fatal[Unknown];
        ENDCASE => ERROR ];
    IF version = OldFileOnly AND createdFile THEN
      ERROR DBEnvironment.Error[FileNotFound];
    IF version = NewFileOnly AND NOT createdFile THEN
      ERROR DBEnvironment.InternalError; -- Model level never uses NewFileOnly 
    IF createdFile THEN {
      f.file ← Directory.CreateFile[
        fileName: LOOPHOLE[nameWithoutDirectory],
        fileType: DCSFileTypes.tLeaderPage, size: nPagesInitial];
      };
    f.file.permissions ← File.read+File.write+File.grow+File.shrink;
    DBStats.Stopping[PilotFileOpen];
    };

  ReadFilePage: PUBLIC PROC [
    f: PilotOpenFileHandle, p: CARDINAL, corePage: LONG POINTER] = {
    DBStats.Starting[PilotFileReadPage];
    Space.CopyIn[
      space: space, window: [f.file, LONG[p]+1], transaction: Transaction.nullHandle];
    Inline.LongCOPY[from: longPointer, to: corePage, nwords: DBCommon.WordsPerPage];
    DBStats.Stopping[PilotFileReadPage];
    };

  WriteFilePage: PUBLIC PROC [
    f: PilotOpenFileHandle, p: CARDINAL, corePage: LONG POINTER] = {
    DBStats.Starting[PilotFileWritePage];
    Inline.LongCOPY[to: longPointer, from: corePage, nwords: DBCommon.WordsPerPage];
    Space.CopyOut[
      space: space, window: [f.file, LONG[p]+1], transaction: f.trans.trans];
    DBStats.Stopping[PilotFileWritePage];
    };

  GetSize: PUBLIC PROC [f: PilotOpenFileHandle] RETURNS [nPages: CARDINAL] = {
    len: LONG CARDINAL;
    DBStats.Starting[PilotFileGetSize];
    len ← File.GetSize[file: f.file, transaction: f.trans.trans];
    IF len = 0 THEN ERROR DBEnvironment.InternalError; --leader page
    DBStats.Stopping[PilotFileGetSize];
    RETURN [len-1];
    };

  SetSize: PUBLIC PROC [f: PilotOpenFileHandle, nPages: CARDINAL] = {
    newLength: LONG CARDINAL;
    DBStats.Starting[PilotFileSetSize];
    File.SetSize[file: f.file, size: LONG[nPages]+1, transaction: f.trans.trans];
    newLength ← LONG[nPages] * Environment.bytesPerPage;
    Directory.PutProperty[file: f.file, property: PropertyTypes.tByteLength,
  	propertyValue: DESCRIPTOR[@newLength, SIZE[LONG CARDINAL]]];
    DBStats.Stopping[PilotFileSetSize];
    };

  space ← Space.Create[size: DBCommon.PagesPerDBPage, parent: Space.virtualMemory];
  Space.Map[space];
  longPointer ← Space.LongPointer[space];

  END.

CHANGE LOG


Created by MBrown on February 28, 1981  3:08 PM

Changed by MBrown on 2-Mar-81 10:44:37
-- Forgot to CONTINUE out of a catch phrase, and didn't have the necessary symbols on my disk
--to figure it out.  A multi-hour waste of time.

Changed by MBrown on 2-Mar-81 11:21:27
-- Added a level of indirection in the representation of transaction.  This is to allow
--commit without losing the transaction, like Juniper does.

Changed by MBrown on 1-Apr-81 20:26:22
-- CopyIn takes a nullHandle for a transaction, since we don't care about the state of the
--buffer pool after a crash(!)

Changed by MBrown on 19-Jun-81 21:06:23
-- STRING -> Rope.Ref.

Changed by MBrown on 15-Jul-81 13:10:23
-- Bug in StripDirectory: indexed to position -1 in string instead of 0.

Changed by Cattell on  4-Aug-81 20:35:54
-- Bug in Mark's fix above: StripDirectory now lost first character if no directory in name.

Changed by Willie-Sue on June 25, 1982 9:30 am
-- Rope.Ref => Rope.ROPE

Changed by Cattell on July 15, 1982 7:47 pm
-- Widespread changes due to changes to FileHandle, Transaction representation.   Using DBCommon.Transaction, DBFile.FileHandles which are REFs to variants.  The former is identical to FileIO.TransHandle.  No longer need any FREEs.

Changed by MBrown on August 7, 1982 9:45 pm
-- Eliminate import of heap storage allocator.

Changed by MBrown on November 29, 1982 1:58 pm
-- New DBFilePilot interface.

Changed by Rick on January 4, 1983 3:18 pm
-- Bug in StripDirectory: local file names are normally of form "[Local]foo", so should strip
-- everything from either "]" onward, not ">".  May change this again later, so didn't change
-- name of StripDirectory, etc.

Changed by Rick and Willie-Sue on January 7, 1983 10:28 am
-- test in FinishTransaction for Transaction.nullHandle
 
Changed by Rick January 20, 1983 2:53 pm
--Refixed change lost by Mark's fix to update file size! (to error generation)
 
Changed by MBrown on February 22, 1983 3:45 pm
-- Work around Space.CopyIn/CopyOut and uniform swap units crock by introducing
--global 1 DB page buffer, and Inline.LongCOPY on each page transfer.