locked
Question about Conflicts (Sync V1.0 CTP2 Example) RRS feed

  • Question

  • Hi,

    i looked at the following example from Liam and have a question about conflicts:
    http://code.msdn.microsoft.com/sync/Release/ProjectReleases.aspx?ReleaseId=615

    I simply want to do an Upload between provider A and B, so i set agent.Direction = SyncDirectionOrder.Upload.
    If a conflict occurs i always want the destination to win! So i set e.SetResolutionAction(ConflictResolutionAction.DestinationWins) in the ItemConflicting-Event.

    I perform following steps (like in example):
    1) Insert Items 1,2 in provider A
    2) Insert Items 3,4 in provider B
    3) Synchronize
    4) Update Item 1 in provider A
    5) Update Item 1 in Provider B
    6) Synchronize ==> Conflict! => DestinationWins => OK

    7) I update Item 1 in provider A! I don't update Item 1 in provider B!
    8) Synchronize => Conflict Again!
    I don't understand why there is a conflict again! If i change an item only at the source this is no conflict in my opinion and the Source-Change should be applied!
    Could you please explain?

    Many thanks!
    Stefan.

    If it helps i can post the MetaData as well.




    • Moved by Max Wang_1983 Thursday, April 21, 2011 10:13 PM forum consolidation (From:SyncFx - Technical Discussion [ReadOnly])
    Wednesday, March 19, 2008 3:53 PM

Answers

  • Ok.I am sorry .I may have been unclear.Let me try explaining again.

    I know that you are not changing B after step 6.

    But since your SyncDirectionOrder  is set to upload.

    The change that you made to B in step 5 was not downloaded to A.

    So when you run Sync at step 8 again.Replica A do not know about yur changes that you made to B in step 5.

    This is what causes the conflict.

    As i said if you set the SyncDirectionOrder  to DownloadAndUpload,The conflict will not happen.

     

    Hope this helps.

     

    Thursday, March 20, 2008 4:30 PM

All replies

  • Hi Stefan,

     

    I tried reproducing the same problem as you have mantioned.

     

    But  I was not able to produce it .My update in A was successfully applied in B.

    If possible , can you please post the MyTestProgram.cs code.

    I am guessing that you have not modifed the code in MySyncProvider.

     

    Cheers

    Rituraj

     

    Thursday, March 20, 2008 6:30 AM
  • Hi Rituraj,

    thanks for your answer!
    here is the MyTestProgram.cs. I didn't change the MySimpleSyncProvider.cs

     class MyTestProgram
        {
            /// <summary>
            /// This is an extension of an in-memory provider sample that is used to illustrate the responsibilites of a provider working on behalf
            /// of a store. For instance, what do do with an item create/update/delete, how to get changes, how to apply changes, how to detect conflicts,
            /// and how to resolve them using a custom action such as merge...
            ///
            /// Please note that this sample is most useful with breakpoints in MyTestProgram.cs to find out HOW synchronization using the
            /// Microsoft Sync Framework works. This sample is not designed to be a boot-strapper like the NTFS providers for native and managed...
            /// </summary>
            /// <param name="args"></param>
            static void Main(string[] args)
            {
                //Metadata store location for the 3 providers we'll be using
                string providerOneMetadata = Environment.CurrentDirectory + "\\A.Metadata.sdf";
                string providerTwoMetadata = Environment.CurrentDirectory + "\\B.Metadata.sdf";
               
                //Since we're illustrating API usage, we're just going to blow away the metadata stores each time...
                if (System.IO.File.Exists(providerOneMetadata))
                {
                    System.IO.File.Delete(providerOneMetadata);
                }
                MySyncProvider providerA = new MySyncProvider("A", providerOneMetadata);
               
                if (System.IO.File.Exists(providerTwoMetadata))
                {
                    System.IO.File.Delete(providerTwoMetadata);
                }
                MySyncProvider providerB = new MySyncProvider("B", providerTwoMetadata);
               
                //Set the provider's conflict resolution policy to custom (in order to show how to do complex resolution actions)
                providerA.Configuration.ConflictResolutionPolicy = ConflictResolutionPolicy.ApplicationDefined;
                providerB.Configuration.ConflictResolutionPolicy = ConflictResolutionPolicy.ApplicationDefined;
                //providerC.Configuration.ConflictResolutionPolicy = ConflictResolutionPolicy.ApplicationDefined;

                //Register how we want to handle conflicts in the event that they're detected...
                providerA.DestinationCallbacks.ItemConflicting += new EventHandler<ItemConflictingEventArgs>(DestinationCallbacks_ItemConflicting);
                providerB.DestinationCallbacks.ItemConflicting += new EventHandler<ItemConflictingEventArgs>(DestinationCallbacks_ItemConflicting);
                //providerC.DestinationCallbacks.ItemConflicting += new EventHandler<ItemConflictingEventArgs>(DestinationCallbacks_ItemConflicting);

                //Illustrate how providers can use transactioning to batch updates...
                providerA.BeginUpdates();
                providerB.BeginUpdates();
                //providerC.BeginUpdates();

                //Create items on each store using a global ID and the data of the item (Note, while real providers should use GUIDs to ensure uniqueness,
                //we're simply creating hardcoded items with byte length ids and string data for ease of use...
                providerA.CreateItem(1, "1");
                providerA.CreateItem(2, "2");
                providerB.CreateItem(3, "3");
                providerB.CreateItem(4, "4");
                //providerC.CreateItem(5, "5");
                //providerC.CreateItem(6, "6");

                //Commit the transactions
                providerA.EndUpdates();
                providerB.EndUpdates();
                //providerC.EndUpdates();

                //Show the contents of the stores, prior to ANY any synchronization...
                Console.WriteLine("Show the contents of the stores, prior to any synchronization...");
                Console.WriteLine(providerA.ToString());
                Console.WriteLine(providerB.ToString());
                //Console.WriteLine(providerC.ToString());

                //Sync providers A and provider B
                Console.WriteLine("Sync A and B...");
                SyncOrchestrator agent = new SyncOrchestrator();
                agent.Direction = SyncDirectionOrder.Upload;
                agent.LocalProvider = providerA;
                agent.RemoteProvider = providerB;
                SyncOperationStatistics stats = agent.Synchronize();

                //Show the results of sync
                Console.WriteLine(providerA.ToString());
                Console.WriteLine(providerB.ToString());
               
                //Create an update-update conflict on item 1 and show merge... (Note - this sample handles update-update conflicts and simply merges the data)
                Console.WriteLine("A and B are going to create a conflict on item 4. A write 'Did Merging' and B writes 'Work?'");
               
                //Transaction these changes:
                providerA.BeginUpdates();
                providerB.BeginUpdates();
               
                //Create an update-update conflict to merge...
                providerA.UpdateOrDeleteItem(1, "Did Merging4", false);
                providerB.UpdateOrDeleteItem(1, " Work?", false);

                //Commit the changes...
                providerA.EndUpdates();
                providerB.EndUpdates();

                Console.WriteLine("\nSync A and B");
                agent.Direction = SyncDirectionOrder.Upload;
                agent.LocalProvider = providerA;
                agent.RemoteProvider = providerB;
                stats = agent.Synchronize();
              
                Console.ReadLine();
            }

            static void DestinationCallbacks_ItemConflicting(object sender, ItemConflictingEventArgs e)
            {
                e.SetResolutionAction(ConflictResolutionAction.DestinationWins);
            }
        }
    Thursday, March 20, 2008 8:03 AM
  • The answer to your question “ Why conflict “ is as follows

    The sample code you have send follows the following steps [Note I have changed the steps based on the code you have posted]
    1) Insert Items 1,2 in provider A
    2) Insert Items 3,4 in provider B
    3) Synchronize
    4) Update Item 1 in provider A
    5) Update Item 1 in Provider B
    6) Synchronize ==> Conflict! => DestinationWins => OK
    7) I update Item 1 in provider A! I don't update Item 1 in provider B!
    8) Synchronize => Conflict Again!

    The conflict is bound to happen at this stage because both source and destination values were changed prior to sync. 

    I also modified the code posted by you to implement step 7 and 8 .Here also you would get a conflict, because data in both replica A and B were changed  prior to sync.

    Your following statement is correct

    “IF I change an item only at the source this is no conflict in my opinion and the Source-Change should be applied” 

    But the situation you posted is different. Since you have set the SyncDirectionOrder to upload, at the step 6 source replica A is not updated with the knowledge and data of the destination replica B. 

    Now at step 8 when you do a sync , source replica A and destination replica B ,both were modified prior to sync.[A was modified in step 7 and B was modified in step 5].

    You would not get a conflict if you set the SyncDirectionOrder to DownloadandUpload in the prevous syncs [step 3and step 6] 

    I also found out another bug with the example

     

    There is a bug in the Sync V1.0 CTP2 Example 

     http://code.msdn.microsoft.com/sync/Release/ProjectReleases.aspx?ReleaseId=615 

    It tries to update the data even inside the  case loop of SaveChangeAction.UpdateVersionOnly.

     

    Ofcourse the sample was not supposed to demonstarte this case as the ConflictResolutionAction was set to merge in the ItemConflicting event.

     

    The fix is very straight forward.

    Write a new case for the UpdateVersionOnly.

     

    case SaveChangeAction.UpdateVersionAndData:

                        {

                            item = _metadata.FindItemMetadataById(change.ItemId);

                            if (null == item)

                            {

                                throw new Exception("Item Not Found in Store!?");

                            }

     

                            item.ChangeVersion = change.ChangeVersion;

                            _store[item.GlobalId.GetByteId()] = (string)context.ChangeData;

                            _metadata.SaveItemMetadata(item);

                        }

                        break;

                    case SaveChangeAction.UpdateVersionOnly:

                        {

                            item = _metadata.FindItemMetadataById(change.ItemId);

                            if (null == item)

                            {

                                throw new Exception("Item Not Found in Store!?");

                            }

     

                            item.ChangeVersion = change.ChangeVersion;

                            //BUG FIXED :

                            //There is no need for this statement as if the SaveChangeAction is set to UpdateVersionOnly then why do we need to update the data as well

                            //Also the context.ChangeData will always be null in this case.

     

                           // _store[item.GlobalId.GetByteId()] = (string)context.ChangeData;

                            _metadata.SaveItemMetadata(item);

                        }

                        break;

    Thursday, March 20, 2008 11:58 AM
  • Hi Rituraj,

    thanks for your answer!
    But i only made an update to provider A in Step 7! I skipp the update for B (providerB.UpdateOrDeleteItem(1, " Work?", false)Wink while debugging ;-) and i don't delete the Metadata when running the sample the second time.
    So the first run is step 1 to 6. After that i start the sample again and continue with an Update (Step7) to provider A. 
    If i call synchronize i get a conflict...why? Sorry if i don't understand you.

    Stefan



    Thursday, March 20, 2008 1:19 PM
  • Ok.I am sorry .I may have been unclear.Let me try explaining again.

    I know that you are not changing B after step 6.

    But since your SyncDirectionOrder  is set to upload.

    The change that you made to B in step 5 was not downloaded to A.

    So when you run Sync at step 8 again.Replica A do not know about yur changes that you made to B in step 5.

    This is what causes the conflict.

    As i said if you set the SyncDirectionOrder  to DownloadAndUpload,The conflict will not happen.

     

    Hope this helps.

     

    Thursday, March 20, 2008 4:30 PM