<> <> <> <> <> <> <> <> <> <> <> 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, Unknown], 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; <> AlpineOpenFileHandle: TYPE = REF ANY; <> CreateTransaction: PUBLIC PROC [server: ROPE] RETURNS [t: AlpineTrans] = { needRetry: BOOL _ FALSE; haveRetried: BOOL _ FALSE; 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} <> 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]} ]; DBStats.Stopping[AlpineFileFinishTransaction]; IF NOT abort AND outcome = abort THEN ERROR DB.Aborted; }; 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 ! AlpFile.Unknown => CONTINUE] }; 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 <> Changed by wert on August 9, 1984 2:16:26 pm PDT <> Changed by Willie-Sue on February 15, 1985 <> <<>> Changed by Willie-Sue on April 25, 1985 <> <> <>