public void Test2() { // Test case 2 - merge with conflicting edits var rootNode1 = new Node("docId","data",0); rootNode1.addVersion("data1",1); rootNode1.addVersion("data2",2); //Console.WriteLine(rootNode1.toString()); var rootNode2 = new Node("docId2", "data",3); rootNode2.addVersion("data1",4); rootNode2.addVersion("rootnode2-data2",5); rootNode2.addVersion("rootnode2-data3",6); //Console.WriteLine(rootNode2.toString()); List<Node> conflicts = rootNode1.merge(rootNode2); Console.WriteLine(); Console.WriteLine("Conflicts"); Console.WriteLine("========="); foreach (Node node in conflicts) { Console.WriteLine(node.rev_id); } Console.WriteLine(); Console.WriteLine("Result"); Console.WriteLine("======"); //Console.WriteLine(rootNode1.toString()); Console.WriteLine(new[] { 1, 2, 3 }.ToJson()); Console.WriteLine(rootNode1.revision.ToJson<Dictionary<string, Node>>()); //Console.WriteLine(rootNode1.ToString()); }
// Create the initial root revision (called during insert from replication) public Node(string id, string data, long sequence, string rev_id) { //rev_id = revision.Count.ToString() + "-" + Utils.CalculateMD5Hash(data); // create the new subnode containing this version Node newNode = new Node(this, rev_id, sequence); newNode.sequence = sequence; // reference to the actual data in the full sequence store this.id = id; this.rev_id = rev_id; this.sequence = sequence; currentVersion = rev_id.Split('-')[0]; revision.Add(currentVersion, newNode); }
// Called to create a new subnode under a parent public Node(Node parent, string rev_id, long sequence) { this.parent = parent; this.rev_id = rev_id; this.sequence = sequence; }
// Merge this revision tree with the one passed in as rootNode // This implementation overwrites local nodes with the supplied version public List<Node> merge(Node rootNode) { List<Node> conflicts = new List<Node>(); bool finished = false; int currentVersion = 1; Console.WriteLine("Starting merge: "); do { Console.WriteLine("Merge version: " + Convert.ToString(currentVersion)); Node node = rootNode.getVersion(Convert.ToString(currentVersion)); if (node == null) { Console.WriteLine("Merge complete.."); finished = true; } else { if (revision.ContainsKey(Convert.ToString(currentVersion))) { Console.WriteLine("Target contains same version as source ..."); Console.WriteLine("Source contains: " + revision[Convert.ToString(currentVersion)].rev_id); Console.WriteLine("Target contains: " + node.rev_id); if (revision[Convert.ToString(currentVersion)].rev_id != node.rev_id) { // Conflict - two version of the same value exist Console.WriteLine("Conflict detected: " + node.rev_id); // work out which has the longer tail - this will take priority conflicts.Add(node); } } else { // Version does not exist - add the whole subtree (potentially) Console.WriteLine("New version being added: " + node.rev_id); this.addVersion(Convert.ToString(currentVersion - 1), node); } } currentVersion++; } while (!finished); return conflicts; }
public Node addVersion(string previousVersion, Node newNode) { // Update this doc with a new version if (previousVersion == currentVersion) { string nextVersion = Convert.ToString(Convert.ToInt32(currentVersion) + 1); Debug.WriteLine("Version incremented to: " + nextVersion); revision.Add(nextVersion, newNode); currentVersion = nextVersion; } else { Debug.WriteLine("addVersion(node) - incompatible version being added: "); Debug.WriteLine("Previous version: " + previousVersion + " , current version: " + currentVersion); } return newNode; }
// Called during deserialisation public Node addVersion(string version, string sequence, string rev_id) { Node newNode = new Node(this, rev_id, Convert.ToInt64(sequence)); revision.Add(version, newNode); currentVersion = version; return newNode; }
public Node addVersion(string previousVersion, string rev_id, long sequence) { Node newNode = null; Console.WriteLine("Previous version: " + previousVersion + " , current version: " + currentVersion); // Update this doc with a new version if (previousVersion == currentVersion) { Debug.WriteLine("versions match"); // create the new subnode containing this version newNode = new Node(this, rev_id,sequence); this.addVersion(currentVersion, newNode); } else { Debug.WriteLine("Trying to add a node with an unexpected version number: " + Convert.ToString(currentVersion)); // create the new subnode containing this version newNode = new Node(this, rev_id, sequence); this.addVersion(previousVersion, newNode); } return newNode; }
public static Node Parse(string json) { string tempStr= json.Split(',')[0]; string docId = tempStr.Split(':')[1]; Node newNode = new Node(docId); json = json.Split('[')[1]; json = json.Split(']')[0]; var nodeList = json.Split('{'); var versionList = new Dictionary<string,Dictionary<string,string>>(); foreach (string node in nodeList) { if (node != "") { var propertyList = node.Split(','); var propList = new Dictionary<string, string>(); foreach (string property in propertyList) { string propStr = property.Split('}')[0]; string propName = propStr.Split(':')[0]; string propValue = propStr.Split(':')[1]; propList.Add(propName, propValue); } versionList.Add(propList["version"], propList); newNode.addVersion(propList["version"],propList["sequence"],propList["rev_id"]); } } return newNode; }
/// <summary> /// Update or insert a new document into the database /// </summary> /// <param name="docId">ID of the document to store or update</param> /// <param name="data">string data for the associated document</param> /// <param name="revId">specific version add by revId </param> public void PutDoc(string docId, string data, string revId) { Node docInfo = null; try { // If possible try and retrieve any existing doc info for this id string docInfoString = docStore.Get(ReadOptions.Default,docId).ToString(); if (docInfoString == null) { // Insert mode: create a new root document docInfo = new Node(docId, data, sequenceCount,revId); docCount = docCounter.Next(); } else { // Update mode: create a new revision entry docInfo = Node.Parse(docInfoString); // add a new document version if (docInfo.addVersion(data, sequenceCount, revId) == null) { return; } } // Store info about the document in the doc store //Debug.WriteLine(docInfo.Dump()); string docInfoData = docInfo.ToJson(); docInfoData = docInfoData.Replace("\"", ""); docStore.Put(WriteOptions.Default, docId, docInfoData); // store a unique uuid linked with the doc id data sequenceStore.Put(WriteOptions.Default, sequenceCount.ToString(), docInfo.getLatestSig() + "+" + data); sequenceCount = sequenceCounter.Next(); } catch (Exception ee) { throw ee; } finally { } }