Previous Page Arrow Next Page Arrow

7.2 Synchronization Endpoint Implementation Notes

Internal vs. Adapter

Two approaches may be used to implement the synchronization endpoints:

  • Internal implementation: the synchronization metadata (digest, record level info) is stored in the application tables and the application takes complete responsibility for the implementation of the endpoint.

  • Adapter: the synchronization metadata is managed by an adapter library rather than by the application itself. The synchronization metadata is stored in separate tables. These tables may reside in the same database as the application tables (recommended option to be robust with respect to backup/restore operations), or in a separate database (fall back option). The adapter handles the SData sync protocol and the endpoint synchronization logic. It interacts with the application through a small number of interfaces that read and write resources.

The following diagram shows the structure of an endpoint implemented with the adapter approach:

sync adapter

The internal solution allows the application to implement the SData synchronization protocol in an optimal way. As the application controls everything, it can optimize the storage and the algorithms.

The adapter alternative gives less control on the application side but relieves the application from implementing the synchronization logic. This approach allow applications to support the SData synchronization protocol with a minimal implementation effort (implementing the adapter interface is much simpler than implementing the whole SData sync protocol).

Despite the extra effort that it requires, the internal solution has some advantages and should be considered for framework-based applications. The adapter alternative is probably the right path for applications that are not structured around a strong framework.

Adapter Interfaces

This section gives a very simplified specification of the adapter interface. This is by no means an “industrial” specification, just a preliminary prototype to explain how the responsibilities will be split between the application and the adapter.

The heart of the adapter interfaces will be a pair of interfaces like the following:

public interface ISyncSource
{
  IEnumerable<IResourceHead> ScanResources(string oldToken, out string newToken);
  XmlNode[] ReadResources(string[] localID);
}

public interface ISyncTarget
{
  IResourceHead[] GetResourceHeads(string[] localIDs);
  IBatchResult ProcessBatch(IBatch batch);
}

The ISyncSoure interface is called by the adapter when it receives a request on its $syncSource URL. It allows the adapter to scan the application table for changes (ScanResources method) and then obtain the XML payload for the synchronization entries (ReadResources method).

The ISyncTarget interface is called by the adapter when it receives a request on its $syncTarget URL. It allows the adapter to detect and handle conflicts and then pass the batch of changes to the application for processing (the changes go through the application’s business logic layer before being written to the database).

If the application only supports unidirectional synchronization on some of its resources, it only needs to implement one of these interfaces.

Resource Head

The ScanResources method does not return the whole data for the changes, it only returns a small piece of heading information for every resource. This heading corresponds to the following C# interface:

public interface IResourceHead
{
  string LocalID { get; }
  string ETag { get; }
  DateTime ModifiedStamp { get; }
}

These properties should be set as follows by the application:

Property Value Comment
LocalID Primary key value for the resource
ETag ETag value for the resource The adapter uses this information to decide if the resource has changed or not. If the application does not keep track of any version information (internal tick, modified stamp), it should compute a checksum on the resource data and return it as ETag.
ModifiedStamp Timestamp of last modification The adapter uses this information because the SData protocol requires it for conflict detection. If the application does not keep track of any the modification stamps, it should return the current timestamp (the conflict handling rule will be misled but this is the best we can do in this case).

Token

The adapter takes full responsibility for the synchronization metadata: digest and resource-level sync data. When the adapter is used, the application does not see the synchronization “ticks” any more (they are delt with at the adapter level). On the other hand, the application may have some way of identifying the ressources that have changed: a timestamp, an internal tick, an offset in a transaction log, etc. This information is managed as a “token” by the adapter. If the application does not have any internal mechanism to track changes, the adapter will still work but will be less efficient: the token will always be empty and the adapter will have no choice but do a full table scan every time it processes a request on its $syncSource URL.

So, the token is a piece of information that the application logic understands and that it uses to query changes efficiently. From the adapter and the SData protocol standpoint, the token is an opaque piece of data that is passed around (it is included in digest entries) but that is never interpreted in any way outside of the application.

Adapter Tables

The adapter maintains two tables:

  • The Digest table in which it keeps track of the digest entries.

  • The ResSync table in which it keeps track of the resource-level synchronization data (endpoint id + tick).

The Digest table has the following columns:

Column name Type Scope Description
EndpointID integer Adapter Identifies the endpoint internally inside the adapter (saves space in the ResSync table)
EndpointUrl string Protocol External (protocol level) identifier for the endpoint.
Tick integer Protocol Tick value for the endpoint
Token string Application Token value that corresponds to the tick.
ConflictPriority integer Protocol Conflict priority

The ResSync table has the following columns:

Column name Type Scope Description
LocalID string Application Local id for the resource in the application. (primary key in the application database)
GlobalID uuid Protocol Global id for the resource. (identical at all endpoints for a given resource)
EndpointID integer Adapter ID of the endpoint where the resource was last modified
Tick integer Protocol EndpointID's tick when the resource was last modified.
ModifiedStamp timestamp Protocol Timestamp at which the resource was last modified
ETag string Application/Protocol Application's etag value for the resource. (checksum or sequence number).

$syncDigest Processing

The adapter processes this request by reading its Digest table. There is no interaction with the application during this request.

$syncSource Processing

When the adapter receives a request on its $syncSource URL, it processes it as follows:

  • First, it brings its ResSync table up to date. For this, it goes throught the following steps:

  • It gets the token for the local entry of the request’s digest.

  • It calls the ScanResources method of the ISyncSource interface, passing the token as first parameter.

  • It processes the ressource headings returned by the call. For each one, it compares the ETag value with the value in the corresponding record of its ResSync table. If the ETag values differ, its sets the tick to the current local tick of its digest table and it updates the ModifiedStamp of the ResSync record.* Then, it generates the SData response to the $syncSource request:

$syncTarget Processing

When the adapter receives a request on its $syncTarget URL, it processes it as follows:

  • First, it performs conflict detection. The steps are the following:

  • It gets the local ids for the batch entries from its ResSync table.

  • It calls the GetResourceHeads method of the ISyncTarget interface to get the resource headings from the application

  • For each resource heading, it compares the ETag value with the value in the corresponding record of its ResSync table. If the ETag values differ, its sets the tick to the current local tick of its digest table and it updates the ModifiedStamp of the ResSync record.

  • It applies the SData conflict detection rules, using the information from its Digest and ResSync tables.* Then it updates the resources in the application:

Other Interfaces

The adapter will need other interfaces to integrate fully into the application’s environment. For example, if the application wants the Digest and ResSync tables to be stored in its database, it will need to provide an additional interface that the adapter will use to obtain a connection to the application database.

Also, the implementation described needs to be refined to handle deleted records (when necessary). If the application does not manage any tombstone data, this may involve a full scan of the application table.

Adapter Summary

The endpoint adapter is a library that handles the SData synchronization protocol on behalf on an application. The adapter reduces the implementation work on the application side. The application will need to provide a small number of methods that the adapter will call to query modified resources, get resource headings and apply a batch of changes. The adapter will deal with all the nitty-gritty details of the synchronization protocol.


Previous Page Arrow Next Page Arrow