-- File: DBFileAlpineImpl.mesa
-- Last edited by:
-- MBrown on April 22, 1983 3:03 pm
-- Kolling on April 27, 1983 12:37 pm


DIRECTORY
AlpineEnvironment
USING[bytesPerPage, Conversation, FileID, nullFileID, OpenFileID, Outcome, PageCount,
PageNumber, TransID, VolumeID, wordsPerPage],
AlpFile
USING[GetSize, Handle, Open, ReadPages, SetSize, WritePages, WriteProperties],
AlpineInterimDirectory
USING[Error, Open],
AlpInstance
USING[Create, Failed, Handle, Unknown],
AlpTransaction
USING[Create, Handle, Finish],
DBEnvironment
USING[Aborted, Error],
DBCommon
USING[VersionOptions],
DBFileAlpine,
DBStats
USING[Starting, Stopping],
FileIO
USING[CreateOptions],
RPC
USING[CallFailed],
Rope
USING[ROPE, Text];

DBFileAlpineImpl: PROGRAM
IMPORTS AlpF: AlpFile, AE: AlpineEnvironment, AlpineInterimDirectory, AlpI: AlpInstance,
AlpT: AlpTransaction, DBEnvironment, DBStats, RPC
EXPORTS DBFileAlpine

= BEGIN

ROPE: TYPE = Rope.ROPE;
VersionOptions: TYPE = DBCommon.VersionOptions;
VolumeID: TYPE = AE.VolumeID;
FileID: TYPE = AE.FileID;
nullFileID: FileID = AE.nullFileID;
OpenFileID: TYPE = AE.OpenFileID;
TransID: TYPE = AE.TransID;
Conversation: TYPE = AE.Conversation;
PageNumber: TYPE = AE.PageNumber;
PageCount: TYPE = AE.PageCount;
bytesPerPage: INT = AE.bytesPerPage;

AlpineTrans: TYPE = REF ANY;
-- must narrow to AlpTransaction.Handle
AlpineOpenFileHandle: TYPE = REF ANY;
-- must narrow to AlpFile.Handle

CreateTransaction: PUBLIC PROC [server: ROPE] RETURNS [t: AlpineTrans] = {
DBStats.Starting[AlpineFileCreateTransaction];
DO
instance: AlpI.Handle ← AlpI.Create[fileStore: server
! AlpI.Failed => IF why # authenticateFailed THEN LOOP];
t ← AlpT.Create[instance
! RPC.CallFailed => IF why = unbound THEN LOOP];
EXIT;
ENDLOOP
;
DBStats.Stopping[AlpineFileCreateTransaction];
RETURN[t]
};

FinishTransaction: PUBLIC PROC [t: AlpineTrans, abort: BOOL, continue: BOOL] = {
outcome: AE.Outcome;
transHandle: AlpT.Handle = NARROW[t];
DBStats.Starting[AlpineFileFinishTransaction];
outcome ← transHandle.Finish[
requestedOutcome: IF abort THEN abort ELSE commit,
continue: continue];
IF NOT abort AND outcome = abort THEN ERROR DBEnvironment.Aborted[t];
DBStats.Stopping[AlpineFileFinishTransaction];
};

CreateOptionsFromVersionOptions:
ARRAY VersionOptions OF FileIO.CreateOptions =
[NewFileOnly: newOnly, OldFileOnly: oldOnly, None: none];

OpenFile: PUBLIC PROC [t: AlpineTrans, file: Rope.Text,
version: VersionOptions, discardFileContents: BOOL, nPagesInitial: INT, noLog: BOOL]
RETURNS [f: AlpineOpenFileHandle, createdFile: BOOL] = {
ENABLE AlpI.Unknown => SELECT what FROM
transID, openFileID => ERROR DBEnvironment.Aborted[t];
ENDCASE => REJECT;
volumeID: VolumeID; fileID: FileID;
transHandle: AlpT.Handle = NARROW[t];
fileHandle: AlpF.Handle;
DBStats.Starting[AlpineFileOpen];
[volumeID, fileID, createdFile] ← AlpineInterimDirectory.Open[
file, CreateOptionsFromVersionOptions[version], nPagesInitial*bytesPerPage !
AlpineInterimDirectory.Error =>
SELECT why FROM
illegalFileName => ERROR DBEnvironment.Error[IllegalFileName];
ownerNotFound, fileNotFound => ERROR DBEnvironment.Error[FileNotFound];
serverNotFound => ERROR DBEnvironment.Error[ServerNotFound];
fileAlreadyExists => ERROR DBEnvironment.Error[AlreadyExists];
lockFailed, transAborted => RETRY;
serverBusy, remoteCallFailed, regServersUnavailable => REJECT;
ENDCASE => REJECT]; -- DirectoryInconsistent {ownerRootFileNotFound}, Error[authenticateFailed, damaged, insufficientPermission, ownerRecordFull, quota}.
{ ENABLE AlpI.Unknown => SELECT what FROM
transID, openFileID => ERROR DBEnvironment.Aborted[t];
ENDCASE => REJECT;
fileHandle ← AlpF.Open[transHandle, volumeID, fileID, $readWrite, [$write, $wait],
IF noLog THEN $noLog ELSE $log, $random];
IF NOT createdFile AND discardFileContents THEN
fileHandle.WriteProperties[properties: LIST[[highWaterMark[highWaterMark: 0]]]];
};
DBStats.Stopping[AlpineFileOpen];
RETURN [fileHandle, createdFile];
};

ReadFilePage: PUBLIC PROC [
f: AlpineOpenFileHandle, p: CARDINAL, corePage: LONG POINTER] = {
fileHandle: AlpF.Handle = NARROW[f];
DBStats.Starting[AlpineFileReadPage];
fileHandle.ReadPages[
pageRun: [firstPage: p],
pageBuffer: DESCRIPTOR [corePage, AE.wordsPerPage] !
AlpI.Unknown => SELECT what FROM
transID, openFileID => ERROR DBEnvironment.Aborted[fileHandle.trans];
ENDCASE => REJECT];
DBStats.Stopping[AlpineFileReadPage];
};

WriteFilePage: PUBLIC PROC [
f: AlpineOpenFileHandle, p: CARDINAL, corePage: LONG POINTER] = {
fileHandle: AlpF.Handle = NARROW[f];
DBStats.Starting[AlpineFileWritePage];
fileHandle.WritePages[
pageRun: [firstPage: p],
pageBuffer: DESCRIPTOR [corePage, AE.wordsPerPage] !
AlpI.Unknown => SELECT what FROM
transID, openFileID => ERROR DBEnvironment.Aborted[fileHandle.trans];
ENDCASE => REJECT];
DBStats.Stopping[AlpineFileWritePage];
};

GetSize: PUBLIC PROC [f: AlpineOpenFileHandle] RETURNS [nPages: CARDINAL] = {
size: INT;
fileHandle: AlpF.Handle = NARROW[f];
DBStats.Starting[AlpineFileGetSize];
size ← fileHandle.GetSize[ !
AlpI.Unknown => SELECT what FROM
transID, openFileID => ERROR DBEnvironment.Aborted[fileHandle.trans];
ENDCASE => REJECT];
DBStats.Stopping[AlpineFileGetSize];
RETURN [size];
};

SetSize: PUBLIC PROC [f: AlpineOpenFileHandle, nPages: CARDINAL] = {
fileHandle: AlpF.Handle = NARROW[f];
DBStats.Starting[AlpineFileSetSize];
{ ENABLE AlpI.Unknown => SELECT what FROM
transID, openFileID => ERROR DBEnvironment.Aborted[fileHandle.trans];
ENDCASE => REJECT;
fileHandle.SetSize[size: nPages];
fileHandle.WriteProperties[properties: LIST[[byteLength[byteLength: nPages*bytesPerPage]]]];
DBStats.Stopping[AlpineFileSetSize]
};
DBStats.Stopping[AlpineFileSetSize];
};

END.