-- AlpInstanceImpl.mesa
-- Last edited by
-- Kolling on August 2, 1983 5:24 pm
DIRECTORY
AlpineEnvironment
USING[Conversation, FileStore, LockFailure, NeededAccess, OperationFailure, Principal,
UnknownType],
AlpineFile
USING[AccessFailed, Close, Create, Delete, GetAccessRights, GetLockOption,
GetRecoveryOption, GetReferencePattern, GetSize, GetTransID, GetUniversalFile,
IncrementVersion, LockFailed, LockPages, Open, OperationFailed, PossiblyDamaged,
ReadPages, ReadProperties, SetLockOption, SetReferencePattern, SetSize,
StaticallyInvalid, UnlockPages, Unknown, UnlockVersion, WritePages, WriteProperties],
AlpineFileRpcControl
USING[ImportNewInterface, NewInterfaceRecord],
AlpineOwner
USING[AccessFailed, Create, Destroy, LockFailed, OperationFailed, ReadDBProperties,
ReadNext, ReadProperties, ReorganizeDB, StaticallyInvalid, Unknown,
WriteProperties],
AlpineOwnerRpcControl
USING[ImportNewInterface, NewInterfaceRecord],
AlpineTransaction
USING[AssertAlpineWheel, Create, CreateWorker, Finish, OperationFailed, Unknown],
AlpineTransactionRpcControl
USING[ImportNewInterface, NewInterfaceRecord],
AlpineVolume
USING[AccessFailed, GetEnclosingGroup, GetGroup, GetNextGroup, StaticallyInvalid,
Unknown],
AlpineVolumeRpcControl
USING[ImportNewInterface, NewInterfaceRecord],
AlpInstance
USING[Failure, Handle, Object],
AlpPrivate
USING[InterfaceCreatorProc],
CedarSnapshot
USING[After, Register],
ClientMap
USING[Register],
Rope
USING[Equal, ROPE],
RPC
USING[AuthenticateFailed, EncryptionKey, GenerateConversation,
GetCaller, ImportFailed, MakeKey, StartConversation, VersionRange],
UserCredentials
USING[GetUserCredentials];
AlpInstanceImpl: CEDAR MONITOR
IMPORTS AF: AlpineFile, AlpineFileRpcControl, AO: AlpineOwner,
AlpineOwnerRpcControl, AT: AlpineTransaction, AlpineTransactionRpcControl, AV:
AlpineVolume, AlpineVolumeRpcControl, CedarSnapshot, ClientMap, Rope,
RPC, UserCredentials
EXPORTS AlpInstance, AlpPrivate
SHARES AlpineFileRpcControl, AlpineOwnerRpcControl, AlpineTransactionRpcControl,
AlpineVolumeRpcControl =
BEGIN OPEN AE: AlpineEnvironment, AlpI: AlpInstance;
objectCache: LIST OF AlpI.Object ← NIL;
FindObjectInCache: INTERNAL PROCEDURE[fileStore: AE.FileStore, caller: AE.Principal, key:
RPC.EncryptionKey] RETURNS[handle: AlpI.Handle] =
BEGIN
conversation: AE.Conversation;
FOR list: LIST OF AlpI.Object ← objectCache, list.rest
UNTIL list = NIL
DO
IF Rope.Equal[list.first.fileStore, fileStore, FALSE]
THEN BEGIN
TRUSTED BEGIN conversation ← (IF
(Rope.Equal[RPC.GetCaller[list.first.conversation], caller, FALSE] AND
(key = list.first.key))
THEN list.first.conversation
ELSE RPC.StartConversation[caller, key, fileStore, authOnly]); END;
handle ← NEW[AlpI.Object ← [
trans: list.first.trans,
file: list.first.file,
owner: list.first.owner,
volume: list.first.volume,
otherInterfaces: list.first.otherInterfaces,
conversation: conversation,
key: key,
fileStore: fileStore]];
RETURN;
END;
ENDLOOP;
TRUSTED BEGIN conversation ← RPC.StartConversation[caller, key, fileStore, authOnly]; END;
handle ← NEW[AlpI.Object ← [
trans: AlpineTransactionRpcControl.ImportNewInterface[[type:
"AlpineTransaction.alpine", instance: fileStore, version: version], [NIL, NIL,
NIL]],
file: AlpineFileRpcControl.ImportNewInterface[[type: "AlpineFile.alpine", instance:
fileStore, version: version], [NIL, NIL, NIL]],
owner: AlpineOwnerRpcControl.ImportNewInterface[[type: "AlpineOwner.alpine",
instance: fileStore, version: version], [NIL, NIL, NIL]],
volume: AlpineVolumeRpcControl.ImportNewInterface[[type:
"AlpineVolume.alpine", instance: fileStore, version: version], [NIL, NIL, NIL]],
otherInterfaces: NIL,
conversation: conversation,
key: key,
fileStore: fileStore]];
FOR list: LIST OF AlpPrivate.InterfaceCreatorProc ← interfaceCreators, list.rest
UNTIL list = NIL
DO
handle.otherInterfaces ← CONS[list.first[fileStore, version], handle.otherInterfaces];
ENDLOOP;
objectCache ← CONS[handle^, objectCache];
END;
Create: PUBLIC ENTRY PROCEDURE[fileStore: AE.FileStore, caller: AE.Principal, key:
RPC.EncryptionKey] RETURNS [handle: AlpI.Handle] =
-- non system-fatal errors:
-- Failed[alpineDownOrCommunications, alpineDown, authenticateFailed, badCallee, grapevineDownOrCommunications, mismatch].
-- caller = NIL means the logged-in user.
BEGIN
ENABLE UNWIND => NULL;
BEGIN
ENABLE BEGIN
RPC.AuthenticateFailed => SELECT why FROM
badCaller, badKey => GOTO authenticateFailed;
badCallee => GOTO badCallee;
communications => GOTO grapevineDownOrCommunications;
ENDCASE => NULL;
RPC.ImportFailed => SELECT why FROM
communications => GOTO alpineDownOrCommunications; -- almost certainly alpine and not grapevine, since authenticate got through.
wrongVersion, stubProtocol => GOTO mismatch;
unbound => GOTO alpineDown;
ENDCASE => NULL;
END;
startedAlready ← TRUE;
IF caller = NIL
THEN BEGIN psw: Rope.ROPE;
[caller, psw] ← UserCredentials.GetUserCredentials[];
TRUSTED BEGIN key ← RPC.MakeKey[psw]; END;
END;
IF Rope.Equal[fileStore, "Local.alpine", FALSE]
THEN BEGIN
conversation: AE.Conversation;
TRUSTED BEGIN conversation ← RPC.GenerateConversation[];
ClientMap.Register[conversation, caller]; END;
handle ← NEW[AlpI.Object ← [
trans: AlpineTransactionRpcControl.NewInterfaceRecord[],
file: AlpineFileRpcControl.NewInterfaceRecord[],
owner: AlpineOwnerRpcControl.NewInterfaceRecord[],
volume: AlpineVolumeRpcControl.NewInterfaceRecord[],
otherInterfaces: NIL,
conversation: conversation,
key: key,
fileStore: fileStore]];
handle.trans^ ← [Create: AT.Create, CreateWorker: AT.CreateWorker,
AssertAlpineWheel: AT.AssertAlpineWheel, Finish: AT.Finish, Unknown:
AT.Unknown, OperationFailed: AT.OperationFailed, lupineDetails: ];
handle.file^ ← [Open: AF.Open, Create: AF.Create, Close: AF.Close, Delete:
AF.Delete, GetUniversalFile: AF.GetUniversalFile, GetTransID:
AF.GetTransID, GetAccessRights: AF.GetAccessRights, GetLockOption:
AF.GetLockOption, SetLockOption: AF.SetLockOption, GetRecoveryOption:
AF.GetRecoveryOption, GetReferencePattern: AF.GetReferencePattern,
SetReferencePattern: AF.SetReferencePattern, ReadPages: AF.ReadPages,
WritePages: AF.WritePages, LockPages: AF.LockPages, UnlockPages:
AF.UnlockPages, ReadProperties: AF.ReadProperties, WriteProperties:
AF.WriteProperties, UnlockVersion: AF.UnlockVersion, IncrementVersion:
AF.IncrementVersion, GetSize: AF.GetSize, SetSize: AF.SetSize, AccessFailed:
AF.AccessFailed, LockFailed: AF.LockFailed, OperationFailed:
AF.OperationFailed, StaticallyInvalid: AF.StaticallyInvalid, Unknown:
AF.Unknown, PossiblyDamaged: AF.PossiblyDamaged, lupineDetails: ];
handle.owner^ ← [ReadProperties: AO.ReadProperties, WriteProperties:
AO.WriteProperties, Create: AO.Create, Destroy: AO.Destroy, ReadNext:
AO.ReadNext, ReadDBProperties: AO.ReadDBProperties, ReorganizeDB:
AO.ReorganizeDB, AccessFailed: AO.AccessFailed, LockFailed: AO.LockFailed,
OperationFailed: AO.OperationFailed, StaticallyInvalid: AO.StaticallyInvalid,
Unknown: AO.Unknown, lupineDetails: ];
handle.volume^ ← [GetNextGroup: AV.GetNextGroup, GetGroup: AV.GetGroup,
GetEnclosingGroup: AV.GetEnclosingGroup, AccessFailed: AV.AccessFailed,
Unknown: AV.Unknown, StaticallyInvalid: AV.StaticallyInvalid, lupineDetails: ];
FOR list: LIST OF AlpPrivate.InterfaceCreatorProc ← interfaceCreators, list.rest
UNTIL list = NIL
DO
handle.otherInterfaces ← CONS[list.first[fileStore, version],
handle.otherInterfaces];
ENDLOOP;
END
ELSE handle ← FindObjectInCache[fileStore, caller, key];
EXITS
alpineDownOrCommunications => RETURN WITH ERROR Failed[alpineDownOrCommunications];
alpineDown => RETURN WITH ERROR Failed[alpineDown];
authenticateFailed => RETURN WITH ERROR Failed[authenticateFailed];
badCallee => RETURN WITH ERROR Failed[badCallee];
grapevineDownOrCommunications => RETURN WITH ERROR Failed[grapevineDownOrCommunications];
mismatch => RETURN WITH ERROR Failed[mismatch];
END;
END;
-- If a object in our cache has an InterfaceRecord matching an InterfaceRecord in this handle, throw out the object. I think one interface matching means all match.....
NoticeUnboundInstance: PUBLIC ENTRY PROCEDURE[handle: AlpI.Handle] =
-- non system-fatal errors:
-- none.
BEGIN
prevEntry: LIST OF AlpI.Object ← NIL;
list: LIST OF AlpI.Object ← objectCache;
DO
IF list = NIL THEN EXIT;
IF list.first.trans = handle.trans
THEN BEGIN
IF prevEntry = NIL
THEN objectCache ← list.rest
ELSE prevEntry.rest ← list.rest;
END
ELSE prevEntry ← list;
list ← list.rest;
ENDLOOP;
END;
RegisterInterfaceCreator: PUBLIC ENTRY PROCEDURE[proc: AlpPrivate.InterfaceCreatorProc] =
-- non system-fatal errors:
-- none.
BEGIN
IF startedAlready THEN ERROR;
interfaceCreators ← CONS[proc, interfaceCreators];
END;
interfaceCreators: LIST OF AlpPrivate.InterfaceCreatorProc ← NIL;
startedAlready: BOOLEAN ← FALSE;
AlpRollbackProcedure: ENTRY PROCEDURE[CedarSnapshot.After] =
-- non system-fatal errors:
-- none.
BEGIN
objectCache ← NIL;
END;
Failed: PUBLIC ERROR [why: AlpInstance.Failure] = CODE;
AccessFailed: PUBLIC ERROR [missingAccess: AE.NeededAccess] ← AF.AccessFailed;
LockFailed: PUBLIC ERROR [why: AE.LockFailure] ← AF.LockFailed;
OperationFailed: PUBLIC ERROR [why: AE.OperationFailure] ← AF.OperationFailed;
StaticallyInvalid: PUBLIC ERROR ← AF.StaticallyInvalid;
Unknown: PUBLIC ERROR [what: AE.UnknownType] ← AF.Unknown;
PossiblyDamaged: PUBLIC SIGNAL ← LOOPHOLE[AF.PossiblyDamaged];
version: RPC.VersionRange = [2, 2];
-- start up code.
TRUSTED BEGIN CedarSnapshot.Register[c: , r: AlpRollbackProcedure];
END;
END.
Edit Log
Initial: Kolling: February 15, 1983 2:58 pm.