LCOV - code coverage report
Current view: top level - src/libs/tools/examples - merging.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 46 0.0 %
Date: 2019-09-12 12:28:41 Functions: 0 1 0.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include <kdb.hpp>
      10             : #include <keysetio.hpp>
      11             : 
      12             : #include <iostream>
      13             : #include <memory>
      14             : #include <string>
      15             : 
      16             : #include <merging/onesidemergeconfiguration.hpp>
      17             : #include <merging/threewaymerge.hpp>
      18             : 
      19             : 
      20             : using namespace kdb;
      21             : using namespace kdb::tools::merging;
      22             : using namespace std;
      23             : 
      24           0 : int main ()
      25             : {
      26           0 :         KeySet ours;
      27           0 :         KeySet theirs;
      28           0 :         KeySet base;
      29             : 
      30             :         // the root of the subtree containing our keys (i.e. our side of the merge)
      31           0 :         Key oursRoot ("user/ours", KEY_END);
      32             : 
      33             :         // the root of the subtree containing their keys (i.e. their side of the merge)
      34           0 :         Key theirsRoot ("user/theirs", KEY_END);
      35             : 
      36             :         // the root of the subtree containing the base keys (i.e. the common ancestor of the merge)
      37           0 :         Key baseRoot ("user/base", KEY_END);
      38             : 
      39             :         // the root of the subtree that will contain the merge result
      40           0 :         Key resultRoot ("user/result", KEY_END);
      41             : 
      42             :         // Step 1: retrieve clean KeySets containing only those
      43             :         // keys that should be merged. This is a bit trickier than
      44             :         // it seems at first. Have a look at the documentation of kdbGet
      45             :         // for detailed information
      46             :         // things to note:
      47             :         //   * use blocks with local KDB instances so we don't have to worry about
      48             :         //     writing the keys back
      49             :         //   * remove the root key itself from the result KeySet because it usually
      50             :         //     contains the mounted filename and cannot be merged anyway
      51             :         // Also have a look at the documentation of kdbSet()
      52             :         // (https://doc.libelektra.org/api/latest/html/group__kdb.html#ga11436b058408f83d303ca5e996832bcf).
      53             :         // The merging framework can also be used to resolve conflicts resulting from
      54             :         // concurrent calls to kdbSet() as described in the example of kdbSet().
      55             :         {
      56           0 :                 KDB lkdb;
      57           0 :                 lkdb.get (ours, oursRoot);
      58           0 :                 ours = ours.cut (oursRoot);
      59           0 :                 ours.lookup (oursRoot, KDB_O_POP);
      60           0 :                 lkdb.get (theirs, theirsRoot);
      61           0 :                 theirs = theirs.cut (theirsRoot);
      62           0 :                 theirs.lookup (theirsRoot, KDB_O_POP);
      63           0 :                 lkdb.get (base, baseRoot);
      64           0 :                 base = base.cut (baseRoot);
      65           0 :                 base.lookup (baseRoot, KDB_O_POP);
      66             :         }
      67             : 
      68             : 
      69             :         // Step 2: Make sure that no keys reside below the intended merge result root
      70             :         // Usually the merge can be either aborted if this is the case or the existing
      71             :         // keys can be overwritten.
      72           0 :         KeySet resultKeys;
      73           0 :         kdb::KDB kdb;
      74           0 :         kdb.get (resultKeys, resultRoot);
      75             : 
      76           0 :         KeySet discard = resultKeys.cut (resultRoot);
      77           0 :         if (discard.size () != 0)
      78             :         {
      79             :                 // handle existing keys below the result root
      80             :                 return -1;
      81             :         }
      82             : 
      83           0 :         ThreeWayMerge merger;
      84             : 
      85             :         // Step 3: Decide which resolution strategies to use. The strategies are registered
      86             :         // with the merge and applied in order as soon as a conflict is detected. If a strategy
      87             :         // marks a conflict as resolved, no further strategies are consulted. Therefore the order
      88             :         // in which they are registered is absolutely crucial. With this chaining the strategies
      89             :         // remain simple, but can be combined to powerful resolution strategies.
      90             :         // Have a look at the strategy documentation for further details on what they do and how they work.
      91             :         // The unit tests also provide insight into how the strategies work.
      92             : 
      93             :         // In order to simplify the initialization, predefined merge configurations exist.
      94             :         // in this example we first resolve all the keys that can be automatically
      95             :         // resolved (e.g. only one side was modified). This is exactly the use case of the
      96             :         // AutoMergeConfiguration.
      97             : 
      98           0 :         AutoMergeConfiguration configuration;
      99           0 :         configuration.configureMerger (merger);
     100             : 
     101             :         // Step 4: Perform the actual merge
     102             :         MergeResult result = merger.mergeKeySet (
     103           0 :                 MergeTask (BaseMergeKeys (base, baseRoot), OurMergeKeys (ours, oursRoot), TheirMergeKeys (theirs, theirsRoot), resultRoot));
     104             : 
     105             :         // Step 5: work with the result. The merger will return an object containing information
     106             :         // about the merge result.
     107           0 :         if (!result.hasConflicts ())
     108             :         {
     109             :                 // output some statistical information
     110           0 :                 cout << result.getMergedKeys ().size () << " keys in the result" << endl;
     111           0 :                 cout << result.getNumberOfEqualKeys () << " keys were equal" << endl;
     112           0 :                 cout << result.getNumberOfResolvedKeys () << " keys were resolved" << endl;
     113             : 
     114             :                 // write the result
     115           0 :                 resultKeys.append (result.getMergedKeys ());
     116           0 :                 kdb.set (resultKeys, resultRoot);
     117             : 
     118             :                 return 0;
     119             :         }
     120             :         else
     121             :         {
     122           0 :                 KeySet conflicts = result.getConflictSet ();
     123             : 
     124           0 :                 cerr << conflicts.size () << " conflicts were detected that could not be resolved automatically:" << endl;
     125           0 :                 conflicts.rewind ();
     126           0 :                 Key current;
     127           0 :                 while ((current = conflicts.next ()))
     128             :                 {
     129             :                         // For each unresolved conflict there is a conflict key in the merge result.
     130             :                         // This conflict key contains meta information about the reason of the conflict.
     131             :                         // In particular the metakeys conflict/operation/our and conflict/operation/their contain
     132             :                         // the operations done on our version of the key and their version of the key relative to
     133             :                         // the base version of the key.
     134           0 :                         string ourConflict = current.getMeta<string> ("conflict/operation/our");
     135           0 :                         string theirConflict = current.getMeta<string> ("conflict/operation/their");
     136             : 
     137           0 :                         cerr << current << endl;
     138           0 :                         cerr << "ours: " << ourConflict << ", theirs: " << theirConflict << endl;
     139           0 :                         cerr << endl;
     140             :                 }
     141             : 
     142           0 :                 cerr << "Merge unsuccessful." << endl;
     143             : 
     144           0 :                 return -1;
     145             :         }
     146           0 : }

Generated by: LCOV version 1.13