/// <summary> /// Creates a tree from the given chunks. Children are grouped to increase the likelihood of node reuse. /// </summary> private static DedupNode CreateRollingHashTree(IReadOnlyList <DedupNode> chunks) { // If we do need to make a tree, then we'll want to use a rolling hash function to ensure // that we get consistent groupings of children nodes even with insertions/removals // of children (i.e. changes to the underlying file). var rolling = new RollingHash( windowLength: 4, bitMask: VariableChildCountBitMask, minCount: MinVariableChildCount); var thisLevel = new Queue <DedupNode>(chunks); while (thisLevel.Count > DedupNode.MaxDirectChildrenPerNode) { var nextLevel = new Queue <DedupNode>(); while (thisLevel.Any()) { rolling.Reset(); var nodesForChild = new List <DedupNode>(); while (thisLevel.Any() && nodesForChild.Count < DedupNode.MaxDirectChildrenPerNode && !rolling.IsAtBoundary) { var node = thisLevel.Dequeue(); ulong nodeHash = 0; nodeHash ^= BitConverter.ToUInt64(node.Hash, 0); nodeHash ^= BitConverter.ToUInt64(node.Hash, 8); nodeHash ^= BitConverter.ToUInt64(node.Hash, 16); nodeHash ^= BitConverter.ToUInt64(node.Hash, 24); rolling.Add(nodeHash); nodesForChild.Add(node); } var newNode = new DedupNode(nodesForChild); nextLevel.Enqueue(newNode); } thisLevel = nextLevel; } var root = new DedupNode(thisLevel.ToList()); return(root); }