Our simple service example has very little data in its synchronizable state. A true service will typically have a much richer set of data. While along with their ability to pass streams as RPC parameters, a set of packed RPCs are a very flexible means to cope with diverse sets of data, some data sets may be so large that it is desirable to minimize the amount of data transferred.
Typical data sets that fall into this category include data that is acquired over a period of time, but has to be retained. The classic example of this is alarm history data. A user may wish to display such data on a client PC at any given time. The programmer is left with an un-enviable choice:
1. Transfer all data during service synchronization. This lengthens synchronization times significantly, and becomes impractical if many clients are attempting to synchronize concurrently. It has the advantage that, after synchronization, response times to user requests are short, as the data is local to the client.
2. Leave all the infrequently accessed data on the server. This avoids the lengthy synchronization times, but gives a poorer response time to user requests to access such data.
RPC Manager provides support for a compromise between these two extremes, by transferring only that part of the data that the client doesn't have. Initially, the client has to be passed the entire set of synchronizable data, but subsequent synchronizations are much briefer, as only the data that the client doesn't have is transferred. Such an arrangement implies that the client must have the ability to retain the bulk of the synchronizable state in non-volatile storage.
You may have noticed that the GetServerChanges()module that was developed in the Simple service example (see Adding Server-only Synchronization) did not make any use of its first parameter, the RevisionInfo parameter. That parameter is a stream which RPC Manager obtains by calling GetClientRevision() on the synchronizing client.
GetClientRevision() is provided by the service code and RPC Manager passes in a reference to a variable that it expects to be set to the stream of client revision information. The content of the stream is entirely service-specific, and contains whatever revision information is appropriate for the service to represent the latest data that the client instance has. RPC Manager places no interpretation on the contents of the stream. Typically, GetClientRevision() will populate the stream with one or more VTS timestamps.
<
{=================== GetClientRevision =============================}
{===================================================================}
GetClientRevision
(
RevisionRef { Reference to revision information };
)
Only [
If watch(1);
[
*RevisionRef = BuffStream("");
{***** Populate the stream with a single timestamp *****}
SWrite(*RevisionRef, "%5b", LastKnownTimeStamp);
Return(Invalid);
]
]
{ End of GetClientRevision }
>
It then becomes the server instance's responsibility to utilize the information within the RevisionInfo parameter to GetServerChanges()to generate the correct RPC package to bring the client up to date with the server.
GetClientRevision() is launched by RPC Manager on the service thread. Note that this module can be either a subroutine returning Invalid, or a launched module that slays itself when complete. In the example above, we have chosen to make it a subroutine module.
The section that follows discusses changes made to RPC packages by clients.