ccs: Server IP = 192.168.3.23, Server port = 15763
|
void CcsRegisterHandler(const char *handlerName, const CkCallback &cb);
|
We can see in the example code, in main.C line 85 and 86, how this is performed by registering a callback to the entire jacobi array when there is an incoming request named "changeValue", and a callback to the mainchare when there is an incoming request named "exit".
// Register the callbacks for CCS
|
struct CkCcsRequestMsg {
|
The method to respond to the callback is registered as a normal entry method for the corresponding object. This method receives as input a CkCcsRequestMsg which contains the information received from the client, as well as the information to reply to such client. The structure of CkCcsRequestMsg is shown on the right.
Being "changeValue" triggered on the entire chare array, every element will execute the code. Each element will therefore pull the information out of the request, and update the values that belong to it. The format of this information must be agreed between client as server. This agreement, in our example is in the data structures ChangeRequest and SingleValue inside the header file jacobi-CS.h (which is included by both the client and the server).
Once the modification has happened, the array contributes back to the mainchare in stepCheckin, and a new iteration will be triggered if the modification exceeds the value of the threshold. The computation will then continue until a new balance is reached. To notice that this example follows the same structure used by the plain Jacobi example, therefore the upper left corner of the matrix is maintained fixed at one, and the border of the entire matrix is maintained fixed at zero.
Another modification we made to Jacobi is eliminating the call to CkExit in Main::stepCheckin when the equilibrium is reached. This gives the possibility to a client to connect and send requests. In this case, to terminate the application, the client has to send a request to the CCS handler "exit", which will provide to call CkExit.
In the case of "exit" we have no desire to reply to the client, so we can simply ignore it. Nevertheless, in the case of "changeValue" we would like to let the client know if the modification has succeded. In order to do this, we use the same structure of the request to send back a list of value change request that could not be applied by the server (clearly an empty list means that everything went ok).
The only caviat to be careful when replying to the client, is that only one single reply is allowed per request. This implies that not every element of the chare array can respond to the client, but only one element can. In our example, the chare element with index (0, 0) will reply to the client.
This client reads two parameters from the command line (the name of the host where the server is running and its port, as printed by the server at startup), connects to the server, and enters an infinite loop asking the user for input. This input, which specifies a position in the matrix to modify and its new value, is then converted to a request in the agreed format and sent to the server. It then waits for the reply from the server before asking the user for the next input. An empty input from the user will trigger the other request to the server, the one to terminate.
To notice that the server does not implement security measures to prevent requests coming from a client to corrupt the data. This can happen if a request arrives to the server while it is still updating the matrix, before it has reached the equilibrium. Here we will consider only the case that the user sends requests at the right moment, namely when the server is idle. It is left as an exercise to the user to implement a synchronization mechanism to allow the server to accept requests at any time, even if the matrix has not yet reached an equilibrium.
Other than the usual system libraries, the client requires to header files. One is jacobi-CS.h which specifies the format of request and replies; the other is ccs-client.h which contains the classes and functions necessary to use CCS. When compiling, we will still need to use the Charm++ compiler charmc with a target language of C++ and the extra flag -seq to specify that the code is sequential and not parallel. Moreover, the dynamic library called ccs-client must be linked in. The command line used to compile the client (present in the makefile) is shown here below.
charmc -o client.o client.C
|