FingerOps.mesa
Last Edited by: Khall, August 13, 1984 10:17:23 am PDT
Last edited by: Donahue, April 22, 1985 9:00:28 am PST
(Added notion of properties to Finger database; removed notion of "fingerable objects" and made clear separation between machines/users. Added procedures to dump and build maps of the available machines)
DIRECTORY
BasicTime USING [GMT],
IO USING[STREAM],
Rope USING [ROPE];
FingerOps: CEDAR DEFINITIONS =
BEGIN
FingerList: TYPE = LIST OF Rope.ROPE;
The name of all of the objects matching a finger pattern
Reason: TYPE = {Error, Aborted, Failure};
These are the possible reasons why a Get or Put may fail. We try hard to avoid aborts, but they may be caused by changes in the collection of properties in the database; errors are programming problems; failures are problems with the server used to store the database
FingerError: ERROR[reason: Reason];
The procedure below that records information about the state of the machine and user logs its input so that if the server is unavailable at the time of the change of state it will still subsequently be recorded in the database (other users may find the database inconsistent with reality for short intervals, but we'll try hard to keep things as accurate as possible).
PropPair: TYPE = REF PropPairObject;
PropPairObject: TYPE = RECORD[prop: ATOM, val: Rope.ROPE];
A property pair consists of an atom describing the property and value currently assigned to the property in the database (or the value to be assigned to it)
The basic procedure for updating the state of the database. PutStateChange is not intended to be used by users of Finger; it is called when going into/out of the Idle state.
StateChange: TYPE = {login, logout};
PutStateChange: PROC [change: StateChange, time: BasicTime.GMT];
Record the specified state change in the finger database
A Finger database can have an arbitrary collection of properties attached to either machines or users. The collection of procedures below allows extension of the properties in the database and provides the means of changing the value of the properties of database entities
ListUserProps: PROC[] RETURNS[propList: LIST OF ATOM];
Produce the list of properties for entities of the given type
ListMachineProps: PROC[] RETURNS[propList: LIST OF ATOM];
Produce the list of properties for entities of the given type
AddUserProp: PROC[name: Rope.ROPE];
Add a new property for entities of the given type (the value associated with all Finger properties are of type Rope.ROPE)
AddMachineProp: PROC[name: Rope.ROPE];
Add a new property for entities of the given type (the value associated with all Finger properties are of type Rope.ROPE)
DeleteUserProp: PROC[name: Rope.ROPE];
Remove this property from the database. If the property does not exist, then the operation has no effect
DeleteMachineProp: PROC[name: Rope.ROPE];
Remove this property from the database. If the property does not exist, then the operation has no effect
Changes made by the set properties operations are logged on the local machine (with the time at which the log entry is made). When recovering from a crash or a down server, the logged entries are replayed if they were made later than the last update made in the database (each update in the database also records the time it was made). It is possible that a log entry cannot be replayed because the associated property has been removed from the database in the interim.
SetUserProps: PROC[props: LIST OF PropPair];
Save all of the properties for the current user.
SetMachineProps: PROC[props: LIST OF PropPair];
Save all of the properties for the current machine.
GetUserProps: PROC[user: Rope.ROPE] RETURNS[props: LIST OF PropPair];
Get all of the stored information for this object.
GetMachineProps: PROC[machineName: Rope.ROPE] RETURNS[props: LIST OF PropPair];
Get all of the stored information for this object.
The basic query operations of Finger allow matching by name, by property value or listing all of the currently free machines or logged on users
GetMatchingPersons: PROC [pattern: Rope.ROPE] RETURNS [result: LIST OF Rope.ROPE];
Find all of the fingerable objects with names matching the given pattern
GetMatchingMachines: PROC [pattern: Rope.ROPE] RETURNS [result: LIST OF Rope.ROPE];
Find all of the fingerable objects with names matching the given pattern
MatchUserProperty: PROC[propVal: PropPair] RETURNS[result: LIST OF Rope.ROPE];
Return all of the users having the given value for the specified property
MatchMachineProperty: PROC[propVal: PropPair] RETURNS[result: LIST OF Rope.ROPE];
Return all of the machines having the given value for the specified property
CurrentUsers: PROC[] RETURNS[userList: LIST OF Rope.ROPE];
Return a list of all of the current users on the system
FreeMachines: PROC[] RETURNS[machineList: LIST OF Rope.ROPE];
Return the list of currently available machines
Finally, two procedures to get login/logout information for a user or a machine
GetMachineData: PROC [name: Rope.ROPE] RETURNS[actualName: Rope.ROPE, lastChange: StateChange, time: BasicTime.GMT, user: Rope.ROPE];
Get the information on the last recorded operation for this machine
GetUserData: PROC [name: Rope.ROPE] RETURNS[machineList: LIST OF Rope.ROPE];
Get the current information for the user, ie., the list of machines for which he was the last (perhaps the current user)
And, we add procedures to read and write a "machine map" (the contents of the map are dependent on the structure of the database when the map is written or read). The dump contains the name of each machine property and the value of each property for each machine.
ReadMachineMap: PROC [file: Rope.ROPE, startPos: INT ← 0, msgStream: IO.STREAMNIL];
Set the data for every machine from the data in the file beginning at the startPos (this allows restarting of a partially completed operation). The message stream is used to record the progress of the operation -- the position of the file of the last update is recorded each time the transaction is committed.
WriteMachineMap: PROC [file: Rope.ROPE];
Dump the information on each machine and store as the contents of the specified file.
END.