SummonerDoc.tioga
Bob Hagmann February 12, 1986 4:25:12 pm PST
How to Use the Compute Server
CEDAR 6.0 — FOR INTERNAL XEROX USE ONLY
How to Use the Compute Server
Robert Hagmann
Copyright © 1985 by Xerox Corporation. All rights reserved
Abstract: The Summoner, also called the Compute Server or the Process Server, is a framework for doing computation on multiple machines in Cedar. It provides the facilities for using the processing power a more powerful workstation from a lower powered workstation for doing computations like CommandTool Commands. It also has facilities for doing multi-machine computations.
The system is not complete, and suggestions are actively solicited.
Keywords: Compute Server, Summoner, Process Server, distributed computing
XEROX Xerox Corporation
Palo Alto Research Center
3333 Coyote Hill Road
Palo Alto, California 94304
For Internal Xerox Use Only
Introduction
The Compute Server, also called the Summoner and the Process Server, is a collection of code that allows for remote execution of Cedar-like commands.
There are three entities implemented in software in the Compute Server: the Client, Server and Controller. The overall idea is to have Clients issue requests for command execution, and for the request to be run on some Server. Servers are grouped together in a cluster and are administered by a Controller. Clients may reside on any Cedar workstation. They can perform the following functions: package submittal (add new software to be run under the Compute Server on all Servers in the cluster), package removal, status information, cluster information, and request/support for a command to be run. The Server is an entity that runs on any Cedar workstation that has excess computing capacity. The Server actually does the request execution. The Controller is a distinguished Server for each cluster, hopefully unique at any given time. Uniqueness is assured if Grapevine has timely execution.
The Client provides the workstation interface to the system. The Controller oversees the operation of all the Servers, parcels out work to Servers requested either by Clients or by Servers, and handles package submission and removal. The Servers actually execute the requests.
A body of software is called a package. It is composed of two parts: the frontend (user interface) and the body. The frontend could be a ``tool'' or a Commander Command, while the body of the package is the part that really does the computation. The Compute Server allows the body of a command to run remotely, while it requires the frontend to run locally. The body of a command may FORK (and then later JOIN), and it may issue requests itself, thereby acting as a frontend.
The interface between the frontend and body has a simple protocol. A request is issued to a named command, passing in a ROPE. Input and output streams are set up if requested. All FS, UserProfile and UserCredentials calls within the body at runtime are handled as if they occurred on the Client. When a request completes, it may return a ROPE.
How to use it - Executive Summary
As a Client (in CSL)
To be a
client, start up the client code on the local machine:
SummonerClientOn
To turn off the client
SummonerClientOff
To run a compile that
prefers to be remote (but will run locally if Grapevine, gateways or all the compute servers are down, or ...)
RCompile foo
To make the Compile command prefer remote compilation (you should have your
client on):
Alias Compile RCompile
To Run only the user interface of the compiler, not the body (faster to Run, fewer GFI's, and smaller checkpoints - use during checkpoint creation)
@RCompile.load
Given that the server is idle, remote compile will run about 8 times faster remotely than locally from a Dolphin and 4 times faster from a DLion. It is wise to make most files needed by the remote compiler global (store them on file servers, and have attachments in the local directory), but a few local files are fine (don't bother to smodel the source).
RTeX uses the Compute Server to remotely perform TeX runs. If the client is on, TSetter may choose to do the typeset remotely (for typesetting files).
As a Server (in CSL)
Dorado owners may elect to have their machines as
servers too. You also have to have Pseudo Server ``Summoner'' set to ``Indigo Indigo'' (
PSAdd Summoner Indigo Indigo). It is nice to have a Pseudo Server for DATools to (
PSAdd DATools
Cyan Cyan). To increase the availability of styles, bring over [Cedar]<CedarChest6.0>Top>Forms.df into root ("///"). It is better to have all of this in your checkpoint (?). An alternative way to do the two
PSAdd's and the bringover in CSL is to have your profile entry for CommandTool.NewUser include the line "///Commands/SummonerCSLNiceGuy". To start being a
server:
SummonerServerOn
To stop being a
server
SummonerServerOff
To enable the server when your machine is in idle
SummonerEnableAutoIdle
To disable this feature
SummonerDisableAutoIdle
See the profile options Summoner.OKToRunBCDs, Summoner.PackagesOKToRun, Summoner.PackagesNotOKToRun, Summoner.FreeGFIs and Summoner.OKToUseLocalDisk to further control operation of the server.
Use from a Client
Using an Existing Package
If the package you want is already in the system (e.g., Compiler, TSetter and TeX), then refer to the documentation on the package use. Most of this document is intended for use by command implementors. Normal users should only read to the ``Summary — How to Use the Compute Server (as a Client only)'' section.
Sometimes a package is flexible about whether local or remote execution is done. Without an enabled Client, the body of the command is done on the local machine. See ``SummonerClientOn'' and ``SummonerClientOff'' in "Enabling and Disabling the Summoner Client Package" below.
For the Compiler, after the Client has been enabled (see below), use the ``RCompile'' command to get the Compiler to prefer remote compilations.
Running the Summoner Client Package
To use the Client and hence any remote services provided through the Compute Server, you have to run the proper software on the workstation. Here's how to start up a Client:
Bringover -p /Cedar/CedarChest6.0/Top/Summoner.df
@SummonerClient.load
The ``Bringover'' may be omitted if you use Environment.df — Summoner.df should be included in Environment.df.
Enabling and Disabling the Summoner Client Package
Clients start ``enabled''. To enable the Client, you have to do the proper bringover (if you have not already done so). Here's how:
Bringover -p /Cedar/CedarChest6.0/Top/Summoner.df
Now, to enable (and possibly start up) and optionally set the cluster (see below), type to a CommandTool
SummonerClientOn {cluster}
To disable, type to a CommandTool
SummonerClientOff
To startup a Client on a machine without the software loaded, ``SummonerClient.load'' and ``SummonerClientOn'' do exactly the same thing. If the software is loaded, ``SummonerClient.load'' has no effect, but ``SummonerClientOn'' makes sure that the Client is enabled.
Setting the Cluster
The
cluster is the Grapevine name for the group of machines coordinating to be the Servers and Controller. After the Client is running and enabled, it is possible to change the cluster. This is done by the SummonerCluster command. The default for the
cluster is PaloAlto.summoner. This command only changes the
cluster for the Client. Normally, you should not need to do this (if you are in Palo Alto).
SummonerCluster PaloAlto.summoner
Getting Status
Use the SummonerInfo command to print whether the client is enabled, the cluster name, the list of active Servers (with the Controller marked specially), and the Best Figure of Merit. The range for Best Figure of Merit is 0.0 to 2.0, with 0.0 being an idle Dorado, and 1.0 is a fully thrashing or CPU bound Dorado. You need a running client for this to work.
Setting a Command Bad
Use the SummonerBadCommand command to set a command bad for a machine. This can be used to eliminate servers that have damaged themselves. The most common use of this is anticipated to be disabling some servers from doing compiles. The compiler breaks if it ever gets a fatal error - it no longer will properly compiler CONDITION statements. Whenever a remote compile completes with any error, the compiler interface prints the machine address of the machine that was used to do the compile. If you think that the copy of the compiler on that server is bad, or that a server is giving you trouble ("stuporous but arosable" servers), then use the SummonerBadCommand command.
The command takes two arguments. The first argument is the name of the server (e.g., "Hornet") or its Pup Address (e.g., "3#35#"). The second argument is the name of the remote command (e.g., "RemoteCompiler"). You can find all the remote commands for a package by looking in the ``Package.remoteCommands'' file.
This can be reversed by use of
SummonerGoodCommand with identical syntax.
SummonerBadCommand server commandname
Example: SummonerBadCommand Bataan RemoteCompiler
User Profile Entries (both for Clients and Servers)
Summoner.ControllerName — used by the Client, Controller and Server to specify the cluster name. Default is "PaloAlto.summoner". The cluster may be changed dynamically for Clients via the SummonerCluster command
Summoner.CachePrefixesOKToRead — used by the Client to allow Servers to load their caches from the Client. This avoids checking of the Server's rights to read files in this prefix. If there are any private files kept under this prefix, then this will allow protection violations if the files are cached on the Client's workstation. This is a list of tokens, where each token is the prefix of a full name. Prefixes must be in the "[]<>" form of name. The default is
NIL. Only when both the Server and Client are on the same physical net will the files be loaded from the Client to the Server — otherwise the file server is used. If you are in the DA group in CSL, a reasonable entry might be
Summoner.CachePrefixesOKToRead: "[Cedar]<Cedar6.0>" "[Cedar]<CedarChest6.0>" "[DATools]"
Summoner.PrimaryController — the net address expressed as a rope of the machine that is the primary Controller (e.g. "3#277#"). This machine when up will become the Controller. May be omitted. Used by the Controller and Server. Not needed by users.
Summoner.RemoteCommandDirectory — the directory on a file server where the packages reside. Used by the Controller and Server. Not needed by users. Default is "/Summoner/Summoner/Packages/" (Summoner is Pseudo Server you must set up using the PSAdd command (e.g., ``PSAdd Summoner Indigo Indigo'')).
Summoner.LocalCommandDirectory — the directory on the workstation dedicated to the Compute Server. Needed by the Server. Not needed by users. Default is "///Summoner/Packages/".
Summoner.OKToRunBCDs — Only for the Server, this is a Boolean that is defaulted to TRUE. If TRUE, the Compute Server may run BCD's on the Server to perform requests. If FALSE, any request requiring a Run will be refused.
Summoner.PackagesOKToRun — Only for the Server, this is a list of packages that are OK to run. No other packages will be run. If Summoner.OKToRunBCDs is FALSE, no packages will be run. Default is NIL, which means all packages can be run.
Summoner.PackagesNotOKToRun — Only for the Server, this is a list of packages that are not OK to run. Any package not on this list will not be run, but may be used if it is already running. Default is NIL, which means no packages are prevented from running.
Summoner.FreeGFIs — Only for the Server, try to keep this number of GFI's free. Default is 10.
Summoner.OKToUseLocalDisk — Only for the Server, allow use of local disk when using special server name "SummonerServer". Default to FALSE. If this is set to TRUE, a FS.Open, FS.Create, FS.CreateOrOpen, and FS.Delete using a file name with server "SummonerServer" (e.g., "/SummonerServer//users/hagmann.pa/Flames.tioga") will open the file on the server's machine. Note that other FS operations are not, at this time supported (e.g., the enumerations and Copy).
Summary — How to Use the Compute Server (as a Client only)
Set up your profile. If you will never login to a machine running as a Server, only the ControllerName entry is needed. "PaloAlto.summoner" is normal cluster for CSL. A normal user in CSL does not need any profile entries. Below are the (effective) defaults in CSL:
Summoner.ControllerName: "PaloAlto.summoner"
Summoner.RemoteCommandDirectory: "[Indigo]<Summoner>Packages>"
Summoner.LocalCommandDirectory: "[]<>Summoner>Packages>"
Do a Bringover. Since Summoner.df should be in Environment.df, you should not need to do anything.
Enable the Compute Server. Type ``SummonerClientOn'' to a CommandTool, or have it in the ``CommandTool.PerLogin'' entry of your profile. We suggest you not put the ``Summoner Client Package'' in your checkpoint (i.e., do not do the ``SummonerClientOn'' or ``@SummonerClient.load''). Although this should work, there could be a startup transient.
Partitioning Software Between the Frontend and Body for a Package
As stated in the Introduction, the interface between the frontend and body has a simple protocol. A request is issued to a named command, passing in a ROPE. Input and output streams are set up if requested. All FS, UserProfile and UserCredentials calls within the body at runtime are handled as if they occurred on the Client. When a request completes, it may return a ROPE.
Currently, this is the only interface provided between the frontend and body of a package. The Compute Server design includes support software to allow import and export of arbitrary RPC remote interfaces, but this has not been implemented. Thus, you have to use the facilities provided: ROPE parameter in and out, input and output streams, and remote access to three interfaces (FS, UserProfile and UserCredentials).
For now, the body should be simply controlled (e.g., by a ROPE parameter) and mostly use files for bulk input and output. Bulk results via files is best, and some status can be returned via a ROPE.
Setting up a Cluster
Establishing the Cluster Name in Grapevine
Replicate the Summoner.GV registry locally (if needed) to avoid long range Grapevine traffic. Add the new individual. Names have the cluster's short name (e.g., ``PaloAlto'') followed by ``.summoner'' (``PaloAlto.summoner'').
UserProfile entries
Add a Summoner.ControllerName UserProfile entry for everyone that will use the Compute Server as a Client.
For every machine that may be a server, make a YourMachineNameGoesHere.machineProfile with a Summoner.RemoteCommandDirectory entry (YourMachineNameGoesHere can be found by "← PupDefs.GetMyName[]"). Alternatively, make Summoner.RemoteCommandDirectory entries in everyone's profile that will ever be logged in at any Server. (The Summoner.RemoteCommandDirectory entry may be omitted from both profiles if a local copy of the StartSummoner.cm'' command file is made, and it specifies the remote command directory). You may default the remote directory if you set up Pseudo Server ``Summoner'' to point at the proper server, and have a Summoner directory on it.
Setting up a Server
On a machine that will be a Server, Bringover [Cedar]<CedarChest6.0>Top>Summoner.df. ///Summoner/ is a nice directory. You can do the Bringover with ``-p'' if you have recent version maps (needed for debugging). Bring up the server using the ``StartSummoner.cm'' command file. Summoner.df is also in Environment.df, so if you use Environment.df you can just use the software in deposited by a Bringover of Environment.df into ///Commands/.
You will now have server that does not know about any remote commands. Write a null file in the directory specified in profile entry Summoner.RemoteCommandDirectory and filename ``PackageList''. Use the ``SubmitSummonerPackage'' command to submit packages. To submit the Compiler, do the following. Bringover the Compiler df file into a subdirectory. Now type ``SubmitSummonerPackage Compiler''. You should get confirmation that the package was accepted. After a few seconds, the Compute Server will learn that the Compiler is out there.
Server and Controller Startup
It is fairly simple to make a machine into a server. One of the main troubles with being a server is that .bcd's can be run on the machine (profile entry Summoner.OKToRunBCDs can be used to prevent .bcd's from being run). This can use up GFI's. The system tries very hard to make sure that ten GFI's are left, and that no ``run'' of a .bcd exhausts all the GFI's.
To run a machine as a Server, do the following:
Bringover -p /Cedar/CedarChest6.0/Top/Summoner.df
@StartSummoner.cm
StartSummoner.cm runs some software, but the startup actually occurs when the following lines are interpreted:
← SummonerControllerControl.StartUpController[]
← ComputeServerControl.StartUpServer[]
SummonerControllerControl.StartUpController has one argument of interest here. It is controllerName which is a rope. Default is "PaloAlto.summoner". This is the cluster that the current Server will run in.
ComputeServerControl.StartUpServer also can specify the cluster via the controllerName argument. The ``remoteCommandDirectory'' argument for ComputeServerControl.StartUpServer is the directory on a file server where the packages reside. Default is "/Summoner/Summoner/Packages/" (Summoner is a Pseudo Server). The ``localCommandDirectory'' argument is a directory on the workstation dedicated to the Compute Server (default is "///Summoner/Packages/").
SummonerServerOn is an alternate method for starting up the Server and Controller.
Unless you always specify the "remoteCommandDirectory" argument to SummonerServerOn, you probably want to specify a Pseudo Server. In Palo Alto, you should have Pseudo Server ``Summoner'' set to ``Indigo Indigo'' (PSAdd Summoner Indigo Indigo). It is better to have this in your checkpoint.
The set of styles available via the TSetter is determined by the files that are in root ("///") with extension style on the Server. To increase the availability of styles, bring over [Cedar]<CedarChest6.0>Top>Forms.df into root ("///") on all machines that may be Servers. Only styles supported via remote TSetting are in EssentialStyles.df (brought over during full boot) and Forms.df.
Other Workstation Commands
RemoveSummonerPackage — the inverse of submit, except that the package name is the argument and it need not have an attached df file.
SummonerServerOn — enables use of the workstation as a Server and Controller. The command has the form "SummonerServerOn {controllerName {remoteCommandDirectory {localCommandDirectory}}}" — the arguments are the same as the ComputeServerControl.StartUpServer call above.
SummonerServerOff — disables use of the workstation for future requests and shuts down the Server and Controller. Current requests are permitted to finish.
SummonerEnableAutoIdle — enables a "SummonerServerOn" command to run, with default arguments, when the machine goes idle, and does a "SummonerServerOff" on return from idle.
SummonerDisableAutoIdle — disables auto idle.
SummonerServerTypescript — Startup a typescript showing start and finish events for services performed on the workstation. Destroy the typescript to make it go away.
SummonerServerStatistics — Print time up, number of requests, time busy, and percent busy.
SummonerBecomeController — Attempt to force the Controller onto this machine. You must have a server running.
SummonerClientRequests — For the local Client, print the remote command names and the servers they are running on. Only commands actually assigned to servers will be printed (There is an initial negotiation phase where the Controller is deciding where to put a request. These will not be listed.)
Errors
If a remote request raises an uncaught error or signal, then an Event window is opened on the Client's display. It is opened in the left column to distinguish it from local events and events from the DebugTool. The Viewer herald starts with "REMOTE [servername] Event:" The error cannot be proceeded, nor can breakpoints be set. The stack can be walked, variables displayed, expressions evaluated, and the stack displayed. By adjusting the debugger search rules if necessary (?), the source can be opened. To finish, use the "Abort" button.
Submitting a New Package
The rest of this document is for people who want to write software that runs under the Compute Server.
There is a certain degree of circularity in trying to understand how all this works. Hence, we will just go through a package submittal and work our way back to how to write a package. Much of this depends on Compute Server being able to parse various things; in particular, some file names should not have additional "."s in them apart from the normal extensions (e.g., "Foo.df" is fine, but not "Old.Foo.df").
The "SubmitSummonerPackage" Command
When a package is ready for the summoner, SModel its df file (!!!) and use the SubmitSummonerPackage command to tell the Compute Server about it. The argument to the command is a .df file, that must be an attachment to a global file (e.g., ``SubmitSummonerPackage MakeError'').
The Compute Server assumes that the df file date
uniquely determines what software is to be used. This is an important performance accelerator in that it is only necessary to look at the current df file dates for the known packages. Only when the df file date changes will a bringover be initiated on a server. Hence, changing a program needed by, but not Exported directly by (i.e., in an "Export" not "Exports Imports" clause), the package's df file will not cause a bringover on the server. The uniqueness assumption has been violated: the package has changed but the df file has not. For example, TSetter.df has an "Exports Imports" statement for InterpressPackage.bcd. Changing InterpressPackage.bcd will
not cause the servers to use the new software. To force the use of new software, dirty the package df file, smodel it, and use SubmitSummonerPackage.
If you do not understand any of this, do the following: always edit and store the package df file before smodelling and submitting it.
Inside the public section of the df file (the Exports section) are the public files needed for the package execution (e.g., the .df file self and the .bcd(s) necessary to implement the package) as well as two control files necessary for the Compute Server. The control files are called ``package.remoteCommands'' and ``package.summonerLoad'' files (package is replaced by the package name). For example, the following files together with their comments are for package
MakeError:
MakeError.remoteCommands: specifies version number, whether the package requires exclusive use of the Server, maximum active count, maintainer list, and command list.
Example:
MakeError.remoteCommands
version: 1
maintainer: Hagmann.pa
commands: MakeError, PrintMyName, Echo
MakeError.summonerLoad: like a .load file except that it is only the Server part of the package and is only a list of packages to run. The implementor agrees that running all the files in the list provided in this file will "Register" (see below) all the commands specified in the "commands" entry in the .remoteCommands file. The bcd's will be run in the order listed. If a .bcd uses an abnormal number of GFI's, then put an estimate of the number of GFI's in parenthesis after the .bcd name. (You can get the number of GFI's used by clicking "Sample" in the WatchTool, remembering the number of GFI's, "run -a" the .bcd, click "Sample" in the WatchTool, and subtract the new number of GFI's from the number you had before.) Any error except "Unbound imports" will terminate the load. "Unbound imports" will be reported to the caller, the bcd will be started, and the load and the command execution will continue.
Example:
MakeError.summonerLoad
MakeError (1)
SubmitSummonerPackage takes the .df file, and does some checks. The .remoteCommands, .summonerLoad, and all bcd's mentioned in .summonerLoad must be either exported by the .df file, or exported for other df files used in the df file.
Next the .remoteCommands file is checked. This file has format similar to a user profile: it has a keyword token, a ":", and a list of tokens. Acceptable keyword tokens are "version", "maintainer", "commands", "exclusive", and "countActive". All are optional except for "commands". The meaning of the fields are:
version: the system tries to use distributed software all running at the same version for a package. If omitted, any version is used. The version is just a character string. Best effort is made at running the most recent version submitted.
maintainer: a list of Grapevine RNames to send mail to about trouble with the package
commands: the implementor agrees that all the commands listed here will be registered with the Compute Server when the .bcd's in the .summonerLoad file have been run.
exclusive: BOOL - this command should have exclusive use of a Compute Server. No other commands may be running concurrently
countActive: this is a numeric value for the maximum number of these commands to run on a single Server (e.g., run only one compiler request on a Server at a time).
Next, the .summonerLoad file is checked to see if the packages listed are valid. The packages are either part of the package submitted, or are packages that reside on a file Server. SubmitSummonerPackage checks for the packages on the file server, and hopes that all the Compute Servers will have the same, or compatible, packages.
The design of SubmitSummonerPackage now specifies that the bcd's to be run are checked to see if they try to import any "unsafe" interfaces. This is not implemented, and is only a half hearted attempt at security anyway.
The SubmitSummonerPackage command now decides that the submitted package is fine, and tries to tell the Controller about it. The Controller may be down, or have crashed, or may detect some different error in package submittal.
It is unfortunate that performance is dependent on how big these .df files are. The public (Exports) region is the most critical. Hence, df files should be quite short (at least later when (if) the Server is heavily used). The .df file and all the other files can be located on any Server, but they must be publicly readable.
The Controller looks at the .df file, and basically believes that it is good (provided it can read it). It adds it to the "PackageList" of known packages. The new package list is written to a file server. The new package now is installed, and any new Compute Servers will see it. The SubmitSummonerPackage command now completes.
Periodically, the Compute Servers tell the Controller statistics of operation. At this time, the knowledge of the new package is sent to the Servers. All Servers should recognize the new package within 10 seconds or so.
Workstation Client Interface and the Body of the Program
The software must be designed or modified to separate the workstation interface from the body of the execution. The goal of the workstation interface code is to call the body of the program after the command has been fully specified. Examples of the workstation interface code is the viewer package management for some tool, or a simple Commander.CommandProc.
Once the split between the interface and the body has been determined, the interface can be written. Where the body would normally occur, a call to the Compute Server should be inserted. The user interface code can either be in its own configuration (and hence its own bcd), or the user interface can be inside the same configuration as the body of the package. The package can either assume that there is a Client running on the workstation (a ``SummonerClient.load'' should be in its load file), or the package be willing to use a Client if one exists, but not demand it.
``ComputeServerClient'' (exported by ComputeServerStubImpl) is the proper interface to use when you do not wish to demand that a Client has been fun on the workstation. ``ComputeClient'' (exported by components of SummonerClient.load) is to be used when you have arranged for a Client to be running. The calls through either interface are similar; we show ComputeServerClient below:
ComputeServerClient.mesa
The Compute Server Client interface. This interface is between the Client (the rest of the Cedar world) and the Client code for the Summoner on the workstation, and thus is not an RPC interface.
Last Edited by: Bob Hagmann, May 15, 1985 1:00:21 pm PDT
Copyright © 1985 by Xerox Corporation. All rights reserved.
ComputeServerClient:
CEDAR
DEFINITIONS =
BEGIN
ROPE: TYPE = Rope.ROPE;
RemoteSuccess:
TYPE = {true, false, timeOut, commandNotFound, aborted, communicationFailure, cantImportController, cantImportServer, serverTooBusy, clientNotRunning};
These values mean -
true: the command succeeded
false: various errors may have occurred:
protocol errors in session establishment between the client and the server (see "remoteMsg" if available from the call)
timeOut: a queued request timed out
aborted: the "aborted" signal has been raised remotely. One way to do this for typical commands is to click "STOP!" in the command tool running the client interface.
communicationFailure: this occurs when the pup byte stream fails, or the "callbacks" via RPC to the client workstation ceases to work,
cantImportController: the machine identified by grapevine as the controller would not establish the RPC calls.
cantImportServer: the server selected by the controller would not establish the RPC calls.
serverTooBusy: the server selected by the controller was too busy, running an exclusive command, or already running too many of the selected command to start a new command. The client might try again, give up, or wait and try again.
clientNotRunning: the client on the workstation has not been run.
StartServiceProc: TYPE = PROC [service: ROPE, version: ROPE ← NIL, cmdLine: ROPE, in, out: IO.STREAM, queueService: BOOL ← FALSE, timeToWait: INT ← 3600, retries: NAT ← 3] RETURNS [found: BOOL, success: RemoteSuccess, remoteMsg: ROPE, serverInstance: ROPE];
StartService: StartServiceProc ;
Attempt to start the command named "service". If "version" is specified, only this version of the software will be used. "cmdLine" is a ROPE that will be given to the command. If "in" and/or "out" are specified and non-NIL, a pup byte stream is created and given to the command on the server. This stream is buffered and bytes are delivered or accepted from "in" and/or "out" as appropriate. "queueService" requests the Controller to do queueing and find a server that will handle the request. The request will be queued by the Controller for "timeToWait" seconds or until it is accepted by a server. If FALSE, the Controller selects a server, but the Client's machine is responsible for contacting the server and asking for the request to be handled. Any server may refuse such a request. "retries" is the number of times to retry to overcome (apparently) transient errors. If successful, "serverInstance" is the Pup Address expressed as a ROPE of the server that performed the command.
BestServerStatsProc: TYPE = PROC RETURNS[success: RemoteSuccess, selfIsBest: BOOL, FOM: REAL];
BestServerStats: BestServerStatsProc ;
Ask the controller which machine has the best figure of merit (FOM). FOM is in the range 0.0 to 1.0 with 0.0 being idle. FOM is left otherwise undefined.
Registration - for internal Compute Server Use
RegisterProcs:
PRIVATE PROC [StartService: StartServiceProc, BestServerStats: BestServerStatsProc ] ;
Register internal procedures — not for general use by clients.
END.
There is also a ``ComputeClientExtras'' interface that has a slightly different ``StartService'' procedure. It allows the server to be explicitly stated instead of letting the Controller specify it. Below is the interface. Note that there is no equivalent ComputeServerClient extras.
ComputeClientExtras.mesa
The Compute Client interface. This interface is between the Client (the rest of the Cedar world) and the Client code for the Summoner on the workstation, and thus is not an RPC interface. It is a variant of the ComputeServerClient.mesa interface, but is faster since it avoids one level of procedure call.
Extras interface to add serverName to StartService
Last Edited by: Bob Hagmann, October 23, 1985 10:19:39 am PDT
Copyright © 1985 by Xerox Corporation. All rights reserved.
DIRECTORY
ComputeServerClient,
IO,
Rope;
ComputeClientExtras:
CEDAR
DEFINITIONS =
BEGIN
ROPE: TYPE = Rope.ROPE;
StartServiceExtra:
PROC [service:
ROPE, version:
ROPE ←
NIL, cmdLine:
ROPE, in, out:
IO.
STREAM, queueService:
BOOL ←
FALSE, timeToWait:
INT ← 3600, retries:
NAT ← 3, serverName:
ROPE ←
NIL]
RETURNS [found:
BOOL, success: ComputeServerClient.RemoteSuccess, remoteMsg:
ROPE, serverInstance:
ROPE];
Identical to ComputeServerClient.StartService, except that the serverName argument is added.
If "serverName" is non-NIL, then the server is contracted directly, bypassing the Controller. Servers may be specified by their name (e.g., "Bataan") or by their network address (e.g., "3#277#").
END.
So a typical command execution might look like:
[found: found, success: success, remoteMsg: msg] ← ComputeServerClient.StartService[service: "PrintServerName", cmdLine: "", in: NIL, out: NIL];
Look at the QueueingTest program for an example of use and strings corresponding to the results ( [Indigo]<Summoner>6.0>QueueingTest>QueueingTest.df ).
Alternatively, one can use the ComputeClient interface. It also has procedures "StartService" and "BestServerStats" like ComputeServerClient, but these are exported by the "Client" code on the workstation (i.e., you must ensure that a "SummonerClient.load" has been done). clientNotRunning is never returned by calls through ComputeClient.
Server Interface and the Body of the Program
The ComputeServerClient.StartService asks the Compute Server to start up a service. The service name must match some name in a "commands" list in some package's .remoteCommands file. The bcd's needed by the package will be started up on the Server selected by the Controller, if needed, by running all the .bcd's listed in the .summonerLoad file for the package. One of the .bcds must call ``Register'' for the service name. ``Register'' can be called through the ComputeServerServer interface (exported by ComputeServerStubImpl) , or if it is known that a Server is running on the machine, then the ComputeServerControl interface may be used instead. This should be done during the module start code. Here is a current copy of the ComputeServerServer interface:
ComputeServerServer.mesa
Compute Server interface for the stub of the Server. This is an interface from the rest of the Cedar world to the Server. This is not an RPC interface, and is used on the Server machine.
Last Edited by: Bob Hagmann, May 15, 1985 4:40:08 pm PDT
Copyright © 1984 by Xerox Corporation. All rights reserved.
DIRECTORY
Commander,
Rope,
SymTab;
ComputeServerServer:
CEDAR
DEFINITIONS =
BEGIN
RegisteredProcHandle: TYPE = REF RegisteredProcObject;
RegisteredProcObject:
TYPE =
RECORD [
version: Rope.ROPE,
service: Rope.ROPE,
commanderProcHandle: Commander.CommandProcHandle ← NIL
];
Register:
PROC
[key: Rope.
ROPE, version: Rope.
ROPE ←
NIL, proc: Commander.CommandProc, doc: Rope.
ROPE ←
NIL, clientData:
REF
ANY ←
NIL];
A bcd file when it is run must call Register to register the existence of a command. The commands registered must include all commands in the .remoteCommands file for the package.
EnumerateAction: TYPE = PROC [key: Rope.ROPE, procData: LIST OF RegisteredProcHandle] RETURNS [stop: BOOL ← FALSE];
Enumerate:
PROC [EnumerateAction]
RETURNS [key: Rope.
ROPE, procData:
LIST
OF RegisteredProcHandle];
... calls the EnumerateAction with the key and registered procedure data for all registered commands. It will stop early if the EnumerateAction returns TRUE. Commands are not enumerated in any particular order.
Lookup:
PROC [key: Rope.
ROPE, version: Rope
.ROPE]
RETURNS [procData: RegisteredProcHandle];
... will look up the command and return the associated CommandProcHandle (NIL if no such command is registered). Case of keys does not matter.
Registration - for internal Compute Server Use
RegisterRealRegistration:
PRIVATE PROC
[
Register:
PROC
[key: Rope.
ROPE, version: Rope.
ROPE ←
NIL, proc: Commander.CommandProc, doc: Rope.
ROPE ←
NIL, clientData:
REF
ANY ←
NIL]];
Registry: PRIVATE SymTab.Ref; -- registered commands, for software that has been run and did a ComputeServer.Register, are saved here
END.
The call to "Register" is very similar to a call to Commander.Register. It makes known the service to the system.
How Command Execution Works
ComputeServerClient.StartService calls to the Controller to find a Server to use for the given command. If everything works (e.g., Grapevine and the Controller is up, and the command is known), then a machine to use is returned. The Client code for the summoner (in ComputeServerClient.StartService) then contacts the Server and attempts to run the command.
A variant of this is when "queueService" is TRUE. Here the Controller not only finds the Server, but contacts the Server to ensure the command will be accepted with high probability. The Client then attempts to run the command.
If "in" and "out" streams are specified, the Compute Server code arranges for a pup byte stream to transport the data. All FS, UserProfile and UserCredential calls originating from the remote process (or its children) are treated special. The effect is the same as the FS, UserProfile or UserCredential operation was done on the Client's workstation. One example is a file opened for writing; it will be written on the Client's disk. A local file will be opened, read, and written (via a RPC interface invisible to everything except for the Compute Server code) on the Client's disk. Attached files opened for reading are handled in the following manner. The open call is sent to the Client's workstation, and the following question is asked to FS: "if I were to open this file in this subdirectory, what would happen?". If the answer is that a global file would be opened, then we look in the workstation's cache for the file. If found, we know we have a global file that the user can read (since he could simply read it off this disk anyway). In this case, we return to the Server the full path name of the file. If the Server can open the file, all is well. If for any reason any of this fails (protection may be violated, file may not be in the Client's cache), then we do a local open on the Client's workstation.
UserProfile.CallWhenProfileChanges and UserProfile.ProfileChanged should not be used.
Various failures can occur (RPC, missing commands, aborts, version mismatch on run, ...).
An Example
Suppose we have written a simple program to use the Server to simply print out the name of the machine that the command happens to run on. Our implementation is:
PrintServerName.mesa
Bob Hagmann May 21, 1985 9:47:33 am PDT
DIRECTORY
Commander,
ComputeServerServer,
PupDefs;
PrintServerName:
CEDAR
PROGRAM
IMPORTS ComputeServerServer, PupDefs
= BEGIN
Test
PrintServerNameProc: Commander.CommandProc = {
msg ← PupDefs.GetMyName[];
};
Init
ComputeServerServer.Register[
key: "PrintServerName",
proc: PrintServerNameProc
];
We make remoteCommands and summonerLoad files like so:
PrintServerName.remoteCommands
Bob Hagmann March 13, 1985 6:48:38 am PST
version: 1
maintainer: Hagmann.pa
commands: PrintServerName
PrintServerName.summonerLoad
PrintServerName (1)
We write a simple command interface through the CommandTool, and a load file like so:
PrintServerNameCmds.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bob Hagmann May 21, 1985 9:49:11 am PDT
DIRECTORY
Commander,
ComputeServerClient,
Rope;
PrintServerNameCmds:
CEDAR
PROGRAM
IMPORTS Commander, ComputeServerClient, Rope
= BEGIN
Body
convertSuccess:
PROC [found:
BOOL, success: ComputeServerClient.RemoteSuccess, msg: Rope.
ROPE]
RETURNS [newMsg: Rope.
ROPE] = {
updateMSG:
PROC [prefix, suffix: Rope
.ROPE ]
RETURNS [newMsg: Rope
.ROPE] = {
IF suffix.IsEmpty[] THEN RETURN [prefix];
newMsg ← Rope.Cat[prefix, " (because ", suffix, ")"];
};
SELECT success
FROM
false => {
IF ~found THEN msg ← updateMSG["compute server command not found", msg]
ELSE msg ← updateMSG["compute server success was false (Computer Server bug?)", msg];
};
aborted => {
msg ← updateMSG["compute server command aborted", msg];
};
communicationFailure => {
msg ← updateMSG["communicationFailure", msg];
};
cantImportController => {
msg ← updateMSG["cantImportController", msg];
};
cantImportServer => {
msg ← updateMSG["cantImportServer", msg];
};
serverTooBusy => {
msg ← updateMSG["serverTooBusy", msg];
};
ENDCASE => msg ← updateMSG["unknown error code", msg];
newMsg ← msg;
};
PrintServerNameProc: Commander.CommandProc = {
found: BOOL;
success: ComputeServerClient.RemoteSuccess;
[found: found, success: success, remoteMsg: msg] ← ComputeServerClient.StartService[service: "PrintServerName", cmdLine: "", in: NIL, out: NIL];
msg ← convertSuccess[found, success, msg];
};
Init
Commander.Register[
key: "PrintServerName",
proc: PrintServerNameProc
];
PrintServerName.load
Copyright © 1985 by Xerox Corporation. All rights reserved.
We compile it and wrap it in a df file. After SModeling the df file, we submit it and use it as follows:
% SubmitSummonerPackage PrintServerName
New package accepted; please wait about 20 seconds before trying to use it.
{3.36 seconds, 7798 words}
% PrintServerName
>
> Run PrintServerNameCmds
Ran: [Indigo]<Summoner>6.0>PrintServerName>PrintServerNameCmds.bcd!1
{0.29 seconds, 1355 words}
Hornet
{1.67 seconds, 11711 words}
% PrintServerName
Hornet
{0.23 seconds, 554 words}
Debugging new packages
All of the previous discussion was about universally available packages that are submitted to the Controller and can, in principle, be run on any server. There are also ``extra'' commands that are known only by some servers. These commands come into existence by the software being explicitly run on a Server (e.g., ``% run FooImpl'') and a ComputeServerServer.Register call performed to register the command.
The net result is that the Controller has a command entry for this command for this particular server. You can then issue requests for this command and it will be directed to this server.
Hence, you can debug the package on the server just like you debug normal programs. After the run, set up the breakpoints (or whatever) and start the command. The request will run on the Server, and breakpoints will be hit as usual. You should choose a sufficiently obscure command name to avoid inadvertent use of the command.
This feature can also be used to enable commands on Servers with special characteristics or hardware (e.g., the Dunn camera).