处理冲突

在同步过程中,目标提供程序通过 ProcessChangeBatch(对于托管代码)或 ProcessChangeBatch(对于非托管代码)方法从源提供程序收到一批变更。然后,目标提供程序必须检测和处理由于此列表而导致的任何冲突。

冲突检测

在同步过程中可能发生两类冲突:并发冲突和约束冲突。

并发冲突

当源副本的知识中未包含某个变更的目标副本版本时,将发生并发冲突。发生冲突的原因是:更新-删除和更新-更新等此类操作影响了正在同步的同一个项。

通常,目标提供程序使用由 Sync Framework 提供的变更应用方对象来检测并发冲突。变更应用方由 NotifyingChangeApplier 对象(对于托管代码)或 ISynchronousNotifyingChangeApplier 接口(对于非托管代码)表示。若要使用变更应用方来检测变更,目标提供程序必须为从源提供程序发送的变更批中的每个项提供版本信息。完成此目标的两种方法如下所示:

  • 目标提供程序生成一个变更列表,此列表对应于由源提供程序发送的变更批。对于源提供程序的变更批中的每个项,目标提供程序将向其列表中添加一个项,而该列表中包含目标副本中此项的版本。此列表被传递给变更应用方。变更应用方使用此列表来验证源副本的知识中是否包含每个项的目标版本。

  • 目标提供程序不向变更应用方提供目标版本的列表。相反,目标提供程序将实现 TryGetDestinationVersion(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::GetDestinationVersion(对于非托管代码)方法。对于源提供程序的变更批中的每个项,将调用此方法一次。

为了更好地理解变更应用方为检测冲突所做的工作,请考察目标提供程序从源提供程序接收变更批的方案。为了检测冲突,将对于变更批中的每个项执行以下步骤:

  1. 目标提供程序确定源副本的知识中是否包含该项的目标副本版本。

  2. 如果源副本的知识中未包含目标副本版本,即表明此对象发生了冲突。

约束冲突

约束冲突指违反有关项的约束(如文件夹的关系或文件系统中同名数据的位置)的冲突。

因为约束冲突的检测依赖于副本使用的数据存储区,所以,必须由提供程序检测这些类型的冲突。例如,表示分层文件系统的提供程序必须能够检测特定于存储区的有关持久化数据(如位置、命名、大小等)的约束。

冲突解决

通过定义一个适用于会话期间所有冲突的冲突解决策略,或处理一个对于每个冲突发生一次的事件,可以解决冲突。

设置冲突解决策略

为了指定将适用于会话期间所有冲突的策略,应用程序在目标提供程序的 ConflictResolutionPolicy 属性(对于托管代码)或 ISyncSession::Start 方法(对于非托管代码)中指定冲突解决策略。

设置冲突解决操作

若要为所发生的每个冲突动态设置冲突解决操作,应用程序通过使用 ItemConflicting(对于托管代码)或 ISyncCallback::OnConflict(对于非托管代码)处理项冲突事件。仅当冲突解决策略设置为 ApplicationDefined(对于托管代码)或 CRP_NONE(对于非托管代码)时,才激发此事件。

托管代码:当引发 ItemConflicting 时,事件处理程序收到一个 ItemConflictingEventArgs 对象,其中包含冲突中两个变更的元数据和项数据。事件处理程序可以通过使用 SetResolutionAction 方法检查这两个冲突、对元数据或项数据进行变更以及为冲突设置解决操作。然后,Sync Framework 处理此冲突并对源或目标提供程序进行适当的调用以应用任何变更。

非托管代码:当引发 ISyncCallback::OnConflict 时,事件处理程序收到一个 IChangeConflict 对象,其中包含冲突中两个变更的元数据和项数据。事件处理程序可以通过使用 IChangeConflict::SetResolveActionForChange 方法检查这两个冲突、对元数据或项数据进行变更以及为冲突设置解决操作。然后,Sync Framework 处理此冲突并对源或目标提供程序进行适当的调用以应用任何变更。

冲突解决

Sync Framework 提供了以下一系列冲突解决操作,对于这些操作,它自己将执行大部分处理工作。可以通过在项冲突事件处理程序中直接进行冲突变更来执行其他类型的冲突解决。

冲突解决 说明 是否可用作会话策略或项操作?

源胜出

源副本始终胜出。这支持只读同步解决方案,其中目标副本不受信任。变更应用方将变更传递到 SaveItemChange(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::SaveChange(对于非托管代码)方法。与对待任何非冲突变更一样,将此变更应用于目标副本。

两者

目标胜出

目标副本始终胜出。这支持目标副本不使用由远程客户端所进行的变更的情形。变更应用方将冲突变更作为纯版本变更传递到 SaveItemChange(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::SaveChange(对于非托管代码)方法。仅将版本信息应用到目标副本中的元数据。

两者

合并

将来自一个项的信息合并到另一个项。变更应用方将冲突变更作为合并变更传递到 SaveItemChange(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::SaveChange(对于非托管代码)方法。将合并源项数据和目标项数据,并将结果应用于目标副本。

仅限项操作

日志

记录冲突供以后处理,而不应用变更。变更应用方将冲突变更传递到 SaveConflict(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::SaveConflict(对于非托管代码)方法。

仅限项操作

延迟

忽略冲突,而不应用变更。变更应用方不将冲突变更传递到目标提供程序。

仅限项操作

已保存的冲突

当记录冲突时,将调用 SaveConflict(对于托管代码)或 SaveConflict(对于非托管代码)方法,而不是调用 SaveItemChange(对于托管代码)或 SaveChange(对于非托管代码)方法。在此情况下,提供程序必须保存冲突知识、冲突变更和冲突数据。接着,应用程序可以从冲突日志中枚举这些冲突,然后解决它们。请注意,这种冲突解决始终是本地变更。因此,正在解决冲突的应用程序必须将此解决办法作为本地变更进行应用,更新滴答计数,并将冲突知识添加到本地知识中。

此外,解决已保存冲突的应用程序必须处理已废弃的冲突。尤其是,当提供程序记录新冲突时,它必须根据其知识检查新冲突,以确保正在记录的冲突取代先前针对该项记录的任何冲突。还必须从日志中清除废弃的冲突。应用程序能够以异步方式(而不是在提供程序中)清除废弃的冲突。在此情况下,应用程序必须验证冲突不是废弃的冲突,然后尝试解决它们。

使用变更单位减少冲突

可以通过使用变更单位来表示子项变更,以减少冲突数。当使用变更单位时,将针对变更单位(而不是作为一个整体针对项)跟踪版本。因此,对同一个项内的不同变更单位进行的变更将不会导致冲突。有关更多信息,请参见同步变更单位

请参阅

参考

ISyncKnowledge 接口
ISyncProvider 接口
IKnowledgeSyncProvider 接口
IKnowledgeSyncProvider::ProcessChangeBatch
ISynchronousNotifyingChangeApplierTarget 接口
IAsynchronousNotifyingChangeApplierTarget 接口
ISyncCallback::OnConflict
CONFLICT_RESOLUTION_POLICY 枚举
SYNC_RESOLVE_ACTION 枚举
SyncKnowledge
KnowledgeSyncProvider
INotifyingChangeApplierTarget
ItemConflicting
ConflictResolutionPolicy
ConflictResolutionAction

概念

同步提供程序
应用变更
了解同步知识