-- FileStreamPrivate.mesa
-- Last edited by
-- MBrown on September 17, 1983 8:42 pm
-- Teitelman on May 26, 1982 4:52 pm
-- Last Edited by: Levin, September 22, 1983 2:48 pm
-- Last Edited by: Hagmann December 5, 1983 1:22 pm


DIRECTORY
  FileStream USING [ FinalizationProc ],
  FS USING [ErrorDesc, ExtendFileProc, Lock, OpenFile, StreamBufferParms, StreamOptions],
  IO USING [STREAM, StreamProcs],
  Rope USING [ROPE],
  VM USING [Interval];
  
FileStreamPrivate: CEDAR DEFINITIONS =
BEGIN
ROPE: TYPE = Rope.ROPE;

    -- DoFinalization should always be TRUE for released software.
    -- It is set to FALSE for testing.
 DoFinalization: BOOL = TRUE ;


 -- We model the behavior of a File IOStream with variables "file", "fileLen", and
 --"streamIndex", where
 -- file is an ARRAY [0..fileLen) OF CHAR
 -- streamIndex is an INT [0..fileLen]

 -- Key in this design is the assumption that a file stream will only be used by
 -- one process at a time. Processes are free to pass the stream around, but they must
 -- synchronize their access to the stream at a higher level than the stream. Two
 -- streams on the same file, the second one created by StreamFromOpenStream,
 -- do not need synchronization above the stream level unless the application requires it.

 -- The real stream contains a lot of redundant state to make the frequently-used
 --operations GetChar and PutChar fast. We shall list some invariant properties of
 --this state below. (Redundant properties, included for their intuitive value, are given in
 --parentheses.)

 -- We also define a piece of fictional state: trueDataBytesInBuffer.
 -- trueDataBytesInBuffer ::= MIN[bufferBytes, fileLen - firstByteInBuffer].
 -- trueDataBytesInBuffer is too expensive for PutByte to maintain at all times, but it
 --is useful for other operations.

 ProcHandle: TYPE = REF IO.StreamProcs;
 STREAM: TYPE = IO.STREAM;

    -- Exported by FileStreamImpl.mesa

 ProcHandleFromAccessRights: PROC [accessRights: FS.Lock]
  RETURNS [ProcHandle];

 SetupBuffer: PROC [fileData: FileDataHandle, fsData: FSDataHandle, fileByte: INT]
  RETURNS [currentNode: BufferNodeHandle] ;

ProcessNode: PROC [ fileData: FileDataHandle, node: BufferNodeHandle ] ;
    -- Exported by FileStreamProcessCacheImpl.mesa

 StartRequest: PROC [ fileData: FileDataHandle, node: BufferNodeHandle ] ;

 FSDataHandle: TYPE = REF Data;
 BufferNodeHandle: TYPE = REF BufferNode ;
 FileDataHandle: TYPE = REF FileData ;


        -- data kept on a per stream basis
 Data: TYPE = RECORD [
  index: CARDINAL ← 0,
   -- index is IN [0..currentNode.bufferBytes].
   -- currentNode.didPut AND index >= dataBytesInBuffer =>
   --  trueDataBytesInBuffer = index.
   -- This field has the property that is can be freely updated by the stream,
   -- and it can be read by the other streams under the monitor.
   -- It is always less than 64K, so that updates are always atomic (All D-machines
   -- write at least 16 bits at a time).
  currentNode: BufferNodeHandle ← NIL,
   -- All streams have a buffer of data in memory associated with the stream.
   -- This buffer may be empty
   -- This field is always non-NIL between calls the the package unless the
   -- stream has been closed.
   -- The control information for this buffer is a BufferNode.
   -- The node currently is use by this stream (and possibly other streams)
   -- is referred to via this field.
   -- Both currentNode and readAheadNode may only be changed under the
   -- monitor, and then only by this stream.
  readAheadNode: BufferNodeHandle ← NIL,
   -- If non-NIL, refers to buffer for read ahead data.
  lastFirstByteInBuffer: INT ← -1,
   -- This is the previous value in currentNode.firstByteInBuffer.
   -- It is used to detect sequentiality in reads in the preread logic.
   -- If this stream accesses buffer n, then buffer n+1, then if accesses buffer
   -- n+2 then a pre-read will be attempted given that there is more data in
   -- the file, there is a free buffer to use, and no other pre-read is in progress.
  isWriteStream: BOOL ← FALSE,
   -- If TRUE, then this record is referred to in fileData.writeStreamData and this
   -- stream was opened by StreamFromOpenFile with (logical) write access.
   -- If FALSE, this stream is referred to in fileData.firstReadStream, and was
   -- opened by StreamFromOpenFile with (logical) read access, or it was opened
   -- by StreamFromOpenStream.
  streamIsClosed: BOOL ← FALSE,
   -- stream.Close[] was called.
   -- (all operations should now raise StreamError[streamClosed]).
  fileData: FileDataHandle,
   -- Refers to the data that is related to the file and not to the stream (there can
   -- be multiple streams refering to the same file)
  FSErrorDesc: FS.ErrorDesc,
   -- last FS error on this stream. Initially set to [ok,NIL,NIL].
  StreamClassData: REF ANY ← NIL,
   -- data for use by FSStreamImpl or AlpineStreamImpl or other file system specific code.
  FinalizationProc: FileStream.FinalizationProc ← NIL
   -- Client supplied finalization procedure, if any.
];

   
NodeStatus: TYPE = {valid, invalid,
 needsParallelRead, parallelReadActive, needsSequentialRead, sequentialReadActive,
 needsParallelWrite, parallelWriteActive, needsSequentialWrite, sequentialWriteActive};
    -- valid - data in buffer is valid
    -- invalid - buffer not active, and data is not valid
    -- otherwise, need => this node has to have this action performed.
    --    Some process finds this, and does the action setting the node active.
   
       -- control information for a buffer
BufferNode: TYPE = RECORD [
  buffer: LONG POINTER TO PACKED ARRAY [0..0) OF CHAR ← NIL,
   -- buffer is really PACKED ARRAY [0..bufferBytes) OF CHAR.
  bufferInterval: VM.Interval ← TRASH,
   -- A space of pages for the stream buffer above.
   -- Although all buffers for a file stream are of the same length,
   -- this is kept on a per node basis so that a finalization routine can release
   -- the buffer space.
  bufferBytes: CARDINAL ← 0,
   -- Size of buffer in bytes
  dataBytesInBuffer: CARDINAL ← 0,
   -- dataBytesInBuffer is IN [0..trueDataBytesInBuffer] => IN [0..bufferBytes].
   -- NOT didPut OR (didPut AND index <= dataBytesInBuffer) =>
   -- trueDataBytesInBuffer = dataBytesInBuffer.
   -- The update of this field is protected by the monitor, but either the reader
   -- or the writer may do the update.
  firstFileByteInBuffer: INT ← -1,
   -- streamIndex = firstFileByteInBuffer + index.
   -- firstFileByteInBuffer < fileLen OR firstFileByteInBuffer = fileLen = 0.
   -- normally, firstFileByteInBuffer MOD bufferBytes = 0, but it is set to -1
   -- initally to indicate that this buffer does not match any file page.
   -- (buffer[0] is indentified with file[firstFileByteInBuffer]. There is always
   -- one file byte in the buffer unless file is empty.)
  didPut: BOOL ← FALSE,
   -- (somebody has done a Put and not updated dataBytesInBuffer, FileLength, and
   --bufferDirty).
  bufferDirty: BOOL ← FALSE,
   -- didPut OR bufferDirty => there exists some i IN [0..trueDataBytesInBuffer) such
   --that buffer[i] # file[i] as last read from file system.
   -- You must hold the monitor to update this entry.
  useCount: INT ← 0,
   -- Number of streams using this node. This reflects the fact that some Data record
   -- has currentNode or readAheadNode referring to this node. This can only be
   -- changed under the monitor, and outside the monitor is always the count of
   -- REFs pointing at this buffer.
  LRUCount: INT ← 0,
   -- This counter is used to try to do a LRU use of the buffers. To update, you need
   -- the monitor.
  status: NodeStatus ← invalid,
   -- Changing the status requires owning the monitor
  nextBufferNode: BufferNodeHandle ← NIL
   -- The nodes are kept as a linked list, starting with FileData.firstBufferNode.
   -- Modification requires the monitor.
];
   
        -- data kept on a per file basis
FileData: TYPE = RECORD [
  lockRecord: MONITORED RECORD [],
   -- Although the monitor is here, it logically covers many fields in BufferNode
   -- and Data records associated with this file.
  fileName: ROPE,
  firstBufferNode: BufferNodeHandle,
   -- first of a list of nodes for buffers.
   -- Update requires the monitor.
  firstReadStream: FSDataHandle ← NIL,
   -- First read stream or NIL if no readers
   -- Currently, there is only one reader.
   -- Update requires the monitor.
  accessRights: FS.Lock,
  tiogaReader: BOOL ← FALSE,
   -- TRUE iff file is being read as a Tioga file (reading the plain text only).
   --This implies that the file length shown in the stream is not the true file length,
   --but instead is the Tioga plain text length.
  fileLength: INT ← 0,
   -- NOT didPut => fileLen = fileLength.
   -- didPut AND index > dataBytesInBuffer => fileLen = firstFileByteInBuffer +
   -- index (index is from the writeStreamData).
  preReadInProgress: BOOL ← FALSE,
   -- Changed under the monitor, this is used to insure that only one pre-read
   -- occurs at a time.
  writeCount: INT ← 0,
   -- Count of writes pending. Changed only under the monitor.
   -- Currently this is not allowed to exceed 1.
  somethingHappened: CONDITION,
   -- General wait condition. It is BROADCAST when various interesting events
   -- occur such as the finish of a preread, and it is WAITed for by code that
   -- needs buffers or results from parallel processes.
  fileHandle: FS.OpenFile,
  streamBufferParms: FS.StreamBufferParms,
  extendFileProc: FS.ExtendFileProc,
  streamOptions: FS.StreamOptions,
  numberOfStreams: INT ← 1,
   -- The number of streams, read or write, that are open on this file.
   -- Do not close the file until this is 0.
   -- Except for initialization, this is modified under the monitor.
  byteLength: INT, --current value of fileHandle.OpenInfo[].bytes
  byteSize: INT, --current value of fileHandle.OpenInfo[].pages*bytesPerPage
  validBytesOnDisk: INT,
   -- The count of bytes on disk in the beginning of the file that are valid.
   -- Writing bytes past this count should not cause a read to fill the buffer.
  writeStreamData: FSDataHandle ← NIL
   -- refers to the write stream data (if any) for this file.
];

END.


CHANGE LOG

Created by MBrown on December 12, 1980 12:04 PM

Changed by MBrown on January 6, 1981 8:53 PM
-- Added Invalidate, added trans field to pilot data.

Changed by MBrown on January 16, 1981 10:00 AM
-- DataObject is now defined without using a Stream.Handle (copied structure from
--FileStreamImpl).

Changed by MBrown on January 18, 1981 1:00 AM
-- LeaderPage now defined here (but it uses something called FileStream.Subtype for its
--"dataType" field).

Changed by MBrown on 18-Jan-81 16:49:31
-- Added bufferDirty (for juniper stream use). and streamIsClosed (for diagnosis from
--the debugger). Improved the description of invariants.

Changed by MBrown on January 21, 1981 3:45 PM
-- Complete re-think of Pilot FileStream state, to make Put faster and generally reduce
--the number of expensive conversions betweeen pages and bytes. Not yet implemented.

Changed by MBrown on January 22, 1981 3:12 PM
-- Improved comments on invariants.

Changed by MBrown on January 25, 1981 8:19 PM
-- Added Juniper variant of Data.

Changed by MBrown on 27-Jan-81 15:10:07
-- FileByteStreamJuniper -> Juniper.

Changed by MBrown on 29-Jan-81 20:43:05
-- Added JOpen, POpen.

Changed by Russ Atkinson on 26-May-81 14:07:10
-- CedarString -> Rope, LONG CARDINAL -> LONG INTEGER

Changed by MBrown on 7-Dec-81 10:30:56
-- Conversion to IO, INT, ROPE, etc.

Changed by MBrown on March 26, 1982 4:40 pm
-- Added tiogaReader field (this is redundant, but may be useful for debugging), and the
--IsThisThingATiogaFile proc.

Changed by Teitelman on May 26, 1982 4:52 pm
-- changed to safe language, name change IOStream -> IO.

Changed by MBrown on August 23, 1982 2:18 pm
-- Eliminated TEXTDataOffset, added bufferParms, renamed JOpen -> JuniperOpen,
--POpen -> ComSoftOpen, added CIFSOpen, added CIFS open file to pilot variant of Data.

Changed by MBrown on May 16, 1983 2:03 pm
-- Eliminated Juniper stuff, added Alpine stuff.

Changed by MBrown on June 22, 1983 11:29 am
-- Eliminated Pilot stuff, added FS stuff.

Changed by MBrown on September 17, 1983 8:42 pm
-- Eliminated all procs, since file stream impl is one module (FS).

Changed by Hagmann on November 22, 1983 4:28 pm
-- added modifications for multiple buffering and multiple streams on the same file
-- added procs from split of FSFileIOImpl (since compiler blows up in pass 3)
-- Renamed to FileStreamPrivate from FSFileIOPrivate from FILEIOPrivate

Changed by Hagmann on November 28, 1983 11:57 am
-- added DoFinalization for help in testing

Changed by Hagmann on December 5, 1983
-- added ProcessNode and StartRequest for process cache
-- deleted process counts in FileData.