예제 #1
0
 private static TreeResponse projectTreeJSON(TreeNode tree)
 {
     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() })
     };
 }
 public Builder(TreeNode imm)
 {
     this.Trees = (imm.Trees).ToList((imm.Trees).Length);
     this.Blobs = (imm.Blobs).ToList((imm.Blobs).Length);
 }
        private async Task<Errorable<TreeIDPathMapping>> getTreeIDByPath(TreeNode root, TreeTreePath path)
        {
            ReadOnlyCollection<string> parts = path.Path.Parts;
            if (parts.Count == 0) return new TreeIDPathMapping(path, path.RootTreeID);

            int j = 0;

            // Start descending into child nodes:
            TreeNode node = root, nextNode;
            while (node != null)
            {
                nextNode = null;

                // Check all child nodes against the next name in the path:
                for (int i = 0; i < node.Trees.Length; ++i)
                    // TODO: specific string comparison logic!
                    if (parts[j] == node.Trees[i].Name)
                    {
                        TreeID nextID = node.Trees[i].TreeID;

                        // Run out of path components? This is it!
                        if (++j == parts.Count) return new TreeIDPathMapping(path, (TreeID?)nextID);

                        // Load up the next node so we can scan through its child nodes:
                        var enextNode = await getTree(nextID).ConfigureAwait(continueOnCapturedContext: false);
                        if (enextNode.HasErrors) return enextNode.Errors;

                        nextNode = enextNode.Value;
                        break;
                    }

                // Attempt to continue:
                node = nextNode;
            }

            // If we got here it means that we didn't find what we were looking for:
            return new TreeIDPathMapping(path, (TreeID?)null);
        }
        private async Task<Errorable<TreeNode>> persistTree(TreeNode tr)
        {
            Debug.Assert(tr != null);

            // Check that all referenced blobs are already persisted:
            foreach (var trbl in tr.Blobs)
            {
                if (!system.getPathByID(trbl.BlobID).Exists)
                    return new BlobIDRecordDoesNotExistError(trbl.BlobID);
            }

            // Check that all referenced blobs are already persisted:
            foreach (var trtr in tr.Trees)
            {
                if (!system.getPathByID(trtr.TreeID).Exists)
                    return new TreeIDRecordDoesNotExistError(trtr.TreeID);
            }

            // Write the tree contents to the file:
            FileInfo tmpFile = system.getTemporaryFile();
            using (var fs = new FileStream(tmpFile.FullName, FileMode.CreateNew, FileAccess.Write, FileShare.None, bufferSize: 16384, useAsync: true))
            {
                await fs.WriteRawAsync(tr.WriteTo(new StringBuilder()).ToString());
            }

            lock (FileSystem.SystemLock)
            {
                FileInfo fi = system.getPathByID(tr.ID);

                // NOTE: if the record already exists we can either error out or overwrite the existing file with contents known to be good in the case the existing file got corrupt.
                // Let's stick with the self-repair scenario since erroring out doesn't help anyone.
                if (fi.Exists)
                {
                    Debug.WriteLine(String.Format("Self-repair scenario: overwriting old TreeID {0} with new contents", tr.ID));
                    fi.Delete();
                    File.Move(tmpFile.FullName, fi.FullName);
                    return tr;
                }

                // Create directory if it doesn't exist:
                if (!fi.Directory.Exists)
                {
                    Debug.WriteLine(String.Format("New DIR '{0}'", fi.Directory.FullName));
                    fi.Directory.Create();
                }

                Debug.WriteLine(String.Format("New TREE '{0}'", fi.FullName));
                File.Move(tmpFile.FullName, fi.FullName);
            }

            return tr;
        }
        private async Task<Errorable<TreeNode[]>> getTreeRecursively(TreeID id)
        {
            var eroot = await getTree(id).ConfigureAwait(continueOnCapturedContext: false);
            if (eroot.HasErrors) return eroot.Errors;

            var root = eroot.Value;
            var rootArr = new TreeNode[1] { root };

            if (root.Trees.Length == 0)
                return rootArr;

            Task<Errorable<TreeNode[]>>[] tasks = new Task<Errorable<TreeNode[]>>[root.Trees.Length];
            for (int i = 0; i < root.Trees.Length; ++i)
            {
                tasks[i] = getTreeRecursively(root.Trees[i].TreeID);
            }

            // Await all the tree retrievals:
            var allTrees = await Task.WhenAll(tasks).ConfigureAwait(continueOnCapturedContext: false);

            // Roll up all the errors:
            ErrorContainer errors =
                (
                    from etrs in allTrees
                    where etrs.HasErrors
                    select etrs.Errors
                ).Aggregate(new ErrorContainer(), (acc, err) => acc + err);

            if (errors.HasAny) return errors;

            // Flatten out the tree arrays:
            var flattened =
                from etrs in allTrees
                from tr in etrs.Value
                select tr;

            // Return the final array:
            return rootArr.Concat(flattened).ToArray(allTrees.Sum(ta => ta.Value.Length) + 1);
        }