internal static void RecursivePrint(TreeID treeID, ImmutableContainer <TreeID, TreeNode> trees, int depth = 1) { TreeNode tr; if (!trees.TryGetValue(treeID, out tr)) { return; } if (depth == 1) { Console.WriteLine("tree {1}: {0}/", new string('_', (depth - 1) * 2), tr.ID.ToString(firstLength: 7)); } // Sort refs by name: var namedRefs = TreeNode.ComputeChildList(tr.Trees, tr.Blobs); foreach (var kv in namedRefs) { var nref = kv.Value; switch (nref.Which) { case Either <TreeTreeReference, TreeBlobReference> .Selected.Left: Console.WriteLine("tree {1}: {0}{2}/", new string('_', depth * 2), nref.Left.TreeID.ToString(firstLength: 7), nref.Left.Name); RecursivePrint(nref.Left.TreeID, trees, depth + 1); break; case Either <TreeTreeReference, TreeBlobReference> .Selected.Right: Console.WriteLine("blob {1}: {0}{2}", new string('_', depth * 2), nref.Right.BlobID.ToString(firstLength: 7), nref.Right.Name); break; } } }
private static TreeResponse projectTreeJSON(TreeID rootid, ImmutableContainer<TreeID, TreeNode> trees) { TreeNode tree; if (!trees.TryGetValue(rootid, out tree)) return null; return new TreeResponse { id = tree.ID.ToString(), blobs = tree.Blobs.SelectAsArray(bl => new TreeBlobRefResponse { name = bl.Name, blobid = bl.BlobID.ToString() }), trees = tree.Trees.SelectAsArray(tr => new TreeTreeRefResponse { name = tr.Name, treeid = tr.TreeID.ToString(), tree = projectTreeJSON(tr.TreeID, trees) }) }; }
private CommitTreeResponse toJSON(CommitID id, ImmutableContainer<CommitID, ICommit> commits) { ICommit cm; if (!commits.TryGetValue(id, out cm)) return null; return new CommitTreeResponse() { id = cm.ID.ToString(), treeid = cm.TreeID.ToString(), committer = cm.Committer.ToString(), date_committed = JSONTranslateExtensions.FromDate(cm.DateCommitted), parents_retrieved = cm.IsComplete, message = cm.Message, parents = cm.Parents.SelectAsArray(cmid => toJSON(cmid, commits)) }; }
internal static void RecursivePrint(CommitID cmID, ImmutableContainer <CommitID, ICommit> commits, int depth = 1) { ICommit cm; if (!commits.TryGetValue(cmID, out cm)) { return; } if (cm.IsComplete) { Console.WriteLine("{0}c {1}: ({2})", new string(' ', (depth - 1) * 2), cm.ID.ToString(firstLength: 7), String.Join(",", cm.Parents.Select(id => id.ToString(firstLength: 7)))); foreach (CommitID parentID in cm.Parents) { RecursivePrint(parentID, commits, depth + 1); } } else { Console.WriteLine("{0}p {1}: ?", new string(' ', (depth - 1) * 2), cm.ID.ToString(firstLength: 7)); } }
public async Task<Errorable<TreeNode>> PersistTree(TreeID rootid, ImmutableContainer<TreeID, TreeNode> trees) { if (trees == null) throw new ArgumentNullException("trees"); // TODO: better return value than `null` if (trees.Count == 0) return (TreeNode)null; // Start a query to check what Trees exist already: var existTrees = await db.ExecuteListQueryAsync(new QueryTreesExist(trees.Keys), expectedCapacity: trees.Count); // This code scans the tree breadth-first and builds a reversed depth-ordered stack: var reverseDepthOrder = new { id = rootid, depth = 0 }.StackOf(trees.Count); reverseDepthOrder.Pop(); var breadthFirstQueue = new { id = rootid, depth = 0 }.QueueOf(trees.Count); while (breadthFirstQueue.Count > 0) { var curr = breadthFirstQueue.Dequeue(); // Add it to the reverse stack: reverseDepthOrder.Push(curr); TreeNode node; if (!trees.TryGetValue(curr.id, out node)) { // TODO: didn't find the TreeID in the given collection, assume already persisted? continue; } // Queue up the child TreeIDs: foreach (var trtr in node.Trees) breadthFirstQueue.Enqueue(new { id = trtr.TreeID, depth = curr.depth + 1 }); } // This code takes the reverse depth-ordered stack and persists the tree nodes in groups per depth level. // This ensures that all child nodes across the breadth of the tree at each depth level are persisted // before moving up to their parents. List<Task<Errorable<TreeNode>>> persistTasks = new List<Task<Errorable<TreeNode>>>(); // Initialize the `isPersisting` set with the set of TreeIDs that already exist. HashSet<TreeID> isPersisting = new HashSet<TreeID>(existTrees); int lastDepth = reverseDepthOrder.Peek().depth; foreach (var curr in reverseDepthOrder) { Debug.WriteLine(String.Format("{0}: {1}", curr.depth, curr.id.ToString(firstLength: 7))); // An invariant of the algorithm, enforced via assert: Debug.Assert(curr.depth <= lastDepth); // Did we move to the next depth group: if ((persistTasks.Count > 0) && (curr.depth != lastDepth)) { Debug.WriteLine(String.Format("Awaiting depth group {0}...", lastDepth)); // Wait for the last depth group to finish persisting: await Task.WhenAll(persistTasks); // Start a new depth group: persistTasks = new List<Task<Errorable<TreeNode>>>(); } // Don't re-persist the same TreeID (this is a legit case - the same TreeID may be seen in different nodes of the tree): if (isPersisting.Contains(curr.id)) { Debug.WriteLine(String.Format("Already persisting {0}", curr.id.ToString(firstLength: 7))); // Keep track of the last depth level: lastDepth = curr.depth; continue; } // Get the TreeNode and persist it: TreeNode node = trees[curr.id]; isPersisting.Add(curr.id); // Fire up a task to persist this tree node: var tsk = db.ExecuteNonQueryAsync(new PersistTree(node)); // Add the task to the depth group to await: Debug.WriteLine(String.Format("Adding to depth group {0}...", curr.depth)); persistTasks.Add(tsk); // Keep track of the last depth level: lastDepth = curr.depth; } Debug.Assert(lastDepth == 0); if (persistTasks.Count > 0) { // Await the last group (the root node): Debug.WriteLine(String.Format("Awaiting depth group {0}...", lastDepth)); await Task.WhenAll(persistTasks); } // Return the root TreeNode: return trees[rootid]; }
public async Task <Errorable <TreeNode> > PersistTree(TreeID rootid, ImmutableContainer <TreeID, TreeNode> trees) { if (trees == null) { throw new ArgumentNullException("trees"); } // TODO: better return value than `null` if (trees.Count == 0) { return((TreeNode)null); } // This code scans the tree breadth-first and builds a reversed depth-ordered stack: var reverseDepthOrder = new { id = rootid, depth = 0 }.StackOf(trees.Count); reverseDepthOrder.Pop(); var breadthFirstQueue = new { id = rootid, depth = 0 }.QueueOf(trees.Count); while (breadthFirstQueue.Count > 0) { var curr = breadthFirstQueue.Dequeue(); // Add it to the reverse stack: reverseDepthOrder.Push(curr); TreeNode node; if (!trees.TryGetValue(curr.id, out node)) { // TODO: didn't find the TreeID in the given collection, assume already persisted? continue; } // Queue up the child TreeIDs: foreach (var trtr in node.Trees) { breadthFirstQueue.Enqueue(new { id = trtr.TreeID, depth = curr.depth + 1 }); } } // This code takes the reverse depth-ordered stack and persists the tree nodes in groups per depth level. // This ensures that all child nodes across the breadth of the tree at each depth level are persisted // before moving up to their parents. List <Task <Errorable <TreeNode> > > persistTasks = new List <Task <Errorable <TreeNode> > >(); HashSet <TreeID> isPersisting = new HashSet <TreeID>(); int lastDepth = reverseDepthOrder.Peek().depth; foreach (var curr in reverseDepthOrder) { Debug.WriteLine(String.Format("{0}: {1}", curr.depth, curr.id.ToString(firstLength: 7))); // An invariant of the algorithm, enforced via assert: Debug.Assert(curr.depth <= lastDepth); // Did we move to the next depth group: if (curr.depth != lastDepth) { Debug.WriteLine(String.Format("Awaiting depth group {0}...", lastDepth)); // Wait for the last depth group to finish persisting: await Task.WhenAll(persistTasks); // TODO: roll up errors! // Start a new depth group: persistTasks = new List <Task <Errorable <TreeNode> > >(); } // Don't re-persist the same TreeID (this is a legit case - the same TreeID may be seen in different nodes of the tree): if (isPersisting.Contains(curr.id)) { Debug.WriteLine(String.Format("Already persisting {0}", curr.id.ToString(firstLength: 7))); // Keep track of the last depth level: lastDepth = curr.depth; continue; } // Get the TreeNode and persist it: TreeNode node = trees[curr.id]; isPersisting.Add(curr.id); // Fire up a task to persist this tree node: var tsk = Task.Run(() => persistTree(node)); // Add the task to the depth group to await: Debug.WriteLine(String.Format("Adding to depth group {0}...", curr.depth)); persistTasks.Add(tsk); // Keep track of the last depth level: lastDepth = curr.depth; } // The final depth group should be depth 0 with at most 1 element: the root node. Debug.Assert(lastDepth == 0); if (persistTasks.Count > 0) { // Await the last group (the root node): Debug.WriteLine(String.Format("Awaiting depth group {0}...", lastDepth)); await Task.WhenAll(persistTasks); } // Return the root TreeNode: return(persistTasks[0].Result); }