CS333 Lab C-1:
Remote Procedure Call (RPC)

Goals of this lab:

Introduction:

Remote Procedure Calls (RPCs) are a common method of communication in distributed applications because of their familiar procedure-style semantics. RPC support can simplify and encapsulates interprocess interaction, especially for client-server applications. This is because, as far as the application programmer is concerned, invoking a remote procedure is not very different from invoking an ordinary local procedure call. The run-time system providing the RPC mechanism handles all the underlying communication to make things look simple to the application programmer.

Inside the run-time system, a typical RPC interaction involves three parties, the client making the remote procedure call, the server on which the remote procedure is to be run, and the location server responsible for assisting the client in making contact with the server.

The client preparing to invoke a remote procedure call must specify the name of the service to be invoked across the network, the order and types of the parameters to be sent in the procedure call, and the expected type of the return value.

Similarly, a server preparing to accept remote procedure calls from across the network must specify the name of the service it is providing, the order and types of parameters expected, and the type of the return value. In addition, it must register its available services with the location server so that clients may find out about the services. This is similar to putting your telephone number in the Yellow Pages so that customers can find you.

When the client actually makes an RPC, it provides the values of the parameters. The run-time system then contacts the location server to establish a binding between the client and the server. Depending upon the RPC implementation, the binding may be established directly by the location server requesting a connection to be made between the client and the server, or the location server may send enough information to the client so that the client can make the connection request itself. In either case, once the connection is made, the parameter values are marshalled (packed for transmission) and sent as a message to the server. Upon receipt of this message, the server demarshalls the parameters and calls the procedure using the parameter values that were sent by the client. Finally, the return value is marshalled and sent back to the client, where it is demarshalled and used as the return value from the procedure call. At this point, the connection may be terminated or left in place to expedite future RPCs from the client to the server.

As you might have guessed, this process takes time, so the client may or may not want to wait while the RPC is in progress. Therefore, there are two types of RPC, called blocking and non-blocking. A blocking RPC is most like an ordinary procedure call. When the client makes the call, the call does not return until the return value comes back from the server. In contrast, a non-blocking RPC returns immediately, returning the client program an object called a promise. The client program can then go on to do other useful work while the RPC is in progress. When the RPC completes and the return value arrives at the client, the value is placed into the promise object so the client program may claim it.

The client may periodically test a promise to see if it is ready to be claimed. If the client program claims the promise before it is ready, then the client will be blocked until the return value comes back from the RPC for delivery to the client. Thus, making a non-blocking RPC and then immediately claiming the promise is essentially the same as making a blocking RPC.

In this project you will design and implement a non-blocking RPC mechanism on top of the asynchronous data communication provided by Playground. You will implement classes that will support RPC synchronization of client and server modules, and you will build a location server module that will be used to assist clients in connecting to servers. You will test your RPC support using an example client/server application, an air pollution database server and a data browser client.

To simplify your job, you will use the Playground data types for communication of parameters and return values, so you don't have to marshal and demarshal the data yourself. Throughout the lab, we'll assume that all parameters and return values are Playground base types (integers, reals, booleans, and strings). Another simplification is that your location server module will request the creation of Playground connections to establish communication between the client and the server when an RPC is made, so you don't have to worry about low-level communication details.


Before Starting:

Read about element-to-aggregate connections (Section 4.5.2) and the connection API (Sections 5.1 and 5.2) in the Playground manual.


Part I. The RPC Mechanism

There are two aspects to an RPC mechanism, declaration and execution.

You will create RPCclient and RPCserver classes to provide the basic RPC functionality. When instances of these classes are created, the constructor will perform the "declaration" part of the RPC. Arguments to the constructor for both RPCserver and RPCclient will include the name of the service and a description of the parameter and return types. (The parameter and return types can be described as you see fit. For example, you might use an array of characters, where different letters represent different types.) The constructor will create a PGtuple containing fields to hold the parameters and return values for communication between the client and the server. The PGclient object will publish this tuple with a unique name. The PGserver object will publish an aggregate of these tuples (for use by multiple clients) with a unique name that it will also forward to the location server in order to register itself.

The execution of an RPC starts at the RPCclient object. Your RPCclient object should provide a call method that will take in (a variable number of) parameter values for the call. All parameters, which will be of type PGvariable pointer, are copied by the call method into the PGtuple you created for communication with the server. Then, the call method should send a request message to the location server. The request message (another PGtuple) should contain the public name of the PGtuple on the client side that is holding the parameter values, as well as the name of the service desired. Using this information, your location server should request a bidirectional element-to-aggregate connection from the client's PGtuple to the appropriate presentation entry on the server side. When this connection is established, the client's parameter values will be automatically sent to the server for execution of the remote procedure.

Execution continues on the server side as follows. A new PGtuple will be created in the aggregate when the element-to-aggregate connection is established from the client. Then, the client's parameter values will be assigned into the PGtuple for use by the RPCserver. The RPCserver should react to the incoming values by calling a virtual function handler. (The application programmer will have subclassed the RPCserver, providing an actual handler method that will accept the parameters, do the work of the server, and return a result. Some casting will need to be done here since the parameters types are just pointers to PGvariables.) After the handler method returns, the RPCserver should put the return value into the PGtuple for communication back to the client. The PGtuple may then be removed from the aggregate and deleted, or left in place to expedite future calls from the client. (If deleted, the destructor of the PGtuple will automatically request the termination of the connection to the client, so you don't have to worry about removing the connection.)

Back on the client side, a reactor should be present to handle the receipt of the return value from the server. This reactor should stuff the return value into the promise object that was returned by the call method. As part of this, the promise's internal status should be set to ready so that the client's program can claim the promise. The claim method on the promise object should return the value that was returned by the server to the client. As mentioned earlier, if the client tries to claim the promise before it is ready, then the claim method should busy-wait (sit in a loop calling PGsleep until the promise is ready).

The design of the location server is fairly open-ended. It needs to take registration information from servers and RPC connection requests from clients. It must keep track of server names and locations so it can send out connection requests on behalf of clients.


Part II. Creating an RPC an Application

You will use your RPC mechanism to implement an interactive multidimensional data browser for air pollution data. Data to be browsed has three dimensions: space, time, and the type of atmospheric species (hydrogen, sulfur, or NO2). Your browser application will consist of one or more data servers, a query generator, and a data viewer. You will create Playground modules for the data server and the query generator. EUPHORIA will be used as the data viewer. In the data viewer, the user will specify at which location and at which time they want to view amount of a particular atmospheric species. This information, collectively called the "cursor" in the rest of this assignment, will go to the query generator that will pose a corresponding data query to be sent to the data server using your RPC mechanism. That is, the RPC will ask data server to calculate/retrieve information from the database according to the current cursor. This return value from the RPC is then sent to viewer for display. Details follow.

The cursor contains following information that is used to form the query
  • x and y location in latitude, longitude
  • radius of interest (this is the area around the cursor in which you wish to search for the closest point)
  • time (1 to 12 representing months)
  • species type (hydrogen, sulfur, or NO2) --- if you are dealing with multiple species
  • Data file description: We have provided files containing air pollution data for three different atmospheric species. Each line of each file contains 16 fields (columns) in the following format.

    Field NumberValue
    Field 1Location Code - unique location identifier
    Field 2Location Name
    Field 3Location Longitude - radians, negative
    Field 4Location Latitude - radians, positive
    Fields 5-16data values for the months Jan. - Dec. 1991

    Modules:
    Data Server
    Functionality: Receives queries through RPC, finds the closest data point in the database for the given species, and returns the data value.
    Your database will access following files:
    1. hydrogen, space separated or comma separated
    2. sulfur, space separated or comma separated
    3. NO2, space separated or comma separated
    Design a database class for data retrieval. Make it flexible. Number of data files may change.
    Presentation:
    1. aggregate of PGtuples used for RPC queries from multiple simultaneous clients

    Query Generator
    Functionality: Receives cursor information from a single viewer, converts cursor into a query, and uses an RPC to retrieve the data from the data server. Data that comes back from the server is sent to the viewer for display.
    Presentation:
    1. RPC Client (query)
    2. X,Y (cursor location)
    3. radius of interest
    4. Species (if handling multiple pollutants)
    5. Time (cursor time)
    6. Data Value

    Data Viewer (in EUPHORIA)
    Functionality: You can use this map of the United States in EUPHORIA to create an interface with a cursor for identifying position and a slider for selecting the time (month) of observation. The cursor should have a circle attached whose size can vary according to the current data value (i.e., circle at current x,y with its radius proportional to the data value). Look at the layer file that describes the dimensions of the map of the US. It gives the latitude and longitude range of the map and the pixel dimensions of the map. Using this information with the origin controller or the calculator, you can get EUPHORIA to report points in the right latitude and longitude units.
    Presentation:
    1. X,Y (cursor location)
    2. radius of interest
    3. Species (if you are handling multiple pollutants)
    4. Time (cursor time)
    5. Data Value

    Extra Credit: Create one data server module for each atmospheric species. Based on location and time from EUPHORIA, your Query Generator will ask for the corresponding value from every data server using instances of PromiseClient class. Simultaneously display the data for all species in EUPHORIA. Use promises to make all the requests and then go back and claim the return values.


    To receive credit for this lab, you should:

    1. Clean up and print out your code. (Don't turn it in, but save it for your code/design review.)

    2. Turn in a Project Evaluation Form near the beginning of class on the day you want to do your demonstration and code/design review. You should be prepared to demonstrate your working application, explain your design and code, and answer questions.