The simple service that we developed has the luxury of being able to acquire its synchronizable state within one script in the service instance. This guarantees that the synchronizable state cannot change while it is being acquired for transmission to the synchronizing client. Once the SetDivert() call has been made, the service can modify the synchronizable state, safe in the knowledge that updates for the synchronizing client will be held in suspension until the client has processed the RPC package.
However, if it is not possible to acquire the synchronizable state within a single script, some form of semaphore is required to hold the service off from modifying the synchronizable state until it has been sampled. Such a situation may arise if part of the synchronizable state is held in non-volatile storage, or if the VTS statements needed to acquire the synchronizable state cannot be used in a script.
RPC Manager provides such a semaphore and maintains one per service instance. The semaphore provides two types of "locks" that can be requested and acquired: a "Write" lock, and a "Read" lock. The Write and Read locks behave according to the following two rules:
• Any number of Read locks may be granted simultaneously, but they will not be granted if a Write lock exists.
• Only one Write lock may be granted at a time, and it will only be granted if there are no Read locks.
In other words: Write, no Reads; Reads, no Write.
The idea is that a service module that wishes to examine the synchronizable state requests a Read lock, whereas a service module that wishes to modify the synchronizable state requests a Write lock. This allows many service modules to concurrently examine the service data without fear of it changing.
RPC Manager automatically acquires locks for a service during the synchronization process, as follows:
• A Write lock is obtained on the client at the start of service synchronization. It is released when SetSyncComplete() is called on the client, or when the synchronization process is aborted by RPC Manager due to communication failure with the server instance.
• A lock is obtained on the server immediately before GetServerChanges() is called. If the client instance provided an RPC package, a Write lock is obtained; otherwise, a Read lock is obtained. The lock is released when the client has processed the RPC package from GetServerChanges()|tag=GetServerChanges (RPC Manager Library), and the RPC package from the client instance (if any) has been processed, or when the synchronization process is aborted by RPC Manager, due to communication failure with the client instance.
Note that if you choose to use locks, you must be very careful to protect all methods that access the synchronizable state using the correct locking call:
\RPCManager\ReadLock(&Ready, SvcName);
\RPCManager\WriteLock(&Ready, SvcName);
Both lock calls require a reference to a variable as their first parameter. The variable value is set to one when the lock has been obtained. The service name is passed as the second parameter. To release the lock, simply stop or slay the ReadLock() or WriteLock() instance that the above statements are running.
The section that follows discusses the synchronization sequence.