Detecting and Resolving Concurrency Conflicts

Concurrency conflicts occur when the same item or change unit is changed on two different replicas that are later synchronized. Sync Framework provides a change applier object that simplifies detection and resolution of concurrency conflicts.

How the Change Applier Detects and Resolves Concurrency Conflicts

A concurrency conflict is detected when the destination replica’s version of a change is not contained in the source replica's knowledge.

Sync Framework provides a change applier object that the destination provider can use to detect concurrency conflicts. The change applier detects concurrency conflicts by performing the following steps for each item in the change batch that is sent by the source provider:

  1. Determines whether the destination replica's version of the item is contained in the source replica's knowledge.

  2. If the destination replica's version of the item is not contained in the source replica's knowledge, the change is in conflict.

After the change applier detects a concurrency conflict, it resolves the conflict according to either the conflict resolution policy set for the session, or the conflict resolution action set by the application for the specified conflict.

Detecting Concurrency Conflicts by Using a Change Applier

To use a change applier to detect changes, the destination provider first creates the change applier object.

Managed code Create a NotifyingChangeApplier object.

Unmanaged code Create an ISynchronousNotifyingChangeApplier object by passing IID_ISynchronousNotifyingChangeApplier to the IProviderSyncServices::CreateChangeApplier method.

The destination provider next must provide version information for each item in the change batch sent by the source provider. The two ways to do this are as follows:

  • The destination provider builds a list of versions that corresponds to the batch of changes that are sent by the source provider. The change applier uses this list to determine whether the destination version of an item is contained in the source replica's knowledge.

    Managed code To create this list, create an object of type System.Collections.Generic.IEnumerable<Microsoft.Synchronization.ItemChange>. For each item in the source provider's change batch, add an item to this list that contains the destination replica's version of the item. Pass this list to the change applier as the destinationVersions parameter of the appropriate method overload, such as ApplyChanges.

    Unmanaged code To create this list, create an IDestinationChangeVersionsBuilder object by calling IProviderSyncServices::CreateDestinationChangeVersionsBuilder. For each item in the source provider's change batch, add an item to this list that contains the destination replica's version of the item, by calling IDestinationChangeVersionsBuilder::AddItemMetadata. Get an enumerator for the list by calling IDestinationChangeVersionsBuilder::GetChangeEnumerator and pass the enumerator to the change applier as the pDestinationVersions parameter of the ApplyChanges method.

  • Alternatively, the destination provider does not pass a list of destination versions to the change applier. Instead, the destination provider implements the TryGetDestinationVersion (for managed code) or ISynchronousNotifyingChangeApplierTarget::GetDestinationVersion (for unmanaged code) method. The change applier calls this method one time for each item in the source provider's change batch. In this method the destination provider looks up the destination replica's version of the item and returns it to the change applier so the change applier can determine whether the change is a conflict.

Finally, the destination provider calls the ApplyChanges (for managed code) or ISynchronousNotifyingChangeApplier::ApplyChanges (for unmanaged code) method of the change applier.

Using a Change Applier to Resolve Concurrency Conflicts

The change applier helps a destination provider resolve conflicts by dispatching calls to a change applier target object that is specified by the provider. When a conflict resolution policy is specified, the change applier uses it to determine the correct conflict resolution action to take to resolve each conflict that occurs. When custom conflict resolution is specified, the change applier notifies the synchronization application of the conflict, and the application specifies the conflict resolution action. In either situation, the change applier calls the appropriate change applier target method and the change applier target object performs the action, such as to save the change to the replica or to log the conflict for later processing.

The synchronization application typically specifies a concurrency conflict resolution policy before synchronization is started.

Managed code The application specifies the policy by setting the ConflictResolutionPolicy property of the destination provider to the desired value.

Unmanaged code The application specifies the policy in the resolutionPolicy parameter of the ISyncSession::Start method. The destination provider receives this policy as the resolutionPolicy parameter of the IKnowledgeSyncProvider::ProcessChangeBatch method.

The destination provider passes the conflict resolution policy to the change applier so the change applier can properly dispatch methods to the change applier target. The change applier target is represented by the INotifyingChangeApplierTarget object (for managed code) or ISynchronousNotifyingChangeApplierTarget (for unmanaged code) object.

Sync Framework defines the following concurrency conflict resolution policies.

Conflict resolution policy Description

SourceWins (for managed code), CRP_SOURCE_PROVIDER_WINS (for unmanaged code)

The change made on the source replica always wins. This supports a read-only synchronization solution in which the destination replica is not to be trusted. Sync Framework specifies a conflict resolution action of SourceWins (for managed code) or SRA_ACCEPT_SOURCE_PROVIDER (for unmanaged code).

DestinationWins (for managed code), CRP_DESTINATION_PROVIDER_WINS (for unmanaged code)

The change made on the destination replica always wins. This supports the case in which the destination replica does not consume changes that are made by remote clients. Sync Framework specifies a conflict resolution action of DestinationWins (for managed code) or SRA_ACCEPT_DESTINATION_PROVIDER (for unmanaged code).

ApplicationDefined (for managed code), CRP_NONE (for unmanaged code)

The change applier notifies the synchronization application of each conflict as it occurs, by using the ItemConflicting event (for managed code) or ISyncCallback::OnConflict method (for unmanaged code). The application examines the conflicting items and specifies the conflict resolution action by calling SetResolutionAction (for managed code), or IChangeConflict::SetResolveActionForChange or IChangeConflict::SetResolveActionForChangeUnit (for unmanaged code).

Specifying Custom Conflict Resolutions

To specify the conflict resolution action dynamically for each concurrency conflict that occurs, an application performs the following actions before starting synchronization.

Managed code

  • Registers an event handler for the ItemConflicting event of the destination provider.

  • Sets the ConflictResolutionPolicy property of the destination provider to ApplicationDefined.

Unmanaged code

During synchronization, the change applier raises the ItemConflicting event (for managed code) or ISyncCallback::OnConflict method (for unmanaged code) one time for each concurrency conflict that it detects. The application can examine the two changes in conflict, make changes to the metadata or item data, and set the resolution action for the conflict by using the SetResolutionAction method (for managed code), or IChangeConflict::SetResolveActionForChange or IChangeConflict::SetResolveActionForChangeUnit method (for unmanaged code). The change applier then processes the conflict and dispatches the appropriate call to the change applier target object.

Note

The same conflict resolution action must be specified for all conflicting change units in an item or unexpected results can occur. When this type of conflict resolution is required, specify that the conflict be resolved by merging and handle the resolution in the destination provider.

Concurrency Conflict Resolution Actions Used by Managed Code

Sync Framework provides the following set of concurrency conflict resolution actions for which the change applier handles most of the processing.

Conflict resolution action Description

SourceWins

The change made on the source replica wins. The change applier passes the change to the SaveItemChange or SaveChangeWithChangeUnits method and specifies a save action of UpdateVersionAndData. The change is applied to the destination replica exactly like any non-conflicting change.

DestinationWins

The change made on the destination replica wins. The change applier passes a version-only change to the SaveItemChange or SaveChangeWithChangeUnits method and specifies a save action of UpdateVersionOnly. Only version information for the item is updated in the metadata on the destination replica. No item data changes are made.

Merge

Merge the data from the source item into the destination item. The change applier passes the source replica's change data to the SaveItemChange or SaveChangeWithChangeUnits method and specifies a save action of UpdateVersionAndMergeData. The destination provider combines the source item data and the destination item data, and applies the result to the destination replica.

SaveConflict

Log the conflict and do not apply the change. The change applier passes the conflict data to the SaveConflict method, which saves the conflict in a conflict log. For more information on logging conflicts, see Logging and Managing Conflicts.

SkipChange

Ignore the conflict and do not apply the change. The change applier does not pass the conflict data to the destination provider.

Last writer wins

The change made most recently wins. The application retrieves the time the change was made on the source replica and the time the change was made on the destination replica, by calling GetItemChangeTime or GetChangeUnitChangeTime on the two changes. The application compares the two times, and specifies the conflict resolution action that applies the change that was made last. For example, when the destination change was made last, the application specifies a conflict resolution action of DestinationWins.

Concurrency Conflict Resolution Actions Used by Unmanaged Code

Sync Framework provides the following set of concurrency conflict resolution actions for which the change applier handles most of the processing.

Conflict resolution action Description

SRA_ACCEPT_SOURCE_PROVIDER

The change made on the source replica wins. The change applier passes the change to the ISynchronousNotifyingChangeApplierTarget::SaveChange or ISynchronousNotifyingChangeApplierTarget::SaveChangeWithChangeUnits method and specifies a save action of SSA_UPDATE_VERSION_AND_DATA. The change is applied to the destination replica exactly like any non-conflicting change.

SRA_ACCEPT_DESTINATION_PROVIDER

The change made on the destination replica wins. The change applier passes a version-only change to the SaveChange or SaveChangeWithChangeUnits method and specifies a save action of SSA_UPDATE_VERSION_ONLY. Only version information for the item is updated in the metadata on the destination replica. No item data changes are made.

SRA_MERGE

Merge the data from the source item into the destination item. The change applier passes the source replica's change data to the SaveChange or SaveChangeWithChangeUnits method and specifies a save action of SSA_UPDATE_VERSION_AND_MERGE_DATA. The destination provider combines the source item data and the destination item data, and applies the result to the destination replica.

SRA_TRANSFER_AND_DEFER

Log the conflict and do not apply the change. The change applier passes the conflict data to the ISynchronousNotifyingChangeApplierTarget::SaveConflict method, which saves the conflict in a conflict log. For more information on logging conflicts, see Logging and Managing Conflicts.

SRA_DEFER

Ignore the conflict and do not apply the change. The change applier does not pass the conflict data to the destination provider.

Last writer wins

The change made most recently wins. The application retrieves the time the change was made on the source replica and the time the change was made on the destination replica, by calling ISupportLastWriteTime::GetItemChangeTime or ISupportLastWriteTime::GetChangeUnitChangeTime on the two changes. The application compares the two times, and specifies the conflict resolution action that applies the change that was made last. For example, when the destination change was made last, the application specifies a conflict resolution action of SRA_ACCEPT_DESTINATION_PROVIDER.

See Also

Reference

ISynchronousNotifyingChangeApplier Interface
ISynchronousNotifyingChangeApplierTarget Interface
CONFLICT_RESOLUTION_POLICY Enumeration
SYNC_RESOLVE_ACTION Enumeration
NotifyingChangeApplier
INotifyingChangeApplierTarget
ConflictResolutionAction
ConflictResolutionPolicy

Concepts

Handling Conflicts
Detecting and Resolving Constraint Conflicts