The Application Programming Interface

For request sequencing, we add three functions to the NetSolve client API:

void netsl_sequence_begin();

This function takes no arguments, and returns nothing. It notifies the NetSolve system to collect information from subsequent calls to netsl() from which to construct a DAG as explained above. The netsolve services will not be scheduled for execution until a subsequent call to netsl_sequence_end()

int netsl_sequence_end(void *, ...);

This function takes as arguments an NS_NULL-terminated list of pointers. (For technical reasons, the user must use the special variable NS_NULL defined in the netsolve.h header file. These pointers are to be references to objects designated as output pointers in previous calls made to netsl() after the most recent call to netsl_sequence_begin(). These pointers designate to the NetSolve system which output parameters NOT to return to the client program. In other words, these output parameters serve only as intermediary input to calls within the chain or sequence. At the point where netsl_sequence_end() is called, the NetSolve system will transfer the collected sequence (in the form of a DAG) to a computational server(s) for execution. netsl_sequence_end() returns an error code that can be used to determine success or failure, and the cause in the case of the latter.

int netsl_sequence_status();

This function takes no arguments, and returns TRUE (non-zero) if the system is currently collecting NetSolve requests (i.e. constructing a DAG or is in the middle of a sequence) and FALSE (zero) otherwise.

Figure 9-1 illustrates what a sequencing call might look like. Two points to note in this example: i)for all requests, only the last parameter is an output, and ii)the user is instructing the system not to return the intermediate results of command1 and command2.

Figure 9-1. Sample C Code Using Request Sequencing Constructs

      submit_request("command1", A, B, C);
      submit_request("command2", A, C, D);
      submit_request("command3", D, E, F);
      begin_end(C, D, NS_NULL);
For the system to be well-behaved, we must impose certain restrictions upon the user. Our first restriction is that no control structure that may change the execution path is allowed within a sequence. We impose this restriction because the conditional clause of this control structure may be dependent upon the result of a prior request in the sequence, and since the requests are not scheduled for execution until the end of the sequence, the results will likely not be what the programmer expects.

The other restriction is that statements that would change the value of any input parameter of any component of the sequence are forbidden within the sequence (with the exception of calls to the NetSolve API itself that the system can track.) This is because during the data analysis, only references to the data are stored. So if changed, the data transferred at the end of the sequence will not be the same as the data that was present when the request was originally made. We contemplated saving the entire data, rather than just the references, but this directly conflicts with one of our premises -- that the data sets are large; multiple copies of these data are not desirable.