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.
STREAM ←
NIL];
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.