-- AlpInstanceImpl.mesa
-- Last edited by
-- Kolling on October 18, 1983 3:51 pm

-- MBrown on February 2, 1984 10:55:52 am PST

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],
Booting
USING[RegisterProcs, RollbackProc],
ClientMap
USING[Register],
PrincOpsUtils
USING[IsBound],
Rope
USING[Equal, ROPE],
RPC
USING[AuthenticateFailed, EncryptionKey, GenerateConversation,
GetCaller, ImportFailed, MakeKey, StartConversation, VersionRange],
UserCredentials
USING[Get];


AlpInstanceImpl: CEDAR MONITOR
IMPORTS AF: AlpineFile, AlpineFileRpcControl, AO: AlpineOwner,
AlpineOwnerRpcControl, AT: AlpineTransaction, AlpineTransactionRpcControl, AV:
AlpineVolume, AlpineVolumeRpcControl, Booting, ClientMap, PrincOpsUtils, Rope,
RPC, UserCredentials
EXPORTS AlpInstance, AlpPrivate
SHARES AlpineFileRpcControl, AlpineOwnerRpcControl, AlpineTransactionRpcControl,
AlpineVolumeRpcControl =

BEGIN OPEN AE: AlpineEnvironment, AlpI: AlpInstance;


objectCache: LIST OF AlpI.Object ← NIL;
localFileStore: AE.FileStore ← "Local.alpine";


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.Get[];
TRUSTED BEGIN key ← RPC.MakeKey[psw]; END;
END;
IF Rope.Equal[fileStore, localFileStore, FALSE]
THEN BEGIN
conversation: AE.Conversation;
IF NOT PrincOpsUtils.IsBound[AT.Create] THEN GOTO alpineDownOrCommunications;
TRUSTED BEGIN
conversationRPC.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
objectCachelist.rest
ELSE
prevEntry.restlist.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: BOOLEANFALSE;


AlpRollbackProcedure: ENTRY Booting.RollbackProc = -- TYPE = PROC[clientData: REF ANY];
-- 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 SIGNALLOOPHOLE[AF.PossiblyDamaged];



version
: RPC.VersionRange = [3, 3];


-- start up code.

TRUSTED BEGIN Booting.RegisterProcs[c: , r: AlpRollbackProcedure];
END;



END.


Edit Log

Initial: Kolling: February 15, 1983 2:58 pm.

Changed: MBrown: February 1, 1984 8:27:49 pm PST. Rolled version stamp.