-- FileInstanceImpl.mesa
-- Last edited by
-- Kolling on November 2, 1983 4:09 pm
DIRECTORY
AlpineEnvironment
USING[FileID, LockMode, PageCount, VolumeID],
AlpineInternal
USING[FileHandle, TransHandle],
FileInstance,
FileMap
USING[GetFileID, GetVolumeID, GetVolumeIDAndFileID, Register],
TransactionMap
USING[GetFileInstanceList, SetFileInstanceList];
FileInstanceImpl: CEDAR MONITOR
IMPORTS FileMap, TM: TransactionMap
EXPORTS AlpineInternal, FileInstance =
BEGIN OPEN AE: AlpineEnvironment, AI: AlpineInternal;
Handle: TYPE = REF FileInstanceObject;
FileInstanceObject: PUBLIC TYPE = RECORD[
trans: AI.TransHandle,
fileHandle: AI.FileHandle,
useCount: CARDINAL,
deltaVersion: LONG INTEGER,
highWaterMark: AE.PageCount,
lockMode: AE.LockMode,
nextForTrans: Handle];
-- errors:
InUse: --CALLING-- ERROR = CODE;
OldHandleNotFound: --CALLING-- ERROR = CODE;
UseCountAlreadyZero: --CALLING-- ERROR = CODE;
-- Finds or creates a Handle for the supplied trans, volume, and file, and increments use count on the returned handle. If the handle is created, it is also entered in the FileInstance list for its transaction and FileMap.Register is called.
Register: PUBLIC ENTRY PROCEDURE [trans: AI.TransHandle, volumeID: AE.VolumeID, fileID:
AE.FileID] RETURNS [handle: Handle] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
firstInsHandle: Handle;
TRUSTED BEGIN firstInsHandle ← TM.GetFileInstanceList[trans]; END;
FOR handle ← firstInsHandle, handle.nextForTrans
UNTIL handle = NIL
DO
IF FileMap.GetVolumeIDAndFileID[handle.fileHandle] = [volumeID, fileID]
THEN GOTO found;
REPEAT
found => handle.useCount ← handle.useCount + 1;
FINISHED => BEGIN handle ← NEW[FileInstanceObject ← [trans:
trans, fileHandle: FileMap.Register[volumeID, fileID], useCount: 1,
deltaVersion: 0, highWaterMark: LAST[AE.PageCount], lockMode: none,
nextForTrans: firstInsHandle]];
TRUSTED BEGIN TM.SetFileInstanceList[trans, handle]; END;
END;
ENDLOOP;
END;
-- Decrements use count on handle. If the use count becomes zero and delta version is 0 (i.e., if the file has not been updated), deletes it from the FileInstance list for its transaction. (Updated files are taken care of by FlushTransState.)
Unregister: PUBLIC ENTRY PROCEDURE [handle: Handle] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
IF handle.useCount = 0 THEN RETURN WITH ERROR UseCountAlreadyZero;
IF (((handle.useCount ← handle.useCount - 1) = 0) AND (handle.deltaVersion = 0))
THEN TRUSTED BEGIN
prevInsHandle: Handle ← FindHandle[handle.fileHandle,
TM.GetFileInstanceList[handle.trans]];
IF prevInsHandle = NIL
THEN TM.SetFileInstanceList[handle.trans, handle.nextForTrans]
ELSE prevInsHandle.nextForTrans ← handle.nextForTrans;
END;
END;
-- When this is called, it is a error if any handle in this transaction's FileInstance list has useCount # 0 or delta version = 0.
FlushTransState: PUBLIC ENTRY PROCEDURE [trans: AI.TransHandle] =
TRUSTED BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
FOR insHandle: Handle ← TM.GetFileInstanceList[trans], insHandle.nextForTrans
UNTIL insHandle = NIL
DO IF ((insHandle.useCount # 0) OR (insHandle.deltaVersion = 0))
THEN RETURN WITH ERROR InUse;
ENDLOOP;
TM.SetFileInstanceList[trans, NIL];
END;
-- Access to immutable attributes.
GetFileHandle: PUBLIC PROCEDURE [handle: Handle] RETURNS [fileHandle:
AI.FileHandle] =
BEGIN -- errors defined in FileInstance: none.
RETURN[handle.fileHandle];
END;
GetTransHandle: PUBLIC PROCEDURE [handle: Handle] RETURNS [trans: AI.TransHandle] =
BEGIN -- errors defined in FileInstance: none.
RETURN[handle.trans];
END;
GetVolumeID: PUBLIC PROCEDURE [handle: Handle] RETURNS [volumeID:
AE.VolumeID] =
BEGIN -- errors defined in FileInstance: none.
RETURN[FileMap.GetVolumeID[handle.fileHandle]];
END;
GetFileID: PUBLIC PROCEDURE [handle: Handle] RETURNS [fileID: AE.FileID] =
BEGIN -- errors defined in FileInstance: none.
RETURN[FileMap.GetFileID[handle.fileHandle]];
END;
GetVolumeIDAndFileID: PUBLIC PROCEDURE [handle: Handle] RETURNS [volumeID:
AE.VolumeID, fileID: AE.FileID] =
BEGIN -- errors defined in FileInstance: none.
[volumeID, fileID] ← FileMap.GetVolumeIDAndFileID[handle.fileHandle];
END;
-- Access to read/write attributes.
GetDeltaVersion: PUBLIC ENTRY PROCEDURE [handle: Handle] RETURNS [delta: LONG
INTEGER] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
RETURN[handle.deltaVersion];
END;
-- Sets the delta version to the MAX of increment and its existing value.
SetMaxDeltaVersion: PUBLIC ENTRY PROCEDURE [handle: Handle, increment: LONG
INTEGER] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
handle.deltaVersion ← MAX[handle.deltaVersion, increment];
END;
-- Returns the uncommitted highWaterMark, for this transaction. Initialize value is LAST[PageCount].
GetHighWaterMark: PUBLIC ENTRY PROCEDURE [handle: Handle] RETURNS
[highWaterMark: AE.PageCount] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
RETURN[handle.highWaterMark];
END;
SetHighWaterMark: PUBLIC ENTRY PROCEDURE [handle: Handle, highWaterMark:
AE.PageCount] RETURNS [oldHighWaterMark: AE.PageCount] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
oldHighWaterMark ← handle.highWaterMark;
handle.highWaterMark ← highWaterMark;
END;
GetLockMode: PUBLIC ENTRY PROCEDURE [handle: Handle] RETURNS [lock: AE.LockMode] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
RETURN[handle.lockMode];
END;
SetLockMode: PUBLIC ENTRY PROCEDURE [handle: Handle, lock: AE.LockMode] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
handle.lockMode ← lock;
END;
-- Enumeration.
-- handle = NIL starts a new enumeration, and nextHandle = NIL is returned when the
-- enumeration is exhausted. The FileInstance list is assumed to not be being modified during
-- this enumeration. When handle is non-NIL, not finding it is a fatal error.
GetNextHandleForTrans: PUBLIC ENTRY PROCEDURE [trans: AI.TransHandle, handle:
Handle] RETURNS [nextHandle: Handle] =
BEGIN -- errors defined in FileInstance: none.
ENABLE UNWIND => NULL;
firstInsHandle: Handle;
TRUSTED BEGIN firstInsHandle ← TM.GetFileInstanceList[trans]; END;
IF handle = NIL THEN RETURN[firstInsHandle];
[] ← FindHandle[handle.fileHandle, firstInsHandle];
RETURN[handle.nextForTrans];
END;
FindHandle: INTERNAL PROCEDURE [fileHandle: AI.FileHandle, firstInsHandle: Handle]
RETURNS [prevHandle: Handle] =
BEGIN -- errors defined in FileInstance: none.
volumeID: AE.VolumeID;
fileID: AE.FileID;
[volumeID, fileID] ← FileMap.GetVolumeIDAndFileID[fileHandle];
prevHandle ← NIL;
FOR foundHandle: Handle ← firstInsHandle, foundHandle.nextForTrans
UNTIL foundHandle = NIL
DO
IF FileMap.GetVolumeIDAndFileID[foundHandle.fileHandle] = [volumeID, fileID]
THEN EXIT;
prevHandle ← foundHandle;
REPEAT FINISHED => ERROR OldHandleNotFound;
ENDLOOP;
END;
-- main line code.
END.
Edit Log
Initial: Kolling: October 21, 1982 2:22 pm: an impl module for FileInstance.