LCOV - code coverage report
Current view: top level - src/libs/tools/src/merging - threewaymerge.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 57 62 91.9 %
Date: 2019-09-12 12:28:41 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Implementation of ThreeWayMerge
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : 
      10             : #include <helper/comparison.hpp>
      11             : #include <helper/keyhelper.hpp>
      12             : #include <merging/threewaymerge.hpp>
      13             : 
      14             : using namespace std;
      15             : using namespace kdb::tools::helper;
      16             : 
      17             : namespace kdb
      18             : {
      19             : 
      20             : namespace tools
      21             : {
      22             : 
      23             : namespace merging
      24             : {
      25             : 
      26         336 : inline void addAsymmetricConflict (MergeResult & result, Key & key, ConflictOperation our, ConflictOperation their, bool reverse)
      27             : {
      28         336 :         if (!reverse)
      29             :         {
      30          63 :                 result.addConflict (key, our, their);
      31             :         }
      32             :         else
      33             :         {
      34         273 :                 result.addConflict (key, their, our);
      35             :         }
      36         336 : }
      37             : 
      38         868 : void ThreeWayMerge::detectConflicts (const MergeTask & task, MergeResult & mergeResult, bool reverseConflictMeta = false)
      39             : {
      40        1736 :         Key our;
      41        1736 :         cursor_t savedCursor = task.ours.getCursor ();
      42         868 :         task.ours.rewind ();
      43             : 
      44        9776 :         while ((our = task.ours.next ()))
      45             :         {
      46        1812 :                 string theirLookup = rebasePath (our, task.ourParent, task.theirParent);
      47        2718 :                 Key theirLookupResult = task.theirs.lookup (theirLookup);
      48             : 
      49             :                 // we have to copy it to obtain owner etc...
      50        1812 :                 Key mergeKey = rebaseKey (our, task.ourParent, task.mergeRoot);
      51             : 
      52         906 :                 if (keyDataEqual (our, theirLookupResult))
      53             :                 {
      54             :                         // keydata matches, see if metakeys match
      55         510 :                         if (keyMetaEqual (our, theirLookupResult))
      56             :                         {
      57        1518 :                                 if (task.ourParent.getFullName () == task.mergeRoot.getFullName ())
      58             :                                 {
      59             :                                         // the key was not rebased, we can reuse our (prevents that the key is rewritten)
      60         332 :                                         mergeResult.addMergeKey (our);
      61             :                                 }
      62             :                                 else
      63             :                                 {
      64             :                                         // the key causes no merge conflict, but the merge result is below a new parent
      65         174 :                                         mergeResult.addMergeKey (mergeKey);
      66             :                                 }
      67             :                         }
      68             :                         else
      69             :                         {
      70             :                                 // metakeys are different
      71           4 :                                 mergeResult.addConflict (mergeKey, CONFLICT_META, CONFLICT_META);
      72             :                         }
      73             :                 }
      74             :                 else
      75             :                 {
      76         792 :                         string baseLookup = rebasePath (our, task.ourParent, task.baseParent);
      77        1188 :                         Key baseLookupResult = task.base.lookup (baseLookup);
      78             : 
      79             :                         // check if the keys was newly added in ours
      80         396 :                         if (baseLookupResult)
      81             :                         {
      82             :                                 // the key exists in base, check if the key still exists in theirs
      83         165 :                                 if (theirLookupResult)
      84             :                                 {
      85             :                                         // check if only they modified it
      86         104 :                                         if (!keyDataEqual (our, baseLookupResult) && keyDataEqual (theirLookupResult, baseLookupResult))
      87             :                                         {
      88             :                                                 // the key was only modified in ours
      89          48 :                                                 addAsymmetricConflict (mergeResult, mergeKey, CONFLICT_MODIFY, CONFLICT_SAME,
      90          48 :                                                                        reverseConflictMeta);
      91             :                                         }
      92             :                                         else
      93             :                                         {
      94             :                                                 // check if both modified it
      95          64 :                                                 if (!keyDataEqual (our, baseLookupResult) &&
      96           8 :                                                     !keyDataEqual (theirLookupResult, baseLookupResult))
      97             :                                                 {
      98             :                                                         // the key was modified on both sides
      99           8 :                                                         mergeResult.addConflict (mergeKey, CONFLICT_MODIFY, CONFLICT_MODIFY);
     100             :                                                 }
     101             :                                         }
     102             :                                 }
     103             :                                 else
     104             :                                 {
     105             :                                         // the key does not exist in theirs anymore, check if ours has modified it
     106          61 :                                         if (keyDataEqual (our, baseLookupResult))
     107             :                                         {
     108             :                                                 // the key was deleted in theirs, and not modified in ours
     109          57 :                                                 addAsymmetricConflict (mergeResult, mergeKey, CONFLICT_SAME, CONFLICT_DELETE,
     110          57 :                                                                        reverseConflictMeta);
     111             :                                         }
     112             :                                         else
     113             :                                         {
     114             :                                                 // the key was deleted in theirs, but modified in ours
     115           4 :                                                 addAsymmetricConflict (mergeResult, mergeKey, CONFLICT_MODIFY, CONFLICT_DELETE,
     116           4 :                                                                        reverseConflictMeta);
     117             :                                         }
     118             :                                 }
     119             :                         }
     120             :                         else
     121             :                         {
     122             :                                 // the key does not exist in base, check if the key was added in theirs
     123         231 :                                 if (theirLookupResult)
     124             :                                 {
     125             :                                         // check if the key was added with the same value in theirs
     126           4 :                                         if (keyDataEqual (mergeKey, theirLookupResult))
     127             :                                         {
     128           0 :                                                 if (keyMetaEqual (our, theirLookupResult))
     129             :                                                 {
     130             :                                                         // the key was added on both sides with the same value
     131           0 :                                                         if (task.ourParent.getFullName () == task.mergeRoot.getFullName ())
     132             :                                                         {
     133             :                                                                 // the key was not rebased, we can reuse our and prevent the sync flag being
     134             :                                                                 // set
     135           0 :                                                                 mergeResult.addMergeKey (our);
     136             :                                                         }
     137             :                                                         else
     138             :                                                         {
     139             :                                                                 // the key causes no merge conflict, but the merge result is below a new
     140             :                                                                 // parent
     141           0 :                                                                 mergeResult.addMergeKey (mergeKey);
     142             :                                                         }
     143             :                                                 }
     144             :                                                 else
     145             :                                                 {
     146             :                                                         // metakeys are different
     147           0 :                                                         mergeResult.addConflict (mergeKey, CONFLICT_META, CONFLICT_META);
     148             :                                                 }
     149             :                                         }
     150             :                                         else
     151             :                                         {
     152             :                                                 // the key was added on both sides with different values
     153           4 :                                                 mergeResult.addConflict (mergeKey, CONFLICT_ADD, CONFLICT_ADD);
     154             :                                         }
     155             :                                 }
     156             :                                 else
     157             :                                 {
     158             :                                         // the key was only added to ours
     159         227 :                                         addAsymmetricConflict (mergeResult, mergeKey, CONFLICT_ADD, CONFLICT_SAME, reverseConflictMeta);
     160             :                                 }
     161             :                         }
     162             :                 }
     163             :         }
     164             : 
     165        1736 :         task.ours.setCursor (savedCursor);
     166         868 : }
     167             : 
     168             : 
     169         434 : MergeResult ThreeWayMerge::mergeKeySet (const MergeTask & task)
     170             : {
     171             : 
     172         434 :         MergeResult result;
     173         434 :         detectConflicts (task, result);
     174         434 :         detectConflicts (task.reverse (), result, true);
     175             : 
     176         434 :         if (!result.hasConflicts ()) return result;
     177             : 
     178             : 
     179             :         // TODO: test this behaviour (would probably need mocks)
     180         106 :         Key current;
     181         212 :         KeySet conflicts = result.getConflictSet ();
     182             :         conflicts.rewind ();
     183        1800 :         while ((current = conflicts.next ()))
     184             :         {
     185        1704 :                 for (auto & elem : strategies)
     186             :                 {
     187         658 :                         (elem)->resolveConflict (task, current, result);
     188             : 
     189         658 :                         if (!result.isConflict (current)) break;
     190             :                 }
     191             :         }
     192             : 
     193             :         return result;
     194             : }
     195             : 
     196          18 : MergeResult ThreeWayMerge::mergeKeySet (const KeySet & base, const KeySet & ours, const KeySet & theirs, const Key & mergeRoot)
     197             : {
     198          90 :         Key ourkey = ours.head ().dup ();
     199          90 :         Key theirkey = theirs.head ().dup ();
     200          90 :         Key basekey = base.head ().dup ();
     201             : 
     202             :         MergeResult merged = mergeKeySet (
     203         108 :                 MergeTask (BaseMergeKeys (base, basekey), OurMergeKeys (ours, ourkey), TheirMergeKeys (theirs, theirkey), mergeRoot));
     204             : 
     205          18 :         return merged;
     206             : }
     207             : } // namespace merging
     208             : } // namespace tools
     209             : } // namespace kdb

Generated by: LCOV version 1.13