locked
MSF 2.0 CTP2 throws exception on RecordConstraintConflictForItem with ConstraintConflictReason.Identity (argument out of range) RRS feed

  • Question

  • I'm using a file system provider as a source and a custom provider as a destination. Where there are ID conflicts, I want to resolve the ID conflicts so that all participating providers correctly identity an item. The two test scenarios I'm working with are:

    1. A file is created, synced, deleted, synced and recreated. The two providers now have a different ID for the item.
    2. A file is synced between two providers and a third provider wants to sync the same file which already exists on its repository.

    This ID conflict scenario is described at http://msdn.microsoft.com/en-us/library/dd937738(SQL.105).aspx#MergingConflictingItems. This is difficult to follow and some code examples or pseudocode would be nice.

    When I attempt to notify that an Identity constraint conflict has occured, CTP2 throws an exception.

    Example code is as follows:

            public void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context)
            {
                if (context.ChangeData != null)
                {
                    DataItemId contextItemId = GetDataItemIdFromContext(context);
                    SyncId metadataId = MetadataManager.GetSyncId(contextItemId);
    
                    if (metadataId != null)
                    {
                        if (metadataId.Equals(change.ItemId) == false)
                        {
                            // This item is know by the MetadataManager as a different id
                            context.RecordConstraintConflictForItem(metadataId, ConstraintConflictReason.Identity);
                            
                            return;
                        }
                    }
                }
    
                switch (saveChangeAction)
                {
                    case SaveChangeAction.Create:
                        {
                            ProcessCreateItem(context, change);
    
                            break;
                        }
    
                    case SaveChangeAction.UpdateVersionOnly:
                        {
                            // Create the store item from the data
                            DataItemMetadata itemMetadata = GetMetadataFromContext(context);
    
                            MetadataManager.SaveItemMetadata(itemMetadata, change.ItemId, change.ChangeVersion);
    
                            break;
                        }
    
                    case SaveChangeAction.UpdateVersionAndData:
                        {
                            ProcessUpdateItem(change, context);
    
                            break;
                        }
    
                    case SaveChangeAction.DeleteAndStoreTombstone:
                        {
                            // Delete the item from the item store and store a tombstone for it in the metadata store.
                            ProcessDeleteItem(change, context);
    
                            break;
                        }
    
                    case SaveChangeAction.UpdateVersionAndMergeData:
                    case SaveChangeAction.DeleteAndRemoveTombstone:
                        {
                            // Neither merging of data nor removing tombstones is supported.
                            throw new NotImplementedException();
                        }
    
                    default:
                        {
                            throw new ArgumentOutOfRangeException();
                        }
                }
    
                // Save the knowledge in the metadata store as each change is applied. 
                // Saving knowledge as each change is applied is not required. 
                // It is more robust than saving the knowledge only after each change batch, 
                // because if synchronization is interrupted before the end of a change batch, 
                // the knowledge will still reflect all of the changes applied. 
                // However, it is less efficient because knowledge must be stored more frequently.
                SyncKnowledge knowledge;
                ForgottenKnowledge forgottenKnowledge;
    
                context.GetUpdatedDestinationKnowledge(out knowledge, out forgottenKnowledge);
    
                StoreKnowledgeForScope(knowledge, forgottenKnowledge);
            }
    The call to context.RecordConstraintConflictForItem(metadataId, ConstraintConflictReason.Identity); throws the exception.

    The test results are as follows:

    StoreSyncProviderTests.SyncCreatesItemAgainAfterDeleteExchangerTest : Failed

    Test method Neovolve.Jabiru.Client.Synchronization.IntegrationTests.StoreSyncProviderTests.SyncCreatesItemAgainAfterDeleteExchangerTest threw exception:  System.ArgumentException: Value does not fall within the expected range..
    at Microsoft.Synchronization.CoreInterop.ISaveChangeContext2.SetConstraintConflictOnChange(Byte[] pbConflictingItemIdUInt32 dwReason)
    at Microsoft.Synchronization.SaveChangeContext.ISaveChangeContextImpl.SetConstraintConflictOnChange(Byte[] conflictingItemIdUInt32 dwReason)
    at Microsoft.Synchronization.SaveChangeContext.RecordConstraintConflictForItem(SyncId conflictingItemIdConstraintConflictReason reason)
    at Neovolve.Jabiru.Client.Synchronization.StoreChangeApplier.SaveItemChange(SaveChangeAction saveChangeActionItemChange changeSaveChangeContext context) in StoreChangeApplier.cs: line 142
    at Microsoft.Synchronization.NotifyingChangeApplierTargetProxy.SaveChange(SYNC_SAVE_ACTION ssaISyncChange pChangeISaveChangeContext pSaveChangeContext)
    at Microsoft.Synchronization.CoreInterop.ISynchronousNotifyingChangeApplier2.ApplyChanges(CONFLICT_RESOLUTION_POLICY resolutionPolicyCOLLISION_CONFLICT_RESOLUTION_POLICY collisionPolicyISyncChangeBatch pSourceChangesObject pUnkDataRetrieverIEnumSyncChanges pDestinationVersionsISyncKnowledge pDestinationKnowledgeIForgottenKnowledge pDestinationForgottenKnowledgeISynchronousNotifyingChangeApplierTarget pChangeApplierTargetIConflictLogAccess pConflictLogAccessISyncSessionState pSessionStateISyncCallback pCallback)
    at Microsoft.Synchronization.NotifyingChangeApplier.ISynchronousNotifyingChangeApplierImpl.ApplyChanges(CONFLICT_RESOLUTION_POLICY resolutionPolicyCOLLISION_CONFLICT_RESOLUTION_POLICY collisionPolicyISyncChangeBatch pSourceChangesObject pUnkDataRetrieverIEnumSyncChanges pDestinationVersionsISyncKnowledge pDestinationKnowledgeIForgottenKnowledge pDestinationForgottenKnowledgeISynchronousNotifyingChangeApplierTarget pChangeApplierTargetIConflictLogAccess pConflictLogAccessISyncSessionState pSessionStateISyncCallback pCallback)
    at Microsoft.Synchronization.NotifyingChangeApplier.ApplyChanges(ConflictResolutionPolicy resolutionPolicyCollisionConflictResolutionPolicy collisionConflictResolutionPolicyChangeBatch sourceChangesIChangeDataRetriever changeDataRetrieverIEnumerable`1 destinationVersionsSyncKnowledge destinationKnowledgeForgottenKnowledge destinationForgottenKnowledgeINotifyingChangeApplierTarget changeApplierTargetIConflictLogAccess conflictLogAccessSyncSessionContext syncSessionStateSyncCallbacks syncCallback)
    at Microsoft.Synchronization.NotifyingChangeApplier.ApplyChanges(ConflictResolutionPolicy resolutionPolicyChangeBatch sourceChangesIChangeDataRetriever changeDataRetrieverIEnumerable`1 destinationVersionsSyncKnowledge destinationKnowledgeForgottenKnowledge destinationForgottenKnowledgeINotifyingChangeApplierTarget changeApplierTargetSyncSessionContext syncSessionStateSyncCallbacks syncCallback)
    at Neovolve.Jabiru.Client.Synchronization.StoreSyncProvider.ProcessChangeBatch(ConflictResolutionPolicy resolutionPolicyChangeBatch sourceChangesObject changeDataRetrieverSyncCallbacks syncCallbacksSyncSessionStatistics sessionStatistics) in StoreSyncProvider.cs: line 206
    at Microsoft.Synchronization.KnowledgeProviderProxy.ProcessChangeBatch(CONFLICT_RESOLUTION_POLICY resolutionPolicyISyncChangeBatch pSourceChangeManagerObject pUnkDataRetrieverISyncCallback pCallbackref _SYNC_SESSION_STATISTICS pSyncSessionStatistics)
    at Microsoft.Synchronization.CoreInterop.ISyncSession.Start(CONFLICT_RESOLUTION_POLICY resolutionPolicyref _SYNC_SESSION_STATISTICS pSyncSessionStatistics)
    at Microsoft.Synchronization.KnowledgeSyncOrchestrator.DoOneWaySyncHelper(SyncIdFormatGroup sourceIdFormatsSyncIdFormatGroup destinationIdFormatsKnowledgeSyncProviderConfiguration destinationConfigurationSyncCallbacks DestinationCallbacksISyncProvider sourceProxyISyncProvider destinationProxyChangeDataAdapter callbackChangeDataAdapterSyncDataConverter conflictDataConverterref Int32 changesAppliedref Int32 changesFailed)
    at Microsoft.Synchronization.KnowledgeSyncOrchestrator.DoOneWayKnowledgeSync(SyncDataConverter sourceConverterSyncDataConverter destinationConverterSyncProvider sourceProviderSyncProvider destinationProviderref Int32 changesAppliedref Int32 changesFailed)
    at Microsoft.Synchronization.KnowledgeSyncOrchestrator.Synchronize()
    at Microsoft.Synchronization.SyncOrchestrator.Synchronize()
    at Neovolve.Jabiru.Client.Synchronization.IntegrationTests.StoreSyncProviderTests.RunSync(String localPathIDataExchange exchangerIMetadataManager syncManager) in StoreSyncProviderTests.cs: line 421
    at Neovolve.Jabiru.Client.Synchronization.IntegrationTests.StoreSyncProviderTests.SyncCreatesItemAgainAfterDeleteExchangerTest() in StoreSyncProviderTests.cs: line 166

    Is there anything I've missed, or a workaround that can be applied? When is the next version drop?

    Cheers,

    Rory
    • Moved by Max Wang_1983 Thursday, April 21, 2011 12:34 AM forum consolidation (From:SyncFx - Technical Discussion [ReadOnly])
    Sunday, September 27, 2009 5:03 AM

Answers

  • Hi Rory,

    For the situation that you're describing, I think you want to set a constraint conflict with the type "Collision".  The Identity conflict reason is reserved for the sync framework to handle situations where two providers disagree on the what data corresponds to an ID, and only happens when the source has a merge tombstone (one example of an Identity conflict is when the source and destination both have merge tombstones for a given Id, but have different winners).  The Collision reason refers to the scenario you've described, where different IDs refer to the same item.

    Hope this helps,

    Aaron
    SDE, Microsoft Sync Framework
    Monday, September 28, 2009 5:43 PM