Skip to content

Implementation of MultiRPC

Support for MultiRPC exists both at the language level and at the runtime level. The runtime level support includes the MultiRPC routines themselves along with the associated library routines which perform argument packing and unpacking. The language level support consists mainly of the argument descriptor information supplied by RP2Gen for each subsystem. The client may choose to interface directly with the runtime MultiRPC system without taking advantage of the RP2Gen simplifications, but the discussion in the following sections assumes the existence of the RP2Gen interface except where explicitly noted otherwise.

The procedure for making a MultiRPC call is very similar to that for making an RPC2 call. The subsystem is designed and the specification is written into a <subsys>.rpc2 file (the specification format is described in RP2Gen Stub Generator). RP2Gen is then invoked on the specification file, and it generates both the standard server and client side interfaces as well as the MultiRPC argument descriptor structures and definitions for each server operation. The relevant descriptor pointers are made available to the client through the associated <subsys>.h file.

Once the interface has been specified, the subsystem implementor is responsible for writing the server main loop and the procedures to perform the server operations. This implementation is completely independent of any considerations relating to MultiRPC; MultiRPC is completely transparent to the server side of a subsystem.

From the clients perspective, making a MultiRPC call is slightly different from the RPC2 case. Instead of the procedure-like client side interface supplied by the stub routines, the single library routine MRPC_MakeMulti is used to interface to RPC2_MultiRPC. The use of the library routine represents a large space savings in the executable files, but requires some additional information from the client making the call (see MRPC_MakeMulti and RPC2_MultiRPC). The client is also responsible for supplying a handler routine for any server operation which is used in a MultiRPC call. This handler routine is called by RPC2 as each individual server response arrives; it is used both for providing individual server return codes to the client and for giving the client control over the continuation or termination of the MultiRPC call. The handler routine is discussed in greater detail in the following section, and its interface is described in HandleResult.

The Client Handler

The client handler routine is intended to give the client control and flexibility in handling the incoming server responses from the MultiRPC call. For each connection specified in a RPC2_MultiRPC call, the client handler is called either when a connection error is detected or when the server response for that connection arrives. This allows the client to examine the replies as they arrive, and provides the opportunity to perform incremental bookeeping and analysis of the responses. The handler also has the ability to abort the MultiRPC call at any time. A more detailed discussion of the handler specifications can be found in HandleResult.

Since a MultiRPC call could potentially last a long time, it is crucial to provide the client with some measure of control over the progress and termination of the call. With many server responses, there are many variables that the client might wish to monitor in order to evaluate the progress of the call. In particular, the server responses and return codes themselves have a significant effect on the clients perception of the progress of the call. To address these requirements, RPC2 periodically passes control to the client during execution of the MultiRPC call. A client supplied routine designed to be called as each server response arrives provides access to complete current information about the status of the call; it also gives the client the ability to perform any incremental processing he considers necessary or useful. The client then indicates his decision to either continue accepting server responses or to terminate the MultiRPC call via the handler return code.

The value of client control over the progress of the MultiRPC call can best be illustrated with some specific examples. One example is in the case of connection errors. If the client requires responses on all of the designated connections and one of them returns an error, then the final result of the MultiRPC call will be useless and the remainder of the processing time will have been wasted. With the client handler routine the client has the ability to notice the connection error. He then has the ability to abort the call, or even to use the handler routine as an opportunity to rebind to the failed site and make an RPC2 call on that connection.

Another example is in the implementation of a replicated server. A useful way to deal with operation quorums (specified as some subset \(N\) of the total number of replicated servers) is to send messages out to all or many of the available servers and abort the call as soon as the first \(N\) responses arrive. This has the advantage of supplying the fastest possible execution for the replicated call; furthermore, since the \(N\) members of the quorum need not be chosen explicitly, the call will rarely have to be repeated if one of the servers is busy or inoperational.

The handler receives full sets of arguments each time it is called, along with an index identifying the current connection. The types of the server arguments to the client handler are identical to the types in the original MakeMulti call: the argument list is in fact passed through RPC2 and returned to the handler. Any processing is permissible in the handler routine, although it should be noted that since RPC2_MultiRPC does not support enqueueing of server requests any call made on a connection already active in a MultiRPC call will generate a return code of RPC2_BUSY. Also, for lengthy blocking computations the same cautions with respect to lightweight processes apply as for RPC2.

It should also be noted that the use of the abort facility of the client handler carries with it some risks. These are discussed in more detail in Error Cases and Abnormal Behavior.

Flow of Control in MultiRPC

The flow of control in MultiRPC is much the same as for RPC2 except for the iterative calling of the client handler. The client initiates the MultiRPC call by calling the library routine MRPC_MakeMulti. MakeMulti packs the client arguments into a request buffer, and calls RPC2_MultiRPC with the request buffer, some argument packing information, and a pointer to MRPC_UnpackMulti, the library unpacking routine.

RPC2_MultiRPC sets up the processing environment, initializes the request packet headers for all the designated servers, and performs any necessary side effect initialization. It then calls an internal routine to perform the transmission of the request packets. This transmission routine does not return until either the client supplied timeout expires or until it has received responses from all of the designated servers. Once the request packets have been transmitted, the routine settles into a loop waiting for server responses to arrive. As each response arrives, some preliminary processing is performed, and any remaining side effect processing is completed.

Then RPC2 calls MRPC_UnpackMulti to unpack the response buffer into the clients original arguments. MRPC_UnpackMulti unpacks the buffer and calls the client handler routine with the current serverss information. The client then performs whatever processing he wishes, and returns with his instructions to continue or terminate the call. If he wishes to continue, the internal loop continues until all the server responses have been received. Otherwise, the loop terminates and the transmission routine cleans up any loose ends caused by the termination.

Control then returns to RPC2_MultiRPC, which checks the return code and returns to MRPC_MakeMulti. MakeMulti simply passes the supplied return code back to the client as it returns.

Since side effects are completely determined by the SE_Descriptor and the connection, extending the side effect mechanism to MultiRPC requires nothing more than supplying a unique SE_Descriptor for each connection.

RPC2_MultiRPC

RPC2_MultiRPC is the RPC2 runtime routine responsible for setting up the internal state properly for sending the request packets to the specified servers. It is called via the RPC2 library routine MRPC_MakeMulti. One of the arguments to MultiRPC is the ArgInfo structure. This structure is never examined by RPC2, but is simply passed through UnpackMulti. If the RP2Gen interface is used, this argument is supplied by MRPC_MakeMulti and need not concern the client. If the RP2Gen interface is not used, this can point to any structure needed by the clients unpacking routine.

The UnpackMulti argument is also related to the RP2Gen interface. If the RP2Gen interface is used, this argument is automatically supplied by MRPC_MakeMulti and will point to the RPC2 library unpacking routine. If the RP2Gen interface is not used, the client is responsible for supplying a pointer to a routine matching the UnpackMulti specification (see MRPC_UnpackMulti).

MRPC_MakeMulti

MRPC_MakeMulti is the library routine which provides the parameter packing interface to RPC2_MultiRPC. It takes the place of the individual client side stub routines generated by RP2Gen.

In additon to the usual information supplied in an RPC2 call, it takes as arguments RP2Gen generated argument and operation descriptors, the number of servers to be called, and a pointer to a client supplied handler routine (see MRPC_MakeMulti for more detailed information). Using the argument descriptors, MRPC_MakeMulti packs the supplied server arguments into an RPC2 request buffer and creates a data structure containing call specific information and a pointer to the client handler routine. It then makes the MultiRPC call, and passes the final return code back to the client when the call terminates.

OUT and INOUT parameters must be supplied in the form of arrays of pointers to the appropriate argument types. The parameter interface specifications are discussed in MultiRPC - C Interface Specification. The size of the array is dependent on the number of servers designated by the client. For INOUT parameters it is only necessary to actually fill in a value for the first element of the array, although storage must be properly allocated for all of the elements.

MRPC_UnpackMulti

MRPC_UnpackMulti is a RPC2 library routine which functions as the other half of MRPC_MakeMulti. It unpacks the contents of the response buffer into their appropriate places in the clients arguments, and calls the client handler routine. It returns with the return code supplied by the client handler routine. If the RP2Gen interface is not used, the client must supply a pointer to a routine with the specified interface (see MRPC_UnpackMulti).

HandleResult

HandleResult is a place holder used to refer to the client-supplied handler routine. It is called once for each connection by MRPC_UnpackMulti with the newly arrived server reply. It can perform as much or as little processing as the client deems necessary, and controls the continuation or termination of the MultiRPC call with its return code. The argument specifications of this routine are explained in detail in HandleResult.

Error Cases and Abnormal Behavior

The semantics for errors in the MultiRPC case are somewhat different from those in the RPC2 case. Since several messages are being transmitted in the same call, an error on one connection should not necessarily cause the call to terminate. The client does, however, need to be informed of error states on any of his connections. The handler routine will be called at most once for each connection submitted to the MultiRPC call, either with an error condition or with the server response. No packet will actually be sent on any connection for which an error was detected in the course of processing.

As mentioned earlier, the additional flexibility provided by the client handler routine incurs some risks. RPC2 makes no guarantees as to the state of the connections which are not examined because of an abort by the client. When the client returns an abort code, there may still be some outstanding server replies. RPC2_MultiRPC increments the connection sequence number and resets the connection state, thus pretending that the response in question was actually received. This allows the system to continue with normal operation.

The risks of this approach can be illustrated with some examples. A client makes a MultiRPC request R1 to 3 servers, and terminates the call after two of the server responses have been received. At server S3, the request has been queued because the server was busy with a previous request. The client then decides to make another MultiRPC request R2 on a set of servers that includes server S3 from the first call. S3 then receives R2, tagged with the next logical sequence number, on the same connection as R1. If S3 has not yet begun processing R1, then it will throw R2 away because it recognizes that its sequence number is too high. S3 will then proceed to process R1 and send the response back to the client; the client, however, will promptly throw the response away as a retry because the semantics of his abort command was to pretend that the response to R1 from S3 had already arrived.

Now, assuming that the client chooses to terminate his second call before S3 returns, the client and S3 are completely out of synch. S3, having thrown away R2, will always be expecting a packet with R2s sequence number; the client, however, has already incremented the connection at the termination of R2. In order to keep the connection from hanging around uselessly, S3 will send a RPC2_NAK return code if it ever receives a request R3 on the same connection with a sequence number greater than R2. This will kill the connection, forcing the client to rebind if he wants to continue communicating with S3.

Another risk associated with the use of abort is the risk of not identifying dead connections. If a server S2 is dead but the client always chooses to abort his MultiRPC call before a response from S2 arrives, RPC2 may not have time to notice that the connection is dead.

These problems are a result of the clients ability to ignore the responses on some connections in a MultiRPC call, and will generally only manifest themselves in a case where a server is forced to queue a request because it is busy processing an earlier request. This means that the MultiRPC call should be used with caution in cases where simultaneous binding to a single site might result, although the severity of the problem can be lessened by providing a greater number of LWPs at the single site. It is important to note that these problems arise only in the case where the client chooses to abort the call before all replies have been received. However, the explicit NAK by the server at least gives the client the opportunity to learn that something has gone wrong with the connection and act accordingly.