MultiRPC
Design Issues
The MultiRPC facility 1 is an extension to RPC2 that provides a parallel RPC capability for sending a single request to multiple servers and awaiting their individual responses. Although the actual transmission is done sequentially, the resultant concurrent processing by the servers results in a significant increase in time and efficiency over a sequence of standard RPC calls. The RPC2 runtime overhead is also reduced as the number of servers increases. For the purposes of this discussion, the base RPC2 facility will be referred to simply as RPC2.
A noteworthy feature of the MultiRPC design is the fact that the entire implementation is contained on the client side of the RPC2 code. The packet which is finally transmitted to the server is identical to a packet generated by an RPC2 call, and the MultiRPC protocol requires only a normal response from a server.
A major design goal was the desire to automatically provide MultiRPC capability
for any subsystem without requiring any additional support from the subsytem
designer or implementor. This has been achieved through modifications to
RP2Gen, the RPC2 stub generation package (see RP2Gen). RP2Gen
generates an array of argument descriptor structures for each server operation
in the specification file, and these arrays are inserted in the beginning of
the client side stub file. These structures are made available to the client
through definitions in the associated .h
file, and allow the use of
MultiRPC with any routine in any subsystem with RP2Gen generated interfaces.
The orthogonality of the MultiRPC modifications also extends to the side effect
mechanism. Side effects for MultiRPC work exactly as in the RPC2 case except
that the client must supply a separate SE_Descriptor
for each connection.
Side effects can be omitted on a subset of the connections by specifying a the
Tag field value of OMITSE
for those SE_Descriptor
's. This used, for example,
in the Coda file system where a MultiRPC call is made to obtain file version
information from a set of servers, but data from only one of those servers.
Parameter packing and unpacking for MultiRPC is provided in the RPC2 runtime library by a pair of routines. These library routines provide the functionality of the client side interface generated by RP2Gen as well as some additional modifications to support MultiRPC. It was decided to perform the packing and unpacking in RPC2 library routines rather than in individual client side stub routines as in the RPC2 case; this requires some extra processing time, but saves a significant amount of space in the client executable file. This approach has the added advantage of modularity; execution of RPC2 calls will not be affected at all, and even for MultiRPC calls the additional processing time is negligable in comparison to the message transmission overheads imposed by the UNIX kernel.
Another feature of MultiRPC is the client supplied handler routine. Through the handler routine the client is allowed to process each server response as it arrives rather than waiting for the entire MultiRPC call to complete. After processing each response, the client can decide whether to continue accepting server responses or whether to abort the remainder of the call. This facility can be useful if only a subset of responses are required, or if one failed message renders the entire call useless to the client. This capability is discussed further in handler.
MultiRPC also provides the same correctness guarantees as RPC2 except in the
case where the client exercises his right to terminate the call. RPC2
guarantees that a request (or response) will be processed exactly once in the
absence of network and machine crashes; otherwise, it guarantees that it will
be processed at most once. If the call completes normally, a return code of
RPC2_Success
guarantees that all messages have been received by the
appropriate servers.
C Interface Specification
The following table shows the C type interface between the client routine and
MRPC_MakeMulti
for all the possible combinations of legal parameter
declarations and types. In all cases it is the clients responsibility to
allocate storage for all parameters, just as in the RPC2 case. For all types
except RPC2_EncryptionKey, IN parameters are handled the same as in the single
MakeRPC case; RPC2_EncryptionKeys must be passed as pointers in the MultiRPC
case. For OUT and INOUT parameters, arrays of pointers to parameters must be
supplied in order to hold the multiple server responses. The array for each
parameter must contain the same number of items as the number of servers
contacted, and they must be filled sequentially starting from element zero. For
all INOUT parameters except for SE_Descriptors
, only the first element of the
array need be filled in. For SE_Descriptors
, all elements must be filled in.
The following table should be consulted for specific formats.
RPC2 Type | in | out | in out |
---|---|---|---|
RPC2_Integer | long | long *[] | long *[] |
RPC2_Unsigned | unsigned long | unsigned long *[] | unsigned long *[] |
RPC2_Byte | unsigned char | unsigned char *[] | unsigned char *[] |
RPC2_String | unsigned char * | unsigned char **[] | unsigned char **[] |
RPC2_CountedBS | RPC2_CountedBS * | RPC2_CountedBS *[] | RPC2_CountedBS *[] |
RPC2_BoundedBS | RPC2_BoundedBS * | RPC2_BoundedBS *[] | RPC2_BoundedBS *[] |
RPC2_EncryptionKey | RPC2_EncryptionKey * | RPC2_EncryptionKey *[] | RPC2_EncryptionKey *[] |
SE_Descriptor | illegal | illegal | SE_Descriptor *[] |
RPC2_Enum name | name | name *[] | name *[] |
RPC2_Struct name | name * | name *[] | name *[] |
RPC2_Byte name[...] | name | name *[] | name *[] |
Table 1. RP2Gen representation of MultiRPC parameters
The client is only responsible for understanding the parameter type interface
to the MakeMulti
and HandleResult
routines, and for allocating all
necessary storage. MRPC_MakeMulti
and MRPC_UnpackMulti
are included in the
RPC2 libraries.
Runtime Calls
MRPC_MakeMulti
int MRPC_MakeMulti(
in long ServerOpcode,
in ARG ArgTypes[],
in long HowMany,
in RPC2_Handle CIDList[],
out RPC2_Integer RCList[],
in out RPC2_Multicast *MCast,
in long (*HandleResult)(),
in struct timeval *Timeout,
...
);
Pack arguments and initialize state for RPC2_MultiRPC
. Individual server
responses are processed by calling HandleResult
. For all in or out
parameters an array of HowMany
of the appropriate type should be allocated
and supplied by the client. For example, if one argument is an out integer, an
array of HowMany integers (i.e. int foo[HowMany];
) should be used. For
structures an array of structures and NOT an array of pointers to structures
should be used. in arguments are treated as in the RPC2_MakeRPC
case.
- Parameters
-
ServerOpcode
-
For server routine foo,
foo_OP
. RP2Gen generated opcode, defined in include file. Note that subsystems with overlapping routine names may cause problems in aRPC2_MakeMulti
call.
-
ArgTypes
-
For server routine foo,
foo_PTR
. RP2Gen generated array of argument type specifiers. A pointer to this array is located in the generated include filefoo.h
.
-
HowMany
-
How many servers are being called.
-
CIDList
-
Array of HowMany connection handles, one for each of the servers.
-
RCList
-
Array of length HowMany, into which RPC2 will place return codes for each of the connections specified in ConnHandleList. May be specified as NULL if return codes will not be examined.
-
MCast
-
Pointer to multicast structure. Set to NULL for now.
-
HandleResult
-
User procedure to be called after each server response. Responses are processed as they come in. Client can indicate when he has received sufficient responses (see RPC2_UnpackMulti).
MRPC_MakeMulti
will return when all responses have been processed.
-
Timeout
-
Timeout for the entire MultiRPC call. If NULL, use default timeout.
-
...
-
Variable length argument list. This is the list of the server arguments as they are declared in the
.rpc2
file. The types of these arguments are determined by the RP2Gen generated include file.
- Completion Codes
-
RPC2_SUCCESS
-
Success.
-
RPC2_TIMEOUT
-
The user specified timeout expired before all server responses were received.
-
RPC2_FAIL
-
Something other than RPC2_SUCCESS or RPC2_TIMEOUT occured.
RPC2_MultiRPC
int RPC2_MultiRPC(
in long HowMany,
in RPC2_Handle ConnHandleList[],
in RPC2_PacketBuffer *Request,
in SE_Descriptor SDescList[],
in long (*UnpackMulti) (),
in out ARG(INFO) *ArgInfo,
in struct timeval *Patience
);
Make a collection of remote procedure calls. Logically identical to iterating
through ConnHandleList and making RPC2_MakeRPC
calls to each specified
connection using Request as the request block, but this call will be
considerably faster than explicit iteration. The calling lightweight process
blocks until either the client requests that the call abort or one of the
following is true about each of the connections specified in ConnHandleList:
a reply has been received, a hard error has been detected for that connection,
or the specified timeout has elapsed.
The ArgInfo structure exists to supply argument packing and unpacking information in the case where RP2Gen is used. Since its value is not examined by RPC2, it can contain any pointer that a non-RP2Gen generated client wishes to supply.
Similarly, UnpackMulti will point to a specific unpacking routine in the RP2Gen case. If the RP2Gen interface is not used, you should assume that the return codes of the supplied routine must conform to the MRPC_UnpackMulti specifications.
Side effects are supported as in the RPC2 case except that the client must
supply a separate SE_Descriptor
for each connection. The format for the
SE_Descriptor
argument is described in Adding New Kinds of Side
Effects. It will often be useful to supply connection
specific information such as unique file names in the SE_Descriptor
.
- Parameters
-
HowMany
-
How many servers are being called.
-
ConnHandleList
-
Array of HowMany connection handles, one for each of the servers.
-
Request
-
A properly formatted request buffer.
-
SDescList
-
List of HowMany side effect descriptors.
-
UnpackMulti
-
Pointer to unpacking routine called by RPC2 when each server response as received. If RP2Gen is used, this will be supplied by
MRPC_MakeMulti
. Otherwise, it must be supplied by the client.
-
ArgInfo
-
A pointer to a structure containing argument information. This structure is not examined by RPC2; it is passed untouched to UnpackMulti. If RP2Gen is used, this structure will be supplied by
MRPC_MakeMulti
. Otherwise, it can be used to pass any structure desired by the client or supplied as NULL.
-
Patience
-
Maximum time to wait for remote sites to respond. A NULL pointer indicates infinite patience as long as RPC2 is running.
- Completion Codes
-
RPC2_SUCCESS
-
Success.
-
RPC2_TIMEOUT
-
The user specified timeout expired before all server responses were received.
-
RPC2_FAIL
-
Something other than RPC2_SUCCESS or RPC2_TIMEOUT occured. More detailed information is supplied via UnpackMulti to the user handler routine supplied in the ArgInfo structure.
MRPC_UnpackMulti
int MRPC_UnpackMulti(
in long HowMany,
in RPC2_Handle ConnHandleList[],
in out ARG(INFO) *ArgInfo,
in RPC2_PacketBuffer *Response,
in long rpcval,
in long thishost,
);
Unpack server arguments and call client handler routine. This routine is fixed
in the RP2Gen case, and can be ignored by the client. For the non-RP2Gen case,
a pointer to a routine with the argument structure described must be supplied
as an argument to RPC2_MultiRPC
. The functionality of such a client-supplied
routine is unconstrained, but note that the return codes have an important
effect on the process of the MultiRPC call.
- Parameters
-
HowMany
-
How many servers were included in the MultiRPC call.
-
ConnHandleList
-
Array of HowMany connection ids.
-
ArgInfo
-
Pointer to argument information structure. This pointer is the same one passed in to
RPC2_MultiRPC
, so for the non-RP2Gen case its type is determined by the client.
-
Response
-
RPC2 response buffer.
-
rpcval
-
Individual connection error code or server response code.
-
thishost
-
Index into ConnHandleList to identify the returning connection.
- Completion Codes
-
0
-
Continue accepting and processing server responses.
-
-1
-
Abort MultiRPC call and return.
HandleResult
int HandleResult(
in long HowMany,
in RPC2_Handle ConnArray[],
in long WhichHost,
in long rpcval,
...
);
Process incoming server replies as they arrive.
This routine must return either 0 or -1. A return value of zero indicates that the client wants to continue receiving server responses as they come in (normal case). A return value of -1 indicates that the client has received enough responses and wants to terminate the MakeMulti call (in which the client is still blocked). This allows the client to call a large number or servers and terminate after the first n responses are received.
Note that the name of this routine is arbitrary and may be determined by the
client. RPC2_MultiRPC
sees it only as a pointer supplied as an argument to
MRPC_MakeMulti
. The parameter list is predefined, however, and the client
must follow the structure specified here in writing the routine.
- Parameters
-
HowMany
-
The number of servers contacted in the MultiRPC call.
-
ConnArray
-
Array of HowMany connection ids.
-
WhichHost
-
This is an offset into ConnArray and into any OUT or IN OUT parameters. Using this to index the arrays will yield the responding server and its corresponding argument values.
-
rpcval
-
This is the RPC2 return code from the specified server.
-
...
-
Variable length argument list. This is the list of the server arguments as they are declared in the
.rpc2
file. The types of these arguments are determined by the RP2Gen generated include file.
- Completion Codes
-
0
-
Continue accepting and processing server responses.
-
-1
-
Abort MultiRPC call and return.
-
M. Satyanarayanan and E. H. Siegel, "Parallel communication in a large distributed environment," IEEE Transactions on Computers, vol. 39, no. 3, pp. 328--348, 1990, doi: 10.1109/12.48864 ↩