DBFileAlpineImpl.mesa - Alpine implementation of file level of Cypress
Copyright © 1985 by Xerox Corporation. All rights reserved.
MBrown on June 7, 1983 4:40 pm
Kolling on May 12, 1983 3:35 pm
Cattell on May 10, 1984 7:13:38 pm PDT
Wert, August 9, 1984 2:18:42 pm PDT
Willie-Sue, April 25, 1985 12:52:32 pm PST
Russ Atkinson (RRA) March 20, 1985 9:35:05 pm PST
Carl Hauser, May 14, 1985 1:50:01 pm PDT
Widom, July 22, 1985 2:29:32 pm PDT
Donahue, December 31, 1985 2:45:08 pm PST
DIRECTORY
AlpineEnvironment USING[bytesPerPage, Conversation, LockOption, OpenFileID, Outcome, PageCount, PageNumber, TransID, UniversalFile, wordsPerPage, PropertyValuePair],
AlpFile USING[Close, GetSize, Handle, ReadPages, SetSize, PropertySet, WritePages, ReadProperties, WriteProperties],
AlpineDirectory USING[Error, OpenFile, CreateOptions],
AlpInstance USING[AccessFailed, Create, Failed, Handle, Unknown],
AlpTransaction USING[Create, Handle, Finish, OperationFailed],
DB USING[Aborted, Failure, Error],
DBCommon USING[VersionOptions],
DBFileAlpine,
DBStats USING[Starting, Stopping],
RPC USING[CallFailed],
Rope USING[ROPE, Text];
DBFileAlpineImpl: CEDAR PROGRAM
IMPORTS AlpFile, AlpineDirectory, AlpInstance, AlpTransaction, DB, DBStats, RPC
EXPORTS DBFileAlpine
= BEGIN OPEN AE: AlpineEnvironment;
ROPE: TYPE = Rope.ROPE;
VersionOptions: TYPE = DBCommon.VersionOptions;
bytesPerPage: INT = AE.bytesPerPage;
Conversation: TYPE = AE.Conversation;
OpenFileID: TYPE = AE.OpenFileID;
PageCount: TYPE = AE.PageCount;
PageNumber: TYPE = AE.PageNumber;
TransID: TYPE = AE.TransID;
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] = {
needRetry: BOOLFALSE;
haveRetried: BOOLFALSE;
transHandle: AlpTransaction.Handle;
DBStats.Starting[AlpineFileCreateTransaction];
DO
instance: AlpInstance.Handle ← AlpInstance.Create[fileStore: server ! AlpInstance.Failed =>
IF why = authenticateFailed THEN ERROR DB.Error[BadUserPassword]
ELSE ERROR DB.Failure[$communication, server]
];
transHandle ← AlpTransaction.Create[instance !
AlpTransaction.OperationFailed => IF why = busy THEN
ERROR DB.Failure[$serverBusy, server];
RPC.CallFailed => TRUSTED {
IF why = unbound THEN {needRetry ← TRUE; CONTINUE}
a moderately likely failure, due to the instance cache
ELSE IF why IN [timeout .. busy] THEN
ERROR DB.Failure[$communication, server]}
];
IF NOT needRetry THEN EXIT;
IF haveRetried THEN
ERROR DB.Failure[$communication, transHandle.inst.fileStore];
needRetry ← FALSE; haveRetried ← TRUE;
ENDLOOP;
DBStats.Stopping[AlpineFileCreateTransaction];
RETURN[transHandle]
};
FinishTransaction: PUBLIC PROC [t: AlpineTrans, abort: BOOL, continue: BOOL] = {
outcome: AE.Outcome;
transHandle: AlpTransaction.Handle = NARROW[t];
DBStats.Starting[AlpineFileFinishTransaction];
outcome ← transHandle.Finish[
requestedOutcome: IF abort THEN abort ELSE commit,
continue: continue ! RPC.CallFailed => TRUSTED {
IF why IN [timeout .. busy] THEN
IF abort THEN {outcome ← abort; CONTINUE} -- so can escape when no communication!
ELSE ERROR
DB.Failure[$communication, transHandle.inst.fileStore]}
];
IF NOT abort AND outcome = abort THEN ERROR DB.Aborted;
DBStats.Stopping[AlpineFileFinishTransaction];
};
CreateOptionsFromVersionOptions:
ARRAY VersionOptions OF AlpineDirectory.CreateOptions =
[NewFileOnly: newOnly, OldFileOnly: oldOnly, None: none];
VersionNumberFromOpenFile: PUBLIC PROC [f: AlpineOpenFileHandle]
RETURNS
[versionNumber: INT] = {
fileHandle: AlpFile.Handle = NARROW[f];
BEGIN ENABLE BEGIN
AlpInstance.Unknown => SELECT what FROM
transID, openFileID => ERROR DB.Aborted;
ENDCASE => REJECT;
RPC.CallFailed => TRUSTED {
IF why IN [timeout .. busy] THEN
ERROR DB.Failure[$communications, fileHandle.trans.inst.fileStore]};
END;
versionList: LIST OF AlpineEnvironment.PropertyValuePair;
versionProp: AlpFile.PropertySet;
IF fileHandle = NIL THEN RETURN[versionNumber: 0];
versionProp[version] ← TRUE;
versionList ← fileHandle.ReadProperties[versionProp];
versionNumber ←
NARROW[versionList.first, AlpineEnvironment.PropertyValuePair[version]].version;
END;
};
OpenFile: PUBLIC PROC [t: AlpineTrans, file: Rope.Text, version: VersionOptions, discardFileContents: BOOL, nPagesInitial: INT, lock: AlpineEnvironment.LockOption, readOnly: BOOL] RETURNS [f: AlpineOpenFileHandle, createdFile: BOOL] = {
ENABLE
AlpInstance.Unknown => SELECT what FROM
transID, openFileID => ERROR DB.Aborted;
ENDCASE => REJECT;
transHandle: AlpTransaction.Handle = NARROW[t];
fileHandle: AlpFile.Handle;
refUniversalFile: REF AE.UniversalFile ← NIL;
DBStats.Starting[AlpineFileOpen];
TRUSTED BEGIN
ENABLE {
AlpineDirectory.Error =>
SELECT type FROM
authenticateFailed => ERROR DB.Error[BadUserPassword];
damaged, ownerRecordFull => REJECT;
fileAlreadyExists => ERROR DB.Error[AlreadyExists];
fileNotFound, ownerNotFound => ERROR DB.Error[FileNotFound];
illegalFileName => ERROR DB.Error[IllegalFileName];
insufficientPermission => ERROR DB.Error[ProtectionViolation];
lockFailed, transAborted =>
ERROR DB.Failure[$lockConflict, transHandle.inst.fileStore];
quota => ERROR DB.Error[QuotaExceeded];
remoteCallFailed, regServersUnavailable, serverNotFound =>
ERROR DB.Failure[$communication, transHandle.inst.fileStore];
serverBusy =>
ERROR DB.Failure[$serverBusy, transHandle.inst.fileStore];
ENDCASE => REJECT; -- DirectoryInconsistent {ownerRootFileNotFound}
RPC.CallFailed => IF why IN [timeout .. busy] THEN ERROR
DB.Failure[$communications, transHandle.inst.fileStore];
};
[fileHandle, createdFile, ] ← AlpineDirectory.OpenFile[trans: transHandle, name: file, access: IF readOnly THEN readOnly ELSE readWrite, lock: lock, recoveryOption: $log, createOptions: CreateOptionsFromVersionOptions[version], referencePattern: $random ! AlpInstance.AccessFailed => DB.Error[ProtectionViolation] ]
END;
IF NOT createdFile AND discardFileContents THEN
fileHandle.WriteProperties[properties: LIST[[highWaterMark[highWaterMark: 0]]]];
DBStats.Stopping[AlpineFileOpen];
RETURN [fileHandle, createdFile];
};
Close: PUBLIC PROC [f: AlpineOpenFileHandle] ~ {
fileHandle: AlpFile.Handle = NARROW[f];
AlpFile.Close[fileHandle]
};
ReadFilePage: PUBLIC PROC [f: AlpineOpenFileHandle, p: CARDINAL, corePage: LONG POINTER] = {
fileHandle: AlpFile.Handle = NARROW[f];
DBStats.Starting[AlpineFileReadPage];
{ ENABLE BEGIN
AlpInstance.Unknown => SELECT what FROM
transID, openFileID => ERROR DB.Aborted;
ENDCASE => REJECT;
RPC.CallFailed => TRUSTED {
IF why IN [timeout .. busy] THEN
ERROR DB.Failure[$communications, fileHandle.trans.inst.fileStore]};
END;
TRUSTED {
fileHandle.ReadPages[
pageRun: [firstPage: p], pageBuffer: DESCRIPTOR [corePage, AE.wordsPerPage]];
};
};
DBStats.Stopping[AlpineFileReadPage];
};
WriteFilePage: PUBLIC PROC [
f: AlpineOpenFileHandle, p: CARDINAL, corePage: LONG POINTER] = {
fileHandle: AlpFile.Handle = NARROW[f];
DBStats.Starting[AlpineFileWritePage];
{ ENABLE BEGIN
AlpInstance.Unknown => SELECT what FROM
transID, openFileID => TRUSTED {ERROR DB.Aborted};
ENDCASE => REJECT;
RPC.CallFailed => TRUSTED {IF why IN [timeout .. busy] THEN
ERROR DB.Failure[$communications, fileHandle.trans.inst.fileStore]};
END;
TRUSTED {
fileHandle.WritePages[
pageRun: [firstPage: p], pageBuffer: DESCRIPTOR [corePage, AE.wordsPerPage]];
};
};
DBStats.Stopping[AlpineFileWritePage];
};
GetSize: PUBLIC PROC [f: AlpineOpenFileHandle] RETURNS [nPages: CARDINAL] = {
size: INT;
fileHandle: AlpFile.Handle = NARROW[f];
DBStats.Starting[AlpineFileGetSize];
{ ENABLE BEGIN
AlpInstance.Unknown => SELECT what FROM
transID, openFileID => ERROR DB.Aborted;
ENDCASE => REJECT;
RPC.CallFailed => TRUSTED { IF why IN [timeout .. busy] THEN
ERROR DB.Failure[$communications, fileHandle.trans.inst.fileStore]};
END;
size ← fileHandle.GetSize[];
};
DBStats.Stopping[AlpineFileGetSize];
RETURN [size];
};
SetSize: PUBLIC PROC [f: AlpineOpenFileHandle, nPages: CARDINAL] = {
fileHandle: AlpFile.Handle = NARROW[f];
DBStats.Starting[AlpineFileSetSize];
{ ENABLE BEGIN
AlpInstance.Unknown => SELECT what FROM
transID, openFileID => TRUSTED {ERROR DB.Aborted};
ENDCASE => REJECT;
RPC.CallFailed => TRUSTED { IF why IN [timeout .. busy] THEN
ERROR DB.Failure[$communications, fileHandle.trans.inst.fileStore]};
END;
fileHandle.SetSize[size: nPages];
fileHandle.WriteProperties[properties: LIST[[byteLength[byteLength: nPages*bytesPerPage]]]];
};
DBStats.Stopping[AlpineFileSetSize];
};
END.
Changed by wert on July 26, 1984 4:35:07 pm PDT
added VersionNumberFromOpenFile[]
Changed by wert on August 9, 1984 2:16:26 pm PDT
hacked VersionNumberFromOpenFile[] to check for a NIL fileHandle
Changed by Willie-Sue on February 15, 1985
made Cedar, added tioga formatting, took out VersionNumberFromOpenFile[]; added trans argument to DB.Failure
Changed by Willie-Sue on April 25, 1985
put back in VersionNumberFromOpenFile[openFile]
Carl Hauser, May 14, 1985 1:49:02 pm PDT
changes to: DBFileAlpineImpl AlpineDirectory rather than AlpineInterimDirectory