检测和解决并发冲突

当同一项或变更单位在以后同步的两个不同副本上发生变更时,会发生并发冲突。Sync Framework 提供可以简化检测和解决并发冲突的变更应用方对象。

变更应用方如何检测和解决并发冲突

当源副本的知识中未包含某个变更的目标副本版本时,会检测到并发冲突。

Sync Framework 提供变更应用方对象,目标提供程序可以使用它来检测并发冲突。通过对源提供程序所发送的变更批中的每一项执行以下步骤,变更应用方检测并发冲突:

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

  2. 如果源副本的知识中未包含该项的目标副本版本,即表明此变更有冲突。

变更应用方检测到并发冲突后,根据为会话设置的冲突解决策略或应用程序为指定冲突设置的冲突解决操作来解决冲突。

使用变更应用方来检测并发冲突

为了使用变更应用方来检测变更,目标提供程序首先创建变更应用方对象。

托管代码:创建 NotifyingChangeApplier 对象。

非托管代码:通过将 IID_ISynchronousNotifyingChangeApplier 传递给 IProviderSyncServices::CreateChangeApplier 方法来创建 ISynchronousNotifyingChangeApplier 对象。

目标提供程序接着必须为源提供程序发送的变更批中的每个项提供版本信息。完成此目标的两种方法如下所示:

  • 目标提供程序生成一个版本列表,此列表对应于由源提供程序发送的变更批。变更应用方使用此列表来确定源副本的知识中是否包含项的目标版本。

    托管代码:要创建此列表,请创建 System.Collections.Generic.IEnumerable<Microsoft.Synchronization.ItemChange> 类型的对象。对于源提供程序的变更批中的每个项,向此列表中添加一个项,而此列表中包含目标副本中此项的版本。将此列表作为相应方法重载(如 ApplyChanges)的 destinationVersions 参数传递给变更应用方。

    非托管代码:要创建此列表,请通过调用 IProviderSyncServices::CreateDestinationChangeVersionsBuilder 来创建 IDestinationChangeVersionsBuilder 对象。通过调用 IDestinationChangeVersionsBuilder::AddItemMetadata,对于源提供程序的变更批中的每个项,向此列表中添加一个项,而此列表中包含目标副本中此项的版本。通过调用 IDestinationChangeVersionsBuilder::GetChangeEnumerator 获取列表的枚举器,并将该枚举器作为 ApplyChanges 方法的 pDestinationVersions 参数传递给变更应用方。

  • 或者,目标提供程序不向变更应用方传递目标版本的列表。相反,目标提供程序将实现 TryGetDestinationVersion(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::GetDestinationVersion(对于非托管代码)方法。对于源提供程序的变更批中的每个项,变更应用方调用此方法一次。通过此方法,目标提供程序查找目标副本中项的版本并将其返回给变更应用方,以便变更应用方可以确定此变更是否有冲突。

最后,目标提供程序调用变更应用方的 ApplyChanges(对于托管代码)或 ISynchronousNotifyingChangeApplier::ApplyChanges(对于非托管代码)方法。

使用变更应用方来解决并发冲突

变更应用方通过对由目标提供程序指定的变更应用方目标对象调度调用,帮助提供程序解决冲突。指定冲突解决策略后,变更应用方使用它来确定要执行的正确冲突解决操作以解决发生的每个冲突。指定自定义冲突解决方法时,变更应用方通知冲突的同步应用程序,然后该应用程序指定冲突解决操作。在每个情形中,变更应用方调用相应的变更应用方目标方法,然后变更应用方目标对象执行操作,如将变更保存到副本或记录冲突以后再处理。

在启动同步之前,同步应用程序通常会指定并发冲突解决策略。

托管代码:应用程序通过将目标提供程序的 ConflictResolutionPolicy 属性设置为所需的值来指定策略。

非托管代码:应用程序在 ISyncSession::Start 方法的 resolutionPolicy 参数中指定策略。目标提供程序将此策略作为 IKnowledgeSyncProvider::ProcessChangeBatch 方法的 resolutionPolicy 参数接收。

目标提供程序将冲突解决策略传递给变更应用方,以便变更应用方可以正确调度方法给变更应用方目标。变更应用方目标由 INotifyingChangeApplierTarget 对象(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget 对象(对于非托管代码)表示。

Sync Framework 定义以下并发冲突解决策略:

冲突解决策略 说明

SourceWins(对于托管代码),CRP_SOURCE_PROVIDER_WINS(对于非托管代码)

对源副本进行的变更始终入选。这支持一个只读同步解决方案,其中目标副本不受信任。Sync Framework 指定冲突解决操作 SourceWins(对于托管代码)或 SRA_ACCEPT_SOURCE_PROVIDER(对于非托管代码)。

DestinationWins(对于托管代码),CRP_DESTINATION_PROVIDER_WINS(对于非托管代码)

对目标副本进行的变更将始终入选。这支持目标副本不使用由远程客户端所进行的变更的情形。Sync Framework 指定冲突解决操作 DestinationWins(对于托管代码)或 SRA_ACCEPT_DESTINATION_PROVIDER(对于非托管代码)。

ApplicationDefined(对于托管代码),CRP_NONE(对于非托管代码)

变更应用方通过使用 ItemConflicting 事件(对于托管代码)或 ISyncCallback::OnConflict 方法(对于非托管代码)通知同步应用程序发生的每个冲突。该应用程序通过调用 SetResolutionAction(对于托管代码)或者 IChangeConflict::SetResolveActionForChangeIChangeConflict::SetResolveActionForChangeUnit(对于非托管代码),检查发生冲突的项并指定冲突解决操作。

指定自定义冲突解决办法

为了为发生的每个并发冲突动态指定冲突解决操作,应用程序在启动同步前执行以下操作。

托管代码

  • 注册事件处理程序以处理目标提供程序的 ItemConflicting 事件。

  • 将目标提供程序的 ConflictResolutionPolicy 属性设置为 ApplicationDefined

非托管代码

在同步期间,变更应用方对于它检测到的每个并发冲突引发一次 ItemConflicting 事件(对于托管代码)或 ISyncCallback::OnConflict 方法(对于非托管代码)。通过使用 SetResolutionAction 方法(对于托管代码)或者 IChangeConflict::SetResolveActionForChangeIChangeConflict::SetResolveActionForChangeUnit 方法(对于非托管代码),应用程序可以检查发生冲突的两个变更、对元数据或项数据进行变更并设置冲突的解决操作。然后,变更应用方处理此冲突并对变更应用方目标对象调度适当的调用。

备注

但是,必须为项中所有冲突的变更单位指定冲突解决操作,否则可能会产生意外结果。需要此类型的冲突解决方法时,指定通过合并解决冲突并处理目标提供程序中的解决方法。

托管代码使用的并发冲突解决操作

Sync Framework 提供了以下一系列并发冲突解决操作,对于这些操作,变更应用方将执行大部分处理工作。

冲突解决操作 说明

SourceWins

对源副本进行的变更入选。变更应用方将变更传递给 SaveItemChangeSaveChangeWithChangeUnits 方法并指定保存操作 UpdateVersionAndData。与对待任何非冲突变更一样,将此变更应用于目标副本。

DestinationWins

对目标副本进行的变更入选。变更应用方将仅限版本的变更传递给 SaveItemChangeSaveChangeWithChangeUnits 方法并指定保存操作 UpdateVersionOnly。目标副本的元数据中只有该项的版本信息进行了更新。没有变更任何项数据。

Merge

将源项中的数据合并到目标项中。变更应用方将源副本的变更数据传递给 SaveItemChangeSaveChangeWithChangeUnits 方法并指定保存操作 UpdateVersionAndMergeData。目标提供程序将源项数据和目标项数据合并,并将结果应用于目标副本。

SaveConflict

记录冲突,不应用变更。变更应用方将冲突数据传递给 SaveConflict 方法,该方法可将冲突保存在冲突日志中。有关记录冲突的详细信息,请参阅记录和管理冲突

SkipChange

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

最后写入者入选

最近进行的变更入选。应用程序通过在两个变更上调用 GetItemChangeTimeGetChangeUnitChangeTime,来检索源副本上进行变更的时间和目标副本上进行变更的时间。应用程序比较这两个时间并指定应用最后所做变更的冲突解决操作。例如,目标变更为最后变更时,应用程序指定冲突解决操作 DestinationWins

非托管代码使用的并发冲突解决操作

Sync Framework 提供了以下一系列并发冲突解决操作,对于这些操作,变更应用方将执行大部分处理工作。

冲突解决操作 说明

SRA_ACCEPT_SOURCE_PROVIDER

对源副本进行的变更入选。变更应用方将变更传递给 ISynchronousNotifyingChangeApplierTarget::SaveChangeISynchronousNotifyingChangeApplierTarget::SaveChangeWithChangeUnits 方法并指定保存操作 SSA_UPDATE_VERSION_AND_DATA。与对待任何非冲突变更一样,将此变更应用于目标副本。

SRA_ACCEPT_DESTINATION_PROVIDER

对目标副本进行的变更入选。变更应用方将仅限版本的变更传递给 SaveChangeSaveChangeWithChangeUnits 方法并指定保存操作 SSA_UPDATE_VERSION_ONLY。目标副本的元数据中只有该项的版本信息进行了更新。没有变更任何项数据。

SRA_MERGE

将源项中的数据合并到目标项中。变更应用方将源副本的变更数据传递给 SaveChangeSaveChangeWithChangeUnits 方法并指定 SSA_UPDATE_VERSION_AND_MERGE_DATA 的保存操作。目标提供程序将源项数据和目标项数据合并,并将结果应用于目标副本。

SRA_TRANSFER_AND_DEFER

记录冲突,不应用变更。变更应用方将冲突数据传递给 ISynchronousNotifyingChangeApplierTarget::SaveConflict 方法,该方法可将冲突保存在冲突日志中。有关记录冲突的详细信息,请参阅记录和管理冲突

SRA_DEFER

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

最后写入者入选

最近进行的变更入选。应用程序通过在两个变更上调用 ISupportLastWriteTime::GetItemChangeTimeISupportLastWriteTime::GetChangeUnitChangeTime,来检索源副本上进行变更的时间和目标副本上进行变更的时间。应用程序比较这两个时间并指定应用最后所做变更的冲突解决操作。例如,目标变更为最后变更时,应用程序指定冲突解决操作 SRA_ACCEPT_DESTINATION_PROVIDER

请参阅

参考

ISynchronousNotifyingChangeApplier 接口
ISynchronousNotifyingChangeApplierTarget 接口
CONFLICT_RESOLUTION_POLICY 枚举
SYNC_RESOLVE_ACTION 枚举
NotifyingChangeApplier
INotifyingChangeApplierTarget
ConflictResolutionAction
ConflictResolutionPolicy

概念

处理冲突
检测和解决约束冲突