void OneSideStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result)
{
	string lookupPath;
	Key winningKey;

	switch (winningSide)
	{
	case BASE:
		lookupPath = rebasePath (conflictKey, task.mergeRoot, task.baseParent);
		winningKey = task.base.lookup(lookupPath);
		break;
	case OURS:
		lookupPath = rebasePath (conflictKey, task.mergeRoot, task.ourParent);
		winningKey = task.ours.lookup(lookupPath);
		break;
	case THEIRS:
		lookupPath = rebasePath (conflictKey, task.mergeRoot, task.theirParent);
		winningKey = task.theirs.lookup(lookupPath);
		break;
	}

	if (winningKey)
	{
		conflictKey.setString(winningKey.getString());
		result.resolveConflict(conflictKey);
		result.addMergeKey(conflictKey);
	} else
	{
		result.resolveConflict(conflictKey);
		result.removeMergeKey(conflictKey);
	}
}
void NewKeyStrategy::resolveConflict (const MergeTask & task, Key & conflictKey, MergeResult & result)
{

	ConflictOperation ourOperation = getOurConflictOperation (conflictKey);
	ConflictOperation theirOperation = getTheirConflictOperation (conflictKey);

	string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent);
	string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent);

	// TODO: this is a subset of the automergestrategy
	// the automergestrategy could be split up into several smaller strategies
	switch (ourOperation)
	{
	case CONFLICT_SAME:
		if (theirOperation == CONFLICT_ADD)
		{
			Key source = task.theirs.lookup (theirLookup);
			copyKeyValue (source, conflictKey);
			result.resolveConflict (conflictKey);
			result.addMergeKey (conflictKey);
		}
		break;
	case CONFLICT_ADD:
		if (theirOperation == CONFLICT_SAME)
		{
			Key source = task.ours.lookup (ourLookup);
			copyKeyValue (source, conflictKey);
			result.resolveConflict (conflictKey);
			result.addMergeKey (conflictKey);
		}
		break;
	default:
		break;
	}
}
Beispiel #3
0
void MetaMergeStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result)
{
	conflictKey.rewindMeta();
	Key currentMeta;

	string baseLookup = rebasePath (conflictKey, task.mergeRoot, task.baseParent);
	string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent);
	string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent);

	Key baseKey = task.base.lookup(baseLookup);
	Key ourKey = task.ours.lookup(ourLookup);
	Key theirKey = task.theirs.lookup(theirLookup);

	Key root ("user/", KEY_END);
	KeySet baseMeta = getMetaKeys (baseKey);
	KeySet ourMeta = getMetaKeys (ourKey);
	KeySet theirMeta = getMetaKeys (theirKey);

	MergeTask metaTask(BaseMergeKeys (baseMeta, root), OurMergeKeys (ourMeta, root),
			TheirMergeKeys (theirMeta, root), root);

	MergeResult metaResult = innerMerger.mergeKeySet(metaTask);

	KeySet mergedMeta = metaResult.getMergedKeys();
	Key current;
	mergedMeta.rewind();
	while ((current = mergedMeta.next()))
	{
		string metaName = current.getName().substr(string("user/").length());
		conflictKey.setMeta(metaName, current.getString());
	}

	ConflictOperation ourOperation = getOurConflictOperation(conflictKey);
	ConflictOperation theirOperation = getTheirConflictOperation(conflictKey);

	if (!metaResult.hasConflicts ())
	{
		if (ourOperation == CONFLICT_META && theirOperation == CONFLICT_META)
		{
			// TODO: addConflict deletes the key content
			// without this strategy restoring the value the value would be lost
			// this happens only for CONFLICT_META <--> CONFLICT_META conflicts
			// add a test for this behaviour
			copyKeyValue(ourKey, conflictKey);
			result.resolveConflict (conflictKey);
			result.addMergeKey (conflictKey);
		}
	}

}
Beispiel #4
0
Key rebaseKey(const Key& key, const Key& oldParent,
		const Key& newParent)
{
	string newPath = rebasePath (key, oldParent, newParent);
	Key result = key.dup ();
	result.setName (newPath);
	return result;
}
void AutoMergeStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result)
{

	ConflictOperation ourOperation = getOurConflictOperation(conflictKey);
	ConflictOperation theirOperation = getTheirConflictOperation(conflictKey);

	string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent);
	string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent);

	switch (ourOperation)
	{
	case SAME:
		if (theirOperation == MODIFY || theirOperation == ADD)
		{
			Key source = task.theirs.lookup(theirLookup);
			conflictKey.setString(source.getString());
			result.resolveConflict(conflictKey);
			result.addMergeKey(conflictKey);
		}

		if (theirOperation == DELETE)
		{
			result.resolveConflict(conflictKey);
		}
		break;
	case MODIFY:
	case ADD:
		if (theirOperation == SAME)
		{
			Key source = task.ours.lookup(ourLookup);
			conflictKey.setString(source.getString());
			result.resolveConflict(conflictKey);
			result.addMergeKey(conflictKey);
		}
		break;
	case DELETE:
		if (theirOperation == SAME)
		{
			result.resolveConflict(conflictKey);
		}
		break;
	case META:
		break;
	}

}
void OneSideValueStrategy::resolveConflict(const MergeTask& task, Key& conflictKey, MergeResult& result)
{
	ConflictOperation ourOperation = getOurConflictOperation (conflictKey);
	ConflictOperation theirOperation = getTheirConflictOperation (conflictKey);

	string ourLookup = rebasePath (conflictKey, task.mergeRoot, task.ourParent);
	string theirLookup = rebasePath (conflictKey, task.mergeRoot, task.theirParent);

	// TODO: this is a subset of the onesidestrategy
	// the onesidestrategy could be split up into several smaller strategies
	if ((ourOperation == CONFLICT_SAME && theirOperation == CONFLICT_MODIFY) || (ourOperation == CONFLICT_MODIFY && theirOperation == CONFLICT_SAME))
	{
		string lookupPath;
		Key winningKey;

		switch (winningSide)
		{
		case BASE:
			lookupPath = rebasePath (conflictKey, task.mergeRoot, task.baseParent);
			winningKey = task.base.lookup (lookupPath);
			break;
		case OURS:
			lookupPath = rebasePath (conflictKey, task.mergeRoot, task.ourParent);
			winningKey = task.ours.lookup (lookupPath);
			break;
		case THEIRS:
			lookupPath = rebasePath (conflictKey, task.mergeRoot, task.theirParent);
			winningKey = task.theirs.lookup (lookupPath);
			break;
		}

		if (winningKey)
		{
			conflictKey.setString (winningKey.getString ());
			result.resolveConflict (conflictKey);
			result.addMergeKey (conflictKey);
		}
	}
}
void ThreeWayMerge::detectConflicts (const MergeTask & task, MergeResult & mergeResult, bool reverseConflictMeta = false)
{
	Key our;
	cursor_t savedCursor = task.ours.getCursor ();
	task.ours.rewind ();

	while ((our = task.ours.next ()))
	{
		string theirLookup = rebasePath (our, task.ourParent, task.theirParent);
		Key theirLookupResult = task.theirs.lookup (theirLookup);

		// we have to copy it to obtain owner etc...
		Key mergeKey = rebaseKey (our, task.ourParent, task.mergeRoot);

		if (keyDataEqual (our, theirLookupResult))
		{
			// keydata matches, see if metakeys match
			if (keyMetaEqual (our, theirLookupResult))
			{
				if (task.ourParent.getFullName () == task.mergeRoot.getFullName ())
				{
					// the key was not rebased, we can reuse our (prevents that the key is rewritten)
					mergeResult.addMergeKey (our);
				}
				else
				{
					// the key causes no merge conflict, but the merge result is below a new parent
					mergeResult.addMergeKey (mergeKey);
				}
			}
			else
			{
				// metakeys are different
				mergeResult.addConflict (mergeKey, CONFLICT_META, CONFLICT_META);
			}
		}
		else
		{
			string baseLookup = rebasePath (our, task.ourParent, task.baseParent);
			Key baseLookupResult = task.base.lookup (baseLookup);

			// check if the keys was newly added in ours
			if (baseLookupResult)
			{
				// the key exists in base, check if the key still exists in theirs
				if (theirLookupResult)
				{
					// check if only they modified it
					if (!keyDataEqual (our, baseLookupResult) && keyDataEqual (theirLookupResult, baseLookupResult))
					{
						// the key was only modified in ours
						addAsymmetricConflict (mergeResult, mergeKey, CONFLICT_MODIFY, CONFLICT_SAME,
								       reverseConflictMeta);
					}
					else
					{
						// check if both modified it
						if (!keyDataEqual (our, baseLookupResult) &&
						    !keyDataEqual (theirLookupResult, baseLookupResult))
						{
							// the key was modified on both sides
							mergeResult.addConflict (mergeKey, CONFLICT_MODIFY, CONFLICT_MODIFY);
						}
					}
				}
				else
				{
					// the key does not exist in theirs anymore, check if ours has modified it
					if (keyDataEqual (our, baseLookupResult))
					{
						// the key was deleted in theirs, and not modified in ours
						addAsymmetricConflict (mergeResult, mergeKey, CONFLICT_SAME, CONFLICT_DELETE,
								       reverseConflictMeta);
					}
					else
					{
						// the key was deleted in theirs, but modified in ours
						addAsymmetricConflict (mergeResult, mergeKey, CONFLICT_MODIFY, CONFLICT_DELETE,
								       reverseConflictMeta);
					}
				}
			}
			else
			{
				// the key does not exist in base, check if the key was added in theirs
				if (theirLookupResult)
				{
					// check if the key was added with the same value in theirs
					if (keyDataEqual (mergeKey, theirLookupResult))
					{
						if (keyMetaEqual (our, theirLookupResult))
						{
							// the key was added on both sides with the same value
							if (task.ourParent.getFullName () == task.mergeRoot.getFullName ())
							{
								// the key was not rebased, we can reuse our and prevent the sync flag being
								// set
								mergeResult.addMergeKey (our);
							}
							else
							{
								// the key causes no merge conflict, but the merge result is below a new
								// parent
								mergeResult.addMergeKey (mergeKey);
							}
						}
						else
						{
							// metakeys are different
							mergeResult.addConflict (mergeKey, CONFLICT_META, CONFLICT_META);
						}
					}
					else
					{
						// the key was added on both sides with different values
						mergeResult.addConflict (mergeKey, CONFLICT_ADD, CONFLICT_ADD);
					}
				}
				else
				{
					// the key was only added to ours
					addAsymmetricConflict (mergeResult, mergeKey, CONFLICT_ADD, CONFLICT_SAME, reverseConflictMeta);
				}
			}
		}
	}

	task.ours.setCursor (savedCursor);
}
Beispiel #8
0
void ThreeWayMerge::detectConflicts(const MergeTask& task, MergeResult& mergeResult, bool reverseConflictMeta = false)
{
	Key our;
	cursor_t savedCursor = task.ours.getCursor ();
	task.ours.rewind ();

	while ((our = task.ours.next ()))
	{
		if (our.getName() == task.ourParent.getName())
			continue;

		string theirLookup = rebasePath (our, task.ourParent, task.theirParent);
		Key theirLookupResult = task.theirs.lookup (theirLookup);

		// we have to copy it to obtain owner etc...
		Key mergeKey = rebaseKey (our, task.ourParent, task.mergeRoot);

		if (keyDataEqual (our, theirLookupResult))
		{
			// keydata matches, see if metakeys match
			if (keyMetaEqual (our, theirLookupResult))
			{
				mergeResult.addMergeKey (mergeKey);
			}
			else
			{
				// metakeys are different
				mergeResult.addConflict (mergeKey, META, META);
			}
		}
		else
		{
			string baseLookup = rebasePath (our, task.ourParent, task.baseParent);
			Key baseLookupResult = task.base.lookup (baseLookup);

			// check if the keys was newly added in ours
			if (baseLookupResult)
			{
				// the key exists in base, check if the key still exists in theirs
				if (theirLookupResult)
				{
					// check if only they modified it
					if (!keyDataEqual (our, baseLookupResult) && keyDataEqual (theirLookupResult, baseLookupResult))
					{
						// the key was only modified in ours
						addAsymmetricConflict (mergeResult, mergeKey, MODIFY, SAME, reverseConflictMeta);
					}
					else
					{
						// check if both modified it
						if (!keyDataEqual (our, baseLookupResult) && !keyDataEqual (theirLookupResult, baseLookupResult))
						{
							// the key was modified on both sides
							mergeResult.addConflict (mergeKey, MODIFY, MODIFY);
						}
					}
				}
				else
				{
					// the key does not exist in theirs anymore, check if ours has modified it
					if (keyDataEqual (our, baseLookupResult))
					{
						// the key was deleted in theirs, and not modified in ours
						addAsymmetricConflict (mergeResult, mergeKey, SAME, DELETE, reverseConflictMeta);
					}
					else
					{
						// the key was deleted in theirs, but modified in ours
						addAsymmetricConflict (mergeResult, mergeKey, MODIFY, DELETE, reverseConflictMeta);
					}
				}
			}
			else
			{
				// the key does not exist in base, check if the key was added in theirs
				if (theirLookupResult)
				{
					// check if the key was added with the same value in theirs
					if (keyDataEqual (mergeKey, theirLookupResult))
					{
						if (keyMetaEqual (our, theirLookupResult))
						{
							// the key was added on both sides with the same value
							mergeResult.addMergeKey (mergeKey);
						}
						else
						{
							// metakeys are different
							mergeResult.addConflict (mergeKey, META, META);
						}
					}
					else
					{
						// the key was added on both sides with different values
						mergeResult.addConflict (mergeKey, ADD, ADD);
					}
				}
				else
				{
					// the key was only added to ours
					addAsymmetricConflict (mergeResult, mergeKey, ADD, SAME, reverseConflictMeta);
				}
			}
		}
	}

	task.ours.setCursor (savedCursor);
}
void InteractiveMergeStrategy::resolveConflict (const MergeTask & task, Key & conflictKey, MergeResult & result)
{
	ConflictOperation ours = getOurConflictOperation (conflictKey);
	ConflictOperation theirs = getTheirConflictOperation (conflictKey);

	outputStream << "merging key " << conflictKey.getName () << endl;
	outputStream << endl;
	outputStream << "======== CONFLICT ========" << endl;
	outputStream << "our operation: " << MergeConflictOperation::getFromTag (ours) << endl;
	outputStream << "their operation: " << MergeConflictOperation::getFromTag (theirs) << endl;
	outputStream << endl;

	Key baseKey = task.base.lookup (rebasePath (conflictKey, task.mergeRoot, task.baseParent));
	Key ourKey = task.ours.lookup (rebasePath (conflictKey, task.mergeRoot, task.ourParent));
	Key theirKey = task.theirs.lookup (rebasePath (conflictKey, task.mergeRoot, task.theirParent));

	outputStream << "======== KEY VALUES ========" << endl;
	outputKeyInfo ("base", baseKey, outputStream);
	outputKeyInfo ("ours", ourKey, outputStream);
	outputKeyInfo ("theirs", theirKey, outputStream);

	outputStream << endl;

	char choice;

	ConflictResolutionSide side;

	bool repeat;
	string input;
	do
	{
		outputStream << "What do you want to do?" << endl;
		outputStream << "Take [o]urs, [t]eirs, [b]ase, [m]erge meta: ";

		repeat = false;
		getline (inputStream, input);

		if (input.size () == 0 || input.size () > 1)
		{
			repeat = true;
			continue;
		}

		choice = input.at (0);

		switch (choice)
		{
		case 'o':
			side = OURS;
			outputStream << "Choose our key" << endl;
			break;
		case 't':
			side = THEIRS;
			outputStream << "Choose their key" << endl;
			break;
		case 'b':
			side = BASE;
			outputStream << "Choose base key" << endl;
			break;
		default:
			repeat = true;
		}
	} while (repeat);

	outputStream << endl;

	OneSideStrategy strategy (side);
	strategy.resolveConflict (task, conflictKey, result);
	outputStream << "Key merged..." << endl;
}