Share via


Recovering an Out-of-Date Replica

Before Sync Framework applies changes, it compares the forgotten knowledge of the source replica with the current knowledge of the destination replica. If the destination knowledge does not contain the forgotten knowledge, Sync Framework identifies the destination replica as out-of-date and begins a recovery synchronization.

To perform a recovery synchronization, Sync Framework takes the following steps:

  • If the application has registered to receive notification, Sync Framework notifies the application that a recovery synchronization is needed. The application can choose to fully enumerate all items in the source replica, to perform a partial synchronization, or to cancel synchronization. The default action is to cancel synchronization.

  • When the application specifies a full enumeration, Sync Framework discards the current change batch, fully enumerates all items in the source replica, and applies them to the destination replica. 

  • When the application specifies a partial synchronization, Sync Framework continues to enumerate source changes and apply them to the destination replica as in a typical synchronization, except that changes to the learned knowledge are applied as single item exceptions.

Understanding Recovery Synchronization

In a Sync Framework synchronization community, each replica contains metadata about the items in the replica. The metadata tracks information about creation, modification, and deletion of the items that are stored on the replica. Typically, a replica must periodically clean up the metadata for deleted items to avoid running out of storage space. When a replica has removed metadata for a deleted item, it can no longer enumerate the deletion and send it as a change during synchronization. As long as all replicas in a synchronization community synchronize the deletions before the metadata is cleaned up, all deletions are propagated correctly and no problems occur.

However, a replica can become out-of-date if it does not synchronize its data until after another replica has performed metadata cleanup. In this case, the replica that has performed the cleanup can no longer enumerate the changes that have been cleaned up, and so cannot send them to the out-of-date replica. To recover from this, when synchronization is tried between a source replica that has performed metadata cleanup and a destination replica that is out-of-date, Sync Framework requires that the destination replica be restored by using recovery synchronization. Recovery synchronization is required to prevent the out-of-date replica from reintroducing an item that was deleted from the synchronization community.

Sync Framework uses the forgotten knowledge of the source replica to detect when the destination replica is out-of-date. When a replica removes metadata for a deleted item, it records the version of the deletion in the forgotten knowledge of the replica. The forgotten knowledge can then be used to identify items that were known by the replica, were deleted, and had their metadata removed. Be aware that forgotten knowledge is an overestimation of which items had their metadata removed. Therefore, the forgotten knowledge might also contain items that still have active entries in the metadata.

Responding to Notification of a Recovery Synchronization

An application can register to receive notification that a recovery synchronization is needed. This notification gives the application the opportunity to begin a full enumeration, continue with the current session, or stop the session. By default, if the application has not registered to receive this notification, Sync Framework stops the session.

Responding to Notification of a Recovery Synchronization by Using Managed Code

To receive notification that a recovery synchronization is needed, the application implements an event handler and registers it to receive the FullEnumerationNeeded event. When this event is raised, the event handler responds by setting the Action property of the FullEnumerationNeededEventArgs object to one of the following actions:

Responding to Notification of a Recovery Synchronization by Using Unmanaged Code

To receive notification that a recovery synchronization is needed, the application implements the ISyncCallback interface and registers it by using ISyncSession::RegisterCallback. Before a recovery synchronization begins, Sync Framework calls ISyncCallback::OnFullEnumerationNeeded. This method returns one of the following actions:

  • SFEA_FULL_ENUMERATION causes Sync Framework to discard the current change batch and begin a full enumeration by calling the following methods:

  • SFEA_PARTIAL_SYNC causes Sync Framework to apply the current change batch and to continue with the session as in a typical synchronization, except that all changes to the learned knowledge are applied as single item exceptions. Single item exceptions are less efficient than the typical knowledge representation, so partial synchronization should be used only when a full enumeration cannot be performed immediately. Be aware that Sync Framework will continue to request a full enumeration at the beginning of each synchronization until a full enumeration is performed.

  • SFEA_ABORT causes Sync Framework to stop the current session.

Fully Enumerating All the Changes on the Source Replica

During a full enumeration, Sync Framework requires the source provider to enumerate all its changes. Sync Framework then compares the changes from the source provider to the items in the destination replica. Any item in the destination replica that does not have a corresponding change from the source provider is assumed to have been deleted from the source replica and will be deleted from the destination replica. Because of this, make sure that the source provider correctly enumerates all items in the source replica or items will be incorrectly deleted from the destination replica.

Fully Enumerating Changes by Using Managed Code

To fully enumerate changes from the source provider, Sync Framework calls GetFullEnumerationChangeBatch(UInt32, SyncId, SyncKnowledge, Object) instead of GetChangeBatch(UInt32, SyncKnowledge, Object). When this method is called, the source provider returns a FullEnumerationChangeBatch object. To build this change batch, follow these steps:

  1. Open an ordered group by using BeginOrderedGroup(SyncId). The item ID that is used to begin the group must be the first ID that is enumerated and must be less than or equal to the lower enumeration bound specified in GetFullEnumerationChangeBatch(UInt32, SyncId, SyncKnowledge, Object).

  2. Optionally add changes to the batch, sorted by item ID, that have item IDs that are less than the lower enumeration bound and that are not contained in the destination knowledge.

  3. Add changes to the batch, sorted by item ID, that have item IDs greater than or equal to the lower enumeration bound.

  4. Close the ordered group by using EndOrderedGroup(SyncId, SyncKnowledge). Specify the upper enumeration bound as the ID of the last change that was added to the group. When this is the last batch, specify the upper enumeration bound as Infinity.

  5. When this is the last batch, call [M:Microsoft.Synchronization.ChangeBatchBase.SetLastBatch;] otherwise, Sync Framework will call GetFullEnumerationChangeBatch(UInt32, SyncId, SyncKnowledge, Object) again.

Fully Enumerating Changes by Using Unmanaged Code

To fully enumerate changes from the source provider, Sync Framework calls IKnowledgeSyncProvider::GetFullEnumerationChangeBatch instead of IKnowledgeSyncProvider::GetChangeBatch. When this method is called, the source provider returns an ISyncFullEnumerationChangeBatch object. To build this change batch, follow these steps:

  1. Create the change batch object by using IProviderSyncServices::CreateFullEnumerationChangeBatch.

  2. Open an ordered group by using ISyncChangeBatchBase::BeginOrderedGroup. The item ID that is used to begin the group must be the first ID that is enumerated and must be less than or equal to the lower enumeration bound specified in GetFullEnumerationChangeBatch.

  3. Optionally add changes to the batch, sorted by item ID, that have item IDs that are less than the lower enumeration bound and that are not contained in the destination knowledge.

  4. Add changes to the batch, sorted by item ID, that have item IDs greater than or equal to the lower enumeration bound.

  5. Close the ordered group by using ISyncChangeBatchBase::EndOrderedGroup. Specify the upper enumeration bound as the ID of the last change that was added to the group. When this is the last batch, specify the upper enumeration bound as NULL.

  6. When this is the last batch, call ISyncChangeBatchBase::SetLastBatch; otherwise, Sync Framework will call GetFullEnumerationChangeBatch again.

Processing Changes During a Recovery Synchronization

To determine which items to delete from the destination replica, Sync Framework requires that the destination provider enumerate, in sorted order by item ID, all items in the destination replica that have item ID between the lower and upper enumeration bounds of each change batch. An item in the destination replica that does not have a corresponding change enumerated from the source provider will be deleted.

The destination provider passes this list of destination items to the change applier. The change applier determines how to handle each change and calls the appropriate destination provider method to apply the change to the destination replica.

Processing Changes by Using Managed Code

To process changes during a recovery synchronization, Sync Framework calls the ProcessFullEnumerationChangeBatch(ConflictResolutionPolicy, FullEnumerationChangeBatch, Object, SyncCallbacks, SyncSessionStatistics) method of the destination provider. This method provides a FullEnumerationChangeBatch object that contains the changes from the source provider.

If the destination provider uses the NotifyingChangeApplier object provided by Sync Framework, the destination provider must call the ApplyFullEnumerationChanges(ConflictResolutionPolicy, FullEnumerationChangeBatch, IChangeDataRetriever, IEnumerableItemChange, SyncKnowledge, ForgottenKnowledge, INotifyingChangeApplierTarget, SyncSessionContext, SyncCallbacks) method to apply the changes. This method requires a collection, sorted by item ID, of all destination changes that have item IDs between the DestinationVersionEnumerationRangeLowerBound and DestinationVersionEnumerationRangeUpperBound properties of the source change batch. To apply changes, the NotifyingChangeApplier object calls INotifyingChangeApplierTarget methods the same as during a typical synchronization.

Processing Changes by Using Unmanaged Code

To process changes during a recovery synchronization, Sync Framework calls the IKnowledgeSyncProvider::ProcessFullEnumerationChangeBatch method of the destination provider. This method provides an ISyncFullEnumerationChangeBatch object that contains the changes from the source provider.

If the destination provider uses the ISynchronousNotifyingChangeApplier object provided by Sync Framework, the destination provider must call the ISynchronousNotifyingChangeApplier::ApplyFullEnumerationChanges method to apply the changes. This method requires a collection, sorted by item ID, of all destination changes that have item IDs between the ISyncFullEnumerationChangeBatch::GetClosedLowerBoundItemId and ISyncFullEnumerationChangeBatch::GetClosedUpperBoundItemId properties of the source change batch. To apply changes, the ISynchronousNotifyingChangeApplier object calls ISynchronousNotifyingChangeApplierTarget Interface methods the same is during a typical synchronization.

See Also

Concepts

Implementing a Standard Custom Provider

Enumerating Changes

Applying Changes