筛选同步数据

筛选器用于限制同步的数据。通常,源提供程序在变更枚举期间应用筛选器,以便限制发送的变更。Sync Framework 支持以下类型的筛选器。

  • 项筛选器将同步数据限制到项的子集,例如,只在两个文件夹之间同步 .txt 文件,而忽略其他类型的文件。如果变更会导致现有项移入或移出筛选器,则项不会采用此方式变更。项筛选器简单易用,但用于同步的元数据随着同步作用域中项数的增长而成比例增长。

  • 变更单位筛选器将同步数据限制为变更单位的子集,例如限制为只同步联系人的 name 和 phone number 字段,而忽略其余的变更单位。

  • 自定义筛选器以 Sync Framework 未知的方式限制同步数据。可以随着时间推移将项移入和移出自定义筛选器。Sync Framework 定义了其他元数据、接口和类,它们高效地支持自定义筛选器,同时使元数据的总体大小保持较小规模。

筛选器可由同步应用程序定义,或者由源或目标提供程序定义,或者可以在源和目标提供程序之间协商。

在源提供程序检测到变更时筛选器由源提供程序使用。在变更检测期间生成的变更批只包括传递给筛选器的同步数据。

在目标提供程序应用变更时筛选器还可由目标提供程序使用。应用于目标副本的变更只包括传递给筛选器的同步数据。

控制可同步的项

项筛选器定义在变更枚举期间源提供程序发送的项变更。因为筛选项的方式依赖于同步作用域中的数据类型,所以,Sync Framework 允许源提供程序定义筛选机制。如果在提供程序和同步应用程序之间要求与筛选器有关的通信,可通过使用任何适当的机制实现这一通信。

在源提供程序筛选项变更时,Sync Framework 要求源提供程序将与筛选器有关的信息附加到在变更枚举期间发送的所有变更批对象。在变更批对象中存在项筛选器信息将通知 Sync Framework 正在发生经筛选的同步,以便 Sync Framework 可以正确处理筛选的变更批的知识。如果源提供程序筛选在变更批中包括的项,但未对变更批对象指定项筛选器信息,则 Sync Framework 可能不会正确处理该知识。

当源提供程序使用筛选器来限制变更批中包含的项时,该提供程序必须将筛选器相关信息附加到 ChangeBatch(对于托管代码)或 ISyncChangeBatch(对于非托管代码)对象。筛选器信息由 ItemListFilterInfo 对象表示(对于托管代码),或者由设置了 SYNC_FILTER_INFO_FLAG_ITEM_LIST 标志的 ISyncFilterInfo 对象表示(对于非托管代码)。在非托管代码中,提供程序通过使用 IProviderFilteredSyncServices::CreateFilterInfo 创建 ISyncFilterInfo 对象。通过使用 ChangeBatch(对于托管代码)或 IProviderFilteredSyncServices::CreateFilteredEnumerationChangeBatch(对于非托管代码)来创建变更批对象,可以将筛选器信息附加到变更批。

有关如何使用项筛选的更多信息,请参见如何筛选枚举项

控制可同步的变更单位

变更单位筛选器定义为在变更枚举期间源提供程序发送的各个项变更包括哪些变更单位变更。在副本只存储在作用域中为项定义的变更单位的子集时,变更单位筛选器会很有用。

例如,同步社区交换联系信息,并且为 name、phone number 和 address 定义变更单位。社区中的一个副本是只能存储 name 和 phone number 的移动设备。该副本使用变更单位筛选器来指定它只跟踪这两个变更单位的知识。在源副本将数据同步到设备副本时,它使用变更单位筛选器以便只发送与 name 和 phone number 变更单位有关的信息。来自源提供程序的已知知识被投影到变更单位筛选器上,这样设备副本上的知识只包含 name 和 phone number 变更单位的知识。同样,在设备上本地执行变更并且设备随后在同步会话中充当源副本时,接收变更的副本只更新指定变更单位集合的知识。

在使用某一变更单位筛选器时,Sync Framework 将变更批的已知知识投影到该筛选器指定的变更单位集合上,以便变更批次的已知知识只包含与该指定变更单位集合有关的信息。

为了筛选变更单位变更,源提供程序创建一个 ChangeUnitListFilterInfo 对象(对于托管代码)或 IChangeUnitListFilterInfo(对于非托管代码),并指定要同步的变更单位集合。在非托管代码中,通过将 SYNC_FILTER_INFO_FLAG_CHANGE_UNIT_LIST 指定给 IProviderFilteredSyncServices::CreateFilterInfo 方法,创建 IChangeUnitListFilterInfo 对象。源提供程序通过使用 ChangeBatch(对于托管代码)或 IProviderFilteredSyncServices::CreateFilteredEnumerationChangeBatch(对于非托管代码)来创建变更批对象,将筛选器信息附加到变更批。

有关如何使用变更单位筛选器的更多信息,请参见如何筛选枚举的变更单位

使用自定义筛选器控制同步内容

自定义筛选器通常由提供程序开发人员在 Sync Framework 之外定义,尽管也可以由第三方定义。Sync Framework 不了解筛选器如何确定同步作用域中包含哪些内容。可以通过随着时间推移将项移入和移出筛选器的方式来定义自定义筛选器。例如,对存储介质文件的副本,可以定义一个筛选器,其中包含级别为三星或更高级别的所有文件。如果用户更改了某个文件的评级,则该文件可能会移入或移出筛选器。

请注意,简单提供程序或报告约束冲突或使用变更应用服务的提供程序无法使用自定义筛选器,否则可能出现意外结果。

为了有效地支持自定义筛选器,Sync Framework 定义了几个新概念。

  • “筛选器跟踪副本”**是一个副本,它维护的元数据用于定义哪些项和变更单位当前位于被跟踪的筛选器中,哪些项和变更单位最近移入或移出了被跟踪的筛选器,以及筛选器遗忘知识(包括不在被跟踪的筛选器中和已被忘记的所有项和变更单位)。跟踪筛选器并不影响将哪些项存储在副本中。一个副本可以跟踪多个筛选器,同时将所有项存储在同步作用域中。通常,筛选器跟踪副本可以为其任何被跟踪的筛选器提供筛选后的变更批。

  • “筛选副本”**是一个副本,它仅为筛选器中的项和变更单位存储项和变更单位数据,以及为原先位于筛选器中但已移出的项和变更批存储元数据。筛选副本始终跟踪它使用的筛选器,并且也可能跟踪其他筛选器。筛选的目标提供程序可以从源提供程序请求筛选的变更枚举,或者它可以在变更应用期间请求完全变更枚举并自行筛选变更。

  • “虚影”**是筛选副本中原先位于筛选器中但已移出的项或变更单位。筛选副本存储虚影的元数据,但不存储项或变更单位数据。

  • “筛选器遗忘知识”**为筛选器跟踪定义起点。筛选器跟踪副本可以通过删除虚影并提前了解筛选器遗忘知识,以包含已被删除的虚影的最高版本,从而节省存储空间。此外,当某个筛选器被同步社区中的其他副本使用之后,而副本开始跟踪该筛选器时,也将使用筛选器遗忘知识。

跟踪筛选器

建议同步社区中的所有副本都跟踪社区中使用的筛选器。当筛选副本从筛选器跟踪副本收到筛选的变更枚举时,筛选副本的知识保持为较小规模。当筛选副本从不跟踪筛选器的副本收到筛选的变更枚举时,知识的大小将根据所发送的变更数而成比例增长。

有关跟踪筛选器的更多信息,请参见如何跟踪筛选器和枚举筛选的变更

筛选器元数据

为了跟踪筛选器,副本将存储该副本中每个项或变更单位的筛选器元数据。筛选器元数据包含下表中的元素:

Is in filter(是否在筛选器中) Move version(移动版本)

指示项或变更单位是否在筛选器中。

导致项移入移出筛选器的变更版本。当创建某个项且该项在筛选器中时,此版本设置为该项的创建版本。如果某个项从来不在该筛选器中,则此版本设置为 (0,0)。

当副本开始跟踪筛选器时,必须针对该筛选器评估所有项或变更单位。如果某个项或变更单位在筛选器中,则其筛选器元数据必须指示它在该筛选器中,且其移动版本必须设置为该项或变更单位的最新变更版本。如果某个项不在筛选器中,则其筛选器元数据必须指示它不在筛选器中,并且其移动版本必须设置为 (0,0)。

筛选器跟踪副本还可以存储其跟踪的每个筛选器的筛选器遗忘知识。当筛选器跟踪副本从筛选器的起源跟踪筛选器时,它不存储筛选器遗忘知识,除非它从不跟踪筛选器的副本收到同步数据。当筛选器跟踪副本在生成该筛选器之后的某个时间跟踪该筛选器时,它必须将筛选器遗忘知识初始化为副本的当前知识。当从副本上清除逻辑删除和筛选器变更元数据时,可以放弃筛选器遗忘知识,并转而使用此遗忘知识。

协商跟踪的筛选器

筛选器跟踪提供程序必须实现 IFilterTrackingProvider(对于托管代码)或 IFilterTrackingProvider(对于非托管代码)。可以使用此接口来与在源副本和目标副本上跟踪的筛选器通信。源副本为在源副本和目标副本上跟踪的筛选器发送筛选器元数据。

当同步会话中的这两个提供程序都是筛选器跟踪提供程序时,Sync Framework 将调停由这两个提供程序跟踪的筛选器之间的协商。将通过以下步骤,在两个筛选器跟踪提供程序之间协商跟踪的筛选器:

  1. 在调用 BeginSession(对于托管代码)或 IKnowledgeSyncProvider::BeginSession(对于非托管代码)之后,Sync Framework 将对于目标提供程序调用 SpecifyTrackedFilters(对于托管代码)或 IFilterTrackingProvider::SpecifyTrackedFilters(对于非托管代码)。

  2. 目标提供程序枚举其跟踪筛选器的列表,并将每个筛选器传递到在对 SpecifyTrackedFilters 的调用中指定的 RequestTrackedFilterCallback 委托(对于托管代码)或 IFilterRequestCallback 对象的 IFilterRequestCallback::RequestFilter 方法(对于非托管代码)。

  3. 对于目标提供程序指定的每个筛选器,Sync Framework 对于源提供程序调用 TryAddTrackedFilter(对于托管代码)或 IFilterTrackingProvider::AddTrackedFilter(对于非托管代码)。

  4. 源提供程序维护由目标提供程序跟踪的筛选器的列表,并返回一个指示它是否跟踪指定的筛选器的值。

  5. Sync Framework 将此值传递给目标提供程序。

为跟踪的筛选器发送筛选器元数据

当目标提供程序跟踪源提供程序也在跟踪的筛选器时,源提供程序必须为双方同时跟踪的筛选器发送筛选器元数据。为此,请向 GetChangeBatch(对于托管代码)或 IKnowledgeSyncProvider::GetChangeBatch(对于非托管代码)的源提供程序实现添加以下变更:

发送筛选的变更

通常,表示筛选器跟踪副本的源提供程序可以为任何跟踪的筛选器枚举筛选的变更批。筛选器可由应用程序通过使用应用程序与源提供程序之间的某种自定义机制来进行标识,或者它可在源提供程序与目标提供程序之间进行协商。本文后面将介绍筛选器协商。

若要发送筛选的变更批,请将以下元素添加到源提供程序的 GetChangeBatch 方法:

  • 创建 CustomFilterInfo(对于托管代码)或 ICustomFilterInfo(对于非托管代码)对象,其中包含用于同步的筛选器。通过将筛选器信息对象传递到适当的变更批构造函数 ChangeBatch(对于托管代码)或通过调用 IProviderFilteredSyncServices::CreateFilteredEnumerationChangeBatch(对于非托管代码),创建筛选的变更批对象。此外,当创建变更批对象时,将传递筛选器的筛选器遗忘知识,而不是副本的遗忘知识。

  • 如果某个项或变更单位以前在筛选器中,但当前不在该筛选器中,则将 ChangeKind 属性指定为 Ghost(对于托管代码)或将 SYNC_CHANGE_FLAG_GHOST 标志传递到 ISyncChangeBatchBase::AddItemMetadataToGroup(对于非托管代码)。

  • 当目标提供程序的筛选类型为 CurrentItemsOnly(对于托管代码)或 FT_CURRENT_ITEMS_ONLY(对于非托管代码)时,仅当某个项在筛选器中时,才将该项包含在变更批中。也就是说,不发送虚影。

  • 当目标提供程序的筛选类型为 CurrentItemsAndVersionsForMovedOutItems(对于托管代码)或 FT_CURRENT_ITEMS_AND_VERSIONS_FOR_MOVED_OUT_ITEMS(对于非托管代码)时,将包含筛选器中的项以及已移出的项。如果某个项或变更单位以前在筛选器中,但该项或变更单位当前不在筛选器中,并且目标知识不包含将项或变更单位移出筛选器的变更版本,则必须发送移出信息。

应用筛选器元数据

当目标提供程序表示筛选器跟踪提供程序并且使用变更应用方来将变更应用于目标副本时,目标提供程序必须实现 IFilterTrackingNotifyingChangeApplierTarget(对于托管代码)或 IFilterTrackingNotifyingChangeApplierTarget(对于非托管代码)。此接口包含 Sync Framework 用于获得所跟踪筛选器的筛选器键映射和筛选器遗忘知识的方法。它还包含 SaveKnowledgeWithFilterForgottenKnowledge(对于托管代码)或 IFilterTrackingNotifyingChangeApplierTarget::SaveKnowledgeWithFilterForgottenKnowledges(对于非托管代码)方法,Sync Framework 将针对筛选器跟踪提供程序调用此方法,而不调用 StoreKnowledgeForScope(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::SaveKnowledge(对于非托管代码)。Sync Framework 在变更批应用后,使用此方法将更新的知识、遗忘知识以及筛选器遗忘知识发送到提供程序。

除了实现 IFilterTrackingNotifyingChangeApplierTarget 之外,还必须更新目标提供程序的 SaveItemChangeSaveChangeWithChangeUnits 方法(对于托管代码);或 ISynchronousNotifyingChangeApplierTarget::SaveChangeISynchronousNotifyingChangeApplierTarget::SaveChangeWithChangeUnits 方法(对于非托管代码)以执行以下步骤:

  1. 通过对变更对象调用 GetFilterChange(对于托管代码)或 ISyncChangeWithFilterKeyMap::GetFilterChange(对于非托管代码),获取每个跟踪筛选器的筛选器变更元数据。

  2. 当筛选器变更元数据存在时,请检查以确保它不过时。当项的目标知识中包含筛选器变更的移动版本时,此变更已过时。使用变更单位时,仅当所有变更单位的目标知识中都包含移动版本时,筛选器变更才过时。如果筛选器变更已过时,请勿将其应用到目标副本。

  3. 如果筛选器变更元数据存在但未过时,请检查以确保它不与目标副本中已存在的筛选器变更信息冲突。若要检查是否存在冲突,请执行以下步骤:

    1. 获取目标副本中当前为项或变更单位存储的移动版本。

    2. 检查移动版本是包含在项的生成知识中,还是包含在与该项关联的每个变更单位变更的生成知识中。

    3. 如果移动版本不包含在适当的生成知识中,则筛选器变更存在冲突。目标提供程序必须将相应地解决此冲突,并为变更分配新的移动版本。

    4. 如果对于移动版本未检测到冲突,请对照目标项或变更单位的移入标志检查源筛选器变更的移入标志。如果标志的值不一致,目标提供程序必须对照筛选器评估项或变更单位,并分配正确的移入标志值以及新的移动版本。

    5. 如果未检测到任何类型的冲突,则存储筛选器变更元数据以及该项的元数据。

  4. 当对于跟踪的筛选器或由目标副本(而非源副本)跟踪的筛选器不存在筛选器变更元数据时,将针对目标上的筛选器评估变更。更新要包含的筛选器元数据(无论该项是否在该筛选器中),并且,如果变更导致项移入移出筛选器,则将移动版本更新为变更的版本。如果多个变更单位与一个筛选器关联,且对于其中任何变更单位所做的变更都导致项移入移出筛选器,则创建一个新的本地版本,并将新版本指定为项的移动版本和与此筛选器关联的所有变更单位的变更版本。

筛选副本

筛选副本仅为位于其筛选器中的项和变更单位存储项和变更单位数据,以及存储虚影(虚影是原先位于筛选器中但已移出的项和变更批的元数据)。筛选副本还跟踪其筛选器,并且也可能跟踪其他筛选器。筛选副本可以与源提供程序协商筛选器,在此情况下,源提供程序生成筛选的变更批。如果源提供程序无法生成筛选的变更批,则筛选的提供程序可以自行筛选变更,并只应用位于其筛选器中的变更。

有关实现筛选副本的更多信息,请参见如何筛选副本

枚举移入筛选器的项

筛选副本实现 IFilteredReplicaNotifyingChangeApplierTarget(对于托管代码)或 IFilteredReplicaNotifyingChangeApplierTarget(对于非托管代码)接口。此接口包含 GetNewMoveInItems(对于托管代码)或 IFilteredReplicaNotifyingChangeApplierTarget::GetNewMoveins(对于非托管代码),Sync Framework 将使用它们来获取在某个时间点后移入筛选器的项。当某个项处于活动状态、该项在筛选器中以及项的移动版本不包含在为该方法指定的知识中时,将向从该方法返回的列表中添加该项。

发送未筛选的变更

当筛选副本为源副本且目标副本未请求筛选变更枚举时,或者在两个副本之间未能成功协商筛选器时,源副本将枚举变更,就像未进行筛选一样。这与发送筛选变更的过程不同,具体体现在以下各个方面:

  • 创建未筛选的变更批。

  • 当创建变更批时传递副本的遗忘知识,而发送筛选变更时不传递筛选器遗忘知识。

应用筛选的变更

如果目标提供程序使用变更应用方来应用变更,则当它将目标版本发送到变更应用方时,它必须指示目标项或变更单位是否为虚影。为此,当项是目标副本中的虚影时,请为 ChangeKind 属性指定 Ghost(对于托管代码),或者将 SYNC_CHANGE_FLAG_GHOST 标志传递给 IDestinationChangeVersionsBuilder::AddItemMetadata(对于非托管代码)。当目标元数据存储区中的项存在元数据、尚未删除项以及目标存储区中的项不存在数据时,项是虚影。

当不筛选源提供程序中的变更时,目标提供程序将针对目标副本的筛选器评估由源提供程序发送的所有变更。目标提供程序将应用传递筛选器的变更,并更新受影响的所有虚影。目标提供程序从变更批的知识中排除任何跳过的变更。

目标提供程序还必须对其 SaveItemChangeSaveChangeWithChangeUnits(对于托管代码)或 ISynchronousNotifyingChangeApplierTarget::SaveChangeISynchronousNotifyingChangeApplierTarget::SaveChangeWithChangeUnits(对于非托管代码)方法进行以下变更。

  • 通过为虚影创建或更新元数据,处理 CreateGhostUpdateGhost(对于托管代码)或 SSA_CREATE_GHOSTSSA_UPDATE_GHOST(对于非托管代码)操作。还必须更新筛选器变更元数据(如果适用)。

  • 通过删除项或变更单位的数据并更新项或变更单位的元数据以反映变更,从而处理 MarkItemAsGhost(对于托管代码)或 SSA_GHOST_ITEM(对于非托管代码)操作。

  • 通过检索项或变更单位的数据,将数据存储在目标副本中,并更新元数据以反映变更,从而处理 UnmarkItemAsGhost(对于托管代码)或 SSA_UNGHOST_ITEM(对于非托管代码)操作。

  • 通过将虚影的元数据标记为已删除,处理 DeleteGhostAndStoreTombstone(对于托管代码)或 SSA_DELETE_GHOST_AND_STORE_TOMBSTONE(对于非托管代码)操作。

清除虚影

为了释放筛选副本上的存储空间,可以删除虚影。删除虚影后,必须通过将虚影的移动版本传递给筛选器遗忘知识的 ForgetTo(对于托管代码)或 IForgottenKnowledge::ForgetToVersion(对于非托管代码)方法,以更新筛选器的筛选器遗忘知识。

协商筛选器

目标提供程序可以指定在变更枚举期间由源提供程序使用的筛选器。源提供程序可以接受或拒绝目标提供程序请求的筛选器。目标提供程序可以继续请求筛选器,直到找到一个源提供程序接受的筛选器。该协商由 Sync Framework 控制。筛选器可以是最适合于提供程序的任何类型。

若要参与筛选器协商,源提供程序必须实现 ISupportFilteredSync(对于托管代码)或 ISupportFilteredSync(对于非托管代码),而目标提供程序必须实现 IRequestFilteredSync(对于托管代码)或 IRequestFilteredSync(对于非托管代码)。

筛选器协商的实现步骤如下:

  1. 在源提供程序开始枚举变更之前,但在调用 BeginSession(对于托管代码)或 IKnowledgeSyncProvider::BeginSession(对于非托管代码)之后,Sync Framework 通过对目标提供程序调用 SpecifyFilter 方法(对于托管代码)或 IRequestFilteredSync::SpecifyFilter(对于非托管代码)开始筛选器协商。

  2. 在处理 SpecifyFilter 的过程中,目标提供程序将筛选器传递给由 Sync Framework 指定的 FilterRequestCallback 委托(对于托管代码)或 IFilterRequestCallback::RequestFilter 方法(对于非托管代码)。当目标提供程序不跟踪所请求的筛选器时,它指定筛选类型 CurrentItemsOnly(对于托管代码)或 FT_CURRENT_ITEMS_ONLY(对于非托管代码)。当目标提供程序跟踪所请求的筛选器时,它指定筛选类型 CurrentItemsAndVersionsForMovedOutItems(对于托管代码)或 FT_CURRENT_ITEMS_AND_VERSIONS_FOR_MOVED_OUT_ITEMS(对于非托管代码)。

  3. 在处理 FilterRequestCallback(对于托管代码)或 RequestFilter(对于非托管代码)的过程中,Sync Framework 调用源提供程序的 TryAddFilter(对于托管代码)或 ISupportFilteredSync::AddFilter(对于非托管代码)方法。如果源提供程序不支持请求的筛选器,则目标提供程序会继续请求筛选器,直到找到一个受支持的筛选器。

  4. 如果目标提供程序找不到源提供程序接受的筛选器,它将通过引发 SyncInvalidOperationException(对于托管代码)或通过返回诸如 SYNC_E_FILTER_NOT_SUPPORTED 的错误代码(对于非托管代码)终止同步。

成功协商筛选器后,源提供程序使用该筛选器来确定在变更枚举的过程中要包含哪些项。

有关如何协商筛选器的更多信息,请参见如何协商筛选器

请参阅

概念

实现标准自定义提供程序
实现同步应用程序
如何筛选枚举项
如何筛选枚举的变更单位
如何协商筛选器
如何跟踪筛选器和枚举筛选的变更
如何筛选副本