private bool RedistributeBranchElements(TreeBranch branch, int childIndex, TreeBranch child) { // We distribute the nodes in the child branch with the branch // immediately to the right. If that's not possible, then we distribute // with the left. // If branch has only a single value, return immediately int branchSize = branch.ChildCount; if (branchSize == 1) { return(false); } int leftI, rightI; TreeBranch left, right; if (childIndex < branchSize - 1) { // Distribute with the right leftI = childIndex; rightI = childIndex + 1; left = child; right = (TreeBranch)UnfreezeNode(FetchNode(branch.GetChild(childIndex + 1))); branch.SetChild(right.Id, childIndex + 1); } else { // Distribute with the left leftI = childIndex - 1; rightI = childIndex; left = (TreeBranch)UnfreezeNode(FetchNode(branch.GetChild(childIndex - 1))); right = child; branch.SetChild(left.Id, childIndex - 1); } // Get the mid value key reference Key midKey = branch.GetKey(rightI); // Perform the merge, Key newMidKey = left.Merge(right, midKey); // Reset the leaf element count branch.SetChildLeafElementCount(left.LeafElementCount, leftI); branch.SetChildLeafElementCount(right.LeafElementCount, rightI); // If after the merge the right branch is empty, we need to remove it if (right.IsEmpty) { // Delete the node DeleteNode(right.Id); // And remove it from the branch, branch.RemoveChild(rightI); return(true); } // Otherwise set the key reference branch.SetKeyToLeft(newMidKey, rightI); return(false); }
public void MoveLastHalfInto(TreeBranch dest) { int midpoint = children.Length / 2; // Check mutable CheckReadOnly(); dest.CheckReadOnly(); // Check this is full if (!IsFull) { throw new InvalidOperationException("Branch node is not full."); } // Check destination is empty if (!dest.IsEmpty) { throw new ArgumentException("Destination branch node is not empty."); } // Copy, Array.Copy(children, midpoint + 1, dest.children, 0, midpoint - 1); // New child count in each branch node. int newChildCount = MaxChildCount / 2; // Set the size of this and the destination node childrenCount = newChildCount; dest.childrenCount = newChildCount; }
private void UpdateStackProperties(int sizeDiff) { StackFrame frame = StackEnd(0); int sz = FrameCount; // Walk the stack from the end for (int i = 1; i < sz; ++i) { int childIndex = frame.ChildIndex; frame = StackEnd(i); NodeId nodeId = frame.NodeId; TreeBranch branch = (TreeBranch)FetchNode(nodeId); branch.SetChildLeafElementCount(branch.GetChildLeafElementCount(childIndex) + sizeDiff, childIndex); } }
public Key MergeLeft(TreeBranch right, Key midValue, int count) { // Check mutable CheckReadOnly(); // If we moving all from right, if (count == right.ChildCount) { // Move all the elements into this node, int destP = childrenCount * 5; int rightLen = (right.childrenCount * 5) - 2; Array.Copy(right.children, 0, children, destP, rightLen); children[destP - 2] = midValue.GetEncoded(1); children[destP - 1] = midValue.GetEncoded(2); // Update children_count childrenCount += right.childrenCount; return(null); } if (count < right.ChildCount) { right.CheckReadOnly(); // Shift elements from right to left // The amount to move that will leave the right node at min threshold int destP = ChildCount * 5; int rightLen = (count * 5) - 2; Array.Copy(right.children, 0, children, destP, rightLen); // Redistribute the right elements int rightRedist = (count * 5); // The midpoint value becomes the extent shifted off the end long newMidpointValue1 = right.children[rightRedist - 2]; long newMidpointValue2 = right.children[rightRedist - 1]; // Shift the right child Array.Copy(right.children, rightRedist, right.children, 0, right.children.Length - rightRedist); children[destP - 2] = midValue.GetEncoded(1); children[destP - 1] = midValue.GetEncoded(2); childrenCount += count; right.childrenCount -= count; // Return the new midpoint value return(new Key(newMidpointValue1, newMidpointValue2)); } throw new ApplicationException("count > right.size()"); }
private void UnfreezeStack() { StackFrame frame = StackEnd(0); NodeId oldChildNodeId = frame.NodeId; // If the leaf ref isn't frozen then we exit early if (!IsFrozen(oldChildNodeId)) { return; } TreeLeaf leaf = (TreeLeaf)UnfreezeNode(FetchNode(oldChildNodeId)); NodeId newChildNodeId = leaf.Id; frame.NodeId = newChildNodeId; currentLeaf = leaf; // NOTE: Setting current_leaf here does not change the key of the node // so we don't need to update current_leaf_key. // Walk the rest of the stack from the end int sz = FrameCount; for (int i = 1; i < sz; ++i) { int changedChildIndex = frame.ChildIndex; frame = StackEnd(i); NodeId oldBranchId = frame.NodeId; TreeBranch branch = (TreeBranch)UnfreezeNode(FetchNode(oldBranchId)); // Get the child_i from the stack, branch.SetChild(newChildNodeId, changedChildIndex); // Change the stack entry frame.NodeId = branch.Id; newChildNodeId = branch.Id; } // Set the new root node ref RootNodeId = newChildNodeId; }
public void WriteLeafOnly(Key key) { // Get the stack frame for the last entry. StackFrame frame = StackEnd(0); // The leaf NodeId leafId = frame.NodeId; // Write it out NodeId newId = WriteNode(leafId); // If new_ref = leaf_ref, then we didn't write a new node if (newId.Equals(leafId)) { return; } // Otherwise, update the references, frame.NodeId = newId; currentLeaf = (TreeLeaf)FetchNode(newId); // Walk back up the stack and update the ref as necessary int sz = FrameCount; for (int i = 1; i < sz; ++i) { // Get the child_i from the stack, int changedChildIndex = frame.ChildIndex; frame = StackEnd(i); NodeId oldBranchId = frame.NodeId; TreeBranch branch = (TreeBranch)UnfreezeNode(FetchNode(oldBranchId)); branch.SetChild(newId, changedChildIndex); // Change the stack entry newId = branch.Id; frame.NodeId = newId; } // Set the new root node ref RootNodeId = newId; }
private TreeGraph CreateRootGraph(Key leftKey, long reference) { // The node being returned TreeGraph graph; // Open the area IArea area = store.GetArea(reference); // What type of node is this? short nodeType = area.ReadInt2(); // The version short ver = area.ReadInt2(); if (nodeType == LeafType) { // Read the reference count, long refCount = area.ReadInt4(); // The number of bytes in the leaf int leafSize = area.ReadInt4(); // Set up the leaf node object graph = new TreeGraph("leaf", reference); graph.SetProperty("ver", ver); graph.SetProperty("key", leftKey.ToString()); graph.SetProperty("reference_count", refCount); graph.SetProperty("leaf_size", leafSize); } else if (nodeType == BranchType) { // The data size area containing the children information int childDataSize = area.ReadInt4(); long[] data = new long[childDataSize]; for (int i = 0; i < childDataSize; ++i) { data[i] = area.ReadInt8(); } // Create the TreeBranch object to query it TreeBranch branch = new TreeBranch(reference, data, childDataSize); // Set up the branch node object graph = new TreeGraph("branch", reference); graph.SetProperty("ver", ver); graph.SetProperty("key", leftKey.ToString()); graph.SetProperty("branch_size", branch.ChildCount); // Recursively add each child into the tree for (int i = 0; i < branch.ChildCount; ++i) { long child_ref = branch.GetChild(i); // If the ref is a special node, skip it if ((child_ref & 0x01000000000000000L) != 0) { // Should we record special nodes? } else { Key newLeftKey = (i > 0) ? branch.GetKey(i) : leftKey; TreeGraph bn = new TreeGraph("child_meta", reference); bn.SetProperty("extent", branch.GetChildLeafElementCount(i)); graph.AddChild(bn); graph.AddChild(CreateRootGraph(newLeftKey, child_ref)); } } } else { throw new IOException("Unknown node type: " + nodeType); } return graph; }
private ITreeNode FetchNode(long nodeId) { // Is it a special static node? if ((nodeId & 0x01000000000000000L) != 0) return SparseLeafNode.Create(nodeId); // Is this a branch node in the cache? TreeBranch branch; lock (branchCache) { branch = (TreeBranch)branchCache.Get(nodeId); if (branch != null) return branch; } // Not found in the cache, so fetch the area from the backing store and // create the node type. // Get the area for the node IArea nodeArea = store.GetArea(nodeId); // Wrap around a BinaryReader for reading values from the store. BinaryReader reader = new BinaryReader(new AreaInputStream(nodeArea, 256)); short nodeType = reader.ReadInt16(); if (nodeType == LeafType) { // Read the key reader.ReadInt16(); // version reader.ReadInt32(); // reference count int leafSize = reader.ReadInt32(); // Return a leaf that's mapped to the data in the store nodeArea.Position = 0; return new AreaTreeLeaf(nodeId, leafSize, nodeArea); } else if (nodeType == BranchType) { // Note that the entire branch is loaded into memory now, reader.ReadInt16(); // version int childDataSize = reader.ReadInt32(); long[] data = new long[childDataSize]; for (int i = 0; i < childDataSize; ++i) { data[i] = reader.ReadInt64(); } branch = new TreeBranch(nodeId, data, childDataSize); // Put this branch in the cache, lock (branchCache) { branchCache.Set(nodeId, branch); // And return the branch return branch; } } throw new ApplicationException("Unknown node type: " + nodeType); }
public void MoveLastHalfInto(TreeBranch dest) { int midpoint = children.Length / 2; CheckReadOnly(); dest.CheckReadOnly(); // Check this is full if (!IsFull) throw new ApplicationException("Branch node is not full."); // Check destination is empty if (dest.ChildCount != 0) throw new ApplicationException("Destination branch node is not empty."); // Copy, Array.Copy(children, midpoint + 1, dest.children, 0, midpoint - 1); // New child count in each branch node. int new_child_count = MaxSize / 2; // Set the size of this and the destination node childCount = new_child_count; dest.childCount = new_child_count; }
public IList<long> Persist(TreeWrite write) { try { store.LockForWrite(); IList<ITreeNode> branches = write.BranchNodes; IList<ITreeNode> leafs = write.LeafNodes; List<ITreeNode> nodes = new List<ITreeNode>(branches.Count + leafs.Count); nodes.AddRange(branches); nodes.AddRange(leafs); // The list of nodes to be allocated, int sz = nodes.Count; // The list of allocated referenced for the nodes, long[] refs = new long[sz]; // The list of area writers, IAreaWriter[] areas = new IAreaWriter[sz]; // Allocate the space first, for (int i = 0; i < sz; ++i) { ITreeNode node = nodes[i]; if (node is TreeBranch) { TreeBranch branch = (TreeBranch)node; int ndsz = branch.DataSize; areas[i] = store.CreateArea(4 + 4 + (ndsz * 8)); } else { TreeLeaf leaf = (TreeLeaf)node; int lfsz = leaf.Length; areas[i] = store.CreateArea(12 + lfsz); } // Set the reference, refs[i] = areas[i].Id; } // Now write out the data, for (int i = 0; i < sz; ++i) { ITreeNode node = nodes[i]; // Is it a branch node? if (node is TreeBranch) { TreeBranch branch = (TreeBranch)node; // The number of children int chsz = branch.ChildCount; // For each child, if it's a heap node, look up the child id and // reference map in the sequence and set the reference accordingly, for (int o = 0; o < chsz; ++o) { long childId = branch.GetChild(o); if (childId < 0) { // The ref is currently on the heap, so adjust accordingly int refId = write.LookupRef(i, o); branch.SetChild(o, refs[refId]); } } // Write out the branch to the store long[] nodeData = branch.ChildPointers; int ndsz = branch.DataSize; IAreaWriter writer = areas[i]; writer.WriteInt2(BranchType); writer.WriteInt2(1); // version writer.WriteInt4(ndsz); for (int o = 0; o < ndsz; ++o) { writer.WriteInt8(nodeData[o]); } writer.Finish(); // Make this into a branch node and add to the cache, branch = new TreeBranch(refs[i], nodeData, ndsz); // Put this branch in the cache, lock (branchCache) { branchCache.Set(refs[i], branch); } } else { // Otherwise, it must be a leaf node, TreeLeaf leaf = (TreeLeaf)node; IAreaWriter area = areas[i]; area.WriteInt2(LeafType); area.WriteInt2(1); // version area.WriteInt4(1); // reference count area.WriteInt4(leaf.Length); leaf.WriteTo(area); area.Finish(); } } return refs; } finally { store.UnlockForWrite(); } }
public Key MergeLeft(TreeBranch right, Key mid_value, int count) { // Check mutable CheckReadOnly(); // If we moving all from right, if (count == right.ChildCount) { // Move all the elements into this node, int dest_p = childCount * 4; int right_len = (right.childCount * 4) - 2; Array.Copy(right.children, 0, children, dest_p, right_len); children[dest_p - 2] = mid_value.GetEncoded(1); children[dest_p - 1] = mid_value.GetEncoded(2); // Update children_count childCount += right.childCount; return null; } if (count < right.ChildCount) { right.CheckReadOnly(); // Shift elements from right to left // The amount to move that will leave the right node at min threshold int dest_p = ChildCount * 4; int right_len = (count * 4) - 2; Array.Copy(right.children, 0, children, dest_p, right_len); // Redistribute the right elements int right_redist = (count * 4); // The midpoint value becomes the extent shifted off the end long new_midpoint_value1 = right.children[right_redist - 2]; long new_midpoint_value2 = right.children[right_redist - 1]; // Shift the right child Array.Copy(right.children, right_redist, right.children, 0, right.children.Length - right_redist); children[dest_p - 2] = mid_value.GetEncoded(1); children[dest_p - 1] = mid_value.GetEncoded(2); childCount += count; right.childCount -= count; // Return the new midpoint value return new Key(new_midpoint_value1, new_midpoint_value2); } throw new ArgumentException("count > right.size()"); }
public TreeBranch(long id, TreeBranch branch, int maxChildCount) : this(id, maxChildCount) { Array.Copy(branch.children, 0, children, 0, Math.Min(branch.children.Length, children.Length)); childCount = branch.childCount; }
public void DeleteLeaf(Key key) { // Set up the state StackFrame frame = StackEnd(0); NodeId thisRef = frame.NodeId; TreeBranch branchNode = null; int deleteNodeSize = -1; Key leftKey = null; // Walk back through the rest of the stack int sz = FrameCount; for (int i = 1; i < sz; ++i) { // Find the child_i for the child // This is the child_i of the child in the current branch int childIndex = frame.ChildIndex; // Move the stack frame, frame = StackEnd(i); NodeId childId = thisRef; thisRef = frame.NodeId; TreeBranch childBranch = branchNode; branchNode = (TreeBranch)UnfreezeNode(FetchNode(thisRef)); if (deleteNodeSize == -1) { deleteNodeSize = (int)branchNode.GetChildLeafElementCount(childIndex); } // If the child branch is empty, if (childBranch == null || childBranch.IsEmpty) { // Delete the reference to it, if (childIndex == 0 && branchNode.ChildCount > 1) { leftKey = branchNode.GetKey(1); } branchNode.RemoveChild(childIndex); // Delete the child branch, DeleteNode(childId); } // Not empty, else { // Replace with the new child node reference branchNode.SetChild(childBranch.Id, childIndex); // Set the element count long newChildSize = branchNode.GetChildLeafElementCount(childIndex) - deleteNodeSize; branchNode.SetChildLeafElementCount(newChildSize, childIndex); // Can we set the left key reference? if (childIndex > 0 && leftKey != null) { branchNode.SetKeyToLeft(leftKey, childIndex); leftKey = null; } // Has the size of the child reached the lower threshold? if (childBranch.ChildCount <= 2) { // If it has, we need to redistribute the children, RedistributeBranchElements(branchNode, childIndex, childBranch); } } } // Finally, set the root node // If the branch node is a single element, we set the root as the child, if (branchNode.ChildCount == 1) { // This shrinks the height of the tree, RootNodeId = branchNode.GetChild(0); DeleteNode(branchNode.Id); if (TreeHeight != -1) { TreeHeight = TreeHeight - 1; } } else { // Otherwise, we set the branch node. RootNodeId = branchNode.Id; } // Reset the object Reset(); }
private ITreeNode FetchNode(NodeId nodeId) { // Is it a special static node? if (nodeId.IsSpecial) { return(SpecialStaticNode(nodeId)); } // Is this a branch node in the cache? NodeId cacheKey = nodeId; TreeBranch branch; lock (branchCache) { branch = (TreeBranch)branchCache.Get(cacheKey); if (branch != null) { return(branch); } } // Not found in the cache, so fetch the area from the backing store and // create the node type. // Get the area for the node IArea nodeArea = nodeStore.GetArea(ToInt64StoreAddress(nodeId)); // Wrap around a buffered BinaryRader for reading values from the store. BinaryReader input = new BinaryReader(new AreaInputStream(nodeArea, 256)); short nodeType = input.ReadInt16(); // Is the node type a leaf node? if (nodeType == StoreLeafType) { // Read the key input.ReadInt16(); // version input.ReadInt32(); // reference count int leafSize = input.ReadInt32(); // Return a leaf that's mapped to the data in the store nodeArea.Position = 0; return(new AreaTreeLeaf(nodeId, leafSize, nodeArea)); } // Is the node type a branch node? if (nodeType == StoreBranchType) { // Note that the entire branch is loaded into memory now, input.ReadInt16(); // version int childDataSize = input.ReadInt32(); long[] dataArr = new long[childDataSize]; for (int i = 0; i < childDataSize; ++i) { dataArr[i] = input.ReadInt64(); } branch = new TreeBranch(nodeId, dataArr, childDataSize); // Put this branch in the cache, lock (branchCache) { branchCache.Set(cacheKey, branch); // And return the branch return(branch); } } throw new ApplicationException("Unknown node type: " + nodeType); }
private TreeReportNode CreateDiagnosticRootGraph(Key leftKey, NodeId id) { // The node being returned TreeReportNode node; // Open the area IArea area = nodeStore.GetArea(ToInt64StoreAddress(id)); // What type of node is this? short nodeType = area.ReadInt2(); // The version short ver = area.ReadInt2(); if (nodeType == StoreLeafType) { // Read the reference count, long refCount = area.ReadInt4(); // The number of bytes in the leaf int leafSize = area.ReadInt4(); // Set up the leaf node object node = new TreeReportNode("leaf", id); node.SetProperty("VER", ver); node.SetProperty("key", leftKey.ToString()); node.SetProperty("reference_count", refCount); node.SetProperty("leaf_size", leafSize); } else if (nodeType == StoreBranchType) { // The data size area containing the children information int childDataSize = area.ReadInt4(); long[] dataArr = new long[childDataSize]; for (int i = 0; i < childDataSize; ++i) { dataArr[i] = area.ReadInt8(); } // Create the TreeBranch object to query it TreeBranch branch = new TreeBranch(id, dataArr, childDataSize); // Set up the branch node object node = new TreeReportNode("branch", id); node.SetProperty("VER", ver); node.SetProperty("key", leftKey.ToString()); node.SetProperty("branch_size", branch.ChildCount); // Recursively add each child into the tree for (int i = 0; i < branch.ChildCount; ++i) { NodeId childId = branch.GetChild(i); // If the id is a special node, skip it if (childId.IsSpecial) { // Should we record special nodes? } else { Key newLeftKey = (i > 0) ? branch.GetKey(i) : leftKey; TreeReportNode bn = new TreeReportNode("child_meta", id); bn.SetProperty("extent", branch.GetChildLeafElementCount(i)); node.ChildNodes.Add(bn); node.ChildNodes.Add(CreateDiagnosticRootGraph(newLeftKey, childId)); } } } else { throw new IOException("Unknown node type: " + nodeType); } return node; }
internal HeapTreeBranch(ITransaction tran, long nodeId, TreeBranch branch, int maxChildren) : base(nodeId, branch, maxChildren) { this.tran = tran; }
public IList <NodeId> Persist(TreeWrite write) { try { nodeStore.LockForWrite(); IList <ITreeNode> allBranches = write.BranchNodes; IList <ITreeNode> allLeafs = write.LeafNodes; List <ITreeNode> nodes = new List <ITreeNode>(allBranches.Count + allLeafs.Count); nodes.AddRange(allBranches); nodes.AddRange(allLeafs); // The list of nodes to be allocated, int sz = nodes.Count; // The list of allocated referenced for the nodes, NodeId[] refs = new NodeId[sz]; // The list of area writers, IAreaWriter[] writers = new IAreaWriter[sz]; // Allocate the space first, for (int i = 0; i < sz; ++i) { ITreeNode node = nodes[i]; // Is it a branch node? if (node is TreeBranch) { TreeBranch branch = (TreeBranch)node; int ndsz = branch.NodeDataSize; writers[i] = nodeStore.CreateArea(4 + 4 + (ndsz * 8)); } // Otherwise, it must be a leaf node, else { TreeLeaf leaf = (TreeLeaf)node; int lfsz = leaf.Length; writers[i] = nodeStore.CreateArea(12 + lfsz); } // Set the reference, refs[i] = FromInt64StoreAddress(writers[i].Id); } // Now write out the data, for (int i = 0; i < sz; ++i) { ITreeNode node = nodes[i]; // Is it a branch node? if (node is TreeBranch) { TreeBranch branch = (TreeBranch)node; // The number of children int chsz = branch.ChildCount; // For each child, if it's a heap node, look up the child id and // reference map in the sequence and set the reference accordingly, for (int o = 0; o < chsz; ++o) { NodeId childId = branch.GetChild(o); if (childId.IsInMemory) { // The ref is currently on the heap, so adjust accordingly int refId = write.LookupRef(i, o); branch.SetChild(refs[refId], o); } } // Write out the branch to the store long[] nodeData = branch.NodeData; int ndsz = branch.NodeDataSize; IAreaWriter writer = writers[i]; writer.WriteInt2(StoreBranchType); writer.WriteInt2(1); // version writer.WriteInt4(ndsz); for (int o = 0; o < ndsz; ++o) { writer.WriteInt8(nodeData[o]); } writer.Finish(); // Make this into a branch node and add to the cache, branch = new TreeBranch(refs[i], nodeData, ndsz); // Put this branch in the cache, lock (branchCache) { branchCache.Set(refs[i], branch); } } // Otherwise, it must be a leaf node, else { TreeLeaf leaf = (TreeLeaf)node; IAreaWriter writer = writers[i]; writer.WriteInt2(StoreLeafType); writer.WriteInt2(1); // version writer.WriteInt4(1); // reference count writer.WriteInt4(leaf.Length); leaf.WriteTo(writer); writer.Finish(); } } return(refs); } finally { nodeStore.UnlockForWrite(); } }
private TreeReportNode CreateDiagnosticRootGraph(Key leftKey, NodeId id) { // The node being returned TreeReportNode node; // Open the area IArea area = nodeStore.GetArea(ToInt64StoreAddress(id)); // What type of node is this? short nodeType = area.ReadInt2(); // The version short ver = area.ReadInt2(); if (nodeType == StoreLeafType) { // Read the reference count, long refCount = area.ReadInt4(); // The number of bytes in the leaf int leafSize = area.ReadInt4(); // Set up the leaf node object node = new TreeReportNode("leaf", id); node.SetProperty("VER", ver); node.SetProperty("key", leftKey.ToString()); node.SetProperty("reference_count", refCount); node.SetProperty("leaf_size", leafSize); } else if (nodeType == StoreBranchType) { // The data size area containing the children information int childDataSize = area.ReadInt4(); long[] dataArr = new long[childDataSize]; for (int i = 0; i < childDataSize; ++i) { dataArr[i] = area.ReadInt8(); } // Create the TreeBranch object to query it TreeBranch branch = new TreeBranch(id, dataArr, childDataSize); // Set up the branch node object node = new TreeReportNode("branch", id); node.SetProperty("VER", ver); node.SetProperty("key", leftKey.ToString()); node.SetProperty("branch_size", branch.ChildCount); // Recursively add each child into the tree for (int i = 0; i < branch.ChildCount; ++i) { NodeId childId = branch.GetChild(i); // If the id is a special node, skip it if (childId.IsSpecial) { // Should we record special nodes? } else { Key newLeftKey = (i > 0) ? branch.GetKey(i) : leftKey; TreeReportNode bn = new TreeReportNode("child_meta", id); bn.SetProperty("extent", branch.GetChildLeafElementCount(i)); node.ChildNodes.Add(bn); node.ChildNodes.Add(CreateDiagnosticRootGraph(newLeftKey, childId)); } } } else { throw new IOException("Unknown node type: " + nodeType); } return(node); }
public long Create() { if (initialized) { throw new InvalidOperationException("This tree store is already initialized."); } // Temporary node heap for creating a starting database TreeNodeHeap nodeHeap = new TreeNodeHeap(17, 4 * 1024 * 1024); // Write a root node to the store, // Create an empty head node TreeLeaf headLeaf = nodeHeap.CreateLeaf(null, Key.Head, 256); // Insert a tree identification pattern headLeaf.Write(0, new byte[] { 1, 1, 1, 1 }, 0, 4); // Create an empty tail node TreeLeaf tailLeaf = nodeHeap.CreateLeaf(null, Key.Tail, 256); // Insert a tree identification pattern tailLeaf.Write(0, new byte[] { 1, 1, 1, 1 }, 0, 4); // The write sequence, TreeWrite seq = new TreeWrite(); seq.NodeWrite(headLeaf); seq.NodeWrite(tailLeaf); IList <NodeId> refs = Persist(seq); // Create a branch, TreeBranch rootBranch = nodeHeap.CreateBranch(null, MaxBranchSize); rootBranch.Set(refs[0], 4, Key.Tail, refs[1], 4); seq = new TreeWrite(); seq.NodeWrite(rootBranch); refs = Persist(seq); // The written root node reference, NodeId rootId = refs[0]; // Delete the head and tail leaf, and the root branch nodeHeap.Delete(headLeaf.Id); nodeHeap.Delete(tailLeaf.Id); nodeHeap.Delete(rootBranch.Id); // Write this version info to the store, long versionId = WriteSingleVersionInfo(1, rootId, new List <NodeId>(0)); // Make a first version VersionInfo versionInfo = new VersionInfo(1, rootId, versionId); versions.Add(versionInfo); // Flush this to the version list IAreaWriter versionList = nodeStore.CreateArea(64); versionList.WriteInt4(0x01433); versionList.WriteInt4(1); versionList.WriteInt8(versionId); versionList.Finish(); // Get the versions id long versionListId = versionList.Id; // The final header IAreaWriter header = nodeStore.CreateArea(64); header.WriteInt4(0x09391); // The magic value, header.WriteInt4(1); // The version header.WriteInt8(versionListId); header.Finish(); // Set up the internal variables, headerId = header.Id; initialized = true; // And return the header reference return(headerId); }
public Key Merge(TreeBranch right, Key midValue) { // Check mutable CheckReadOnly(); right.CheckReadOnly(); // How many elements in total? int totalElements = ChildCount + right.ChildCount; // If total elements is smaller than max size, if (totalElements <= MaxChildCount) { // Move all the elements into this node, int destP = childrenCount * 5; int rightLen = (right.childrenCount * 5) - 2; Array.Copy(right.children, 0, children, destP, rightLen); children[destP - 2] = midValue.GetEncoded(1); children[destP - 1] = midValue.GetEncoded(2); // Update children_count childrenCount += right.childrenCount; right.childrenCount = 0; return(null); } else { long newMidpointValue1, newMidpointValue2; // Otherwise distribute between the nodes, int maxShift = (MaxChildCount + right.MaxChildCount) - totalElements; if (maxShift <= 2) { return(midValue); } int minThreshold = MaxChildCount / 2; if (ChildCount < right.ChildCount) { // Shift elements from right to left // The amount to move that will leave the right node at min threshold int count = Math.Min(right.ChildCount - minThreshold, maxShift); int destP = ChildCount * 5; int rightLen = (count * 5) - 2; Array.Copy(right.children, 0, children, destP, rightLen); // Redistribute the right elements int rightRedist = (count * 5); // The midpoint value becomes the extent shifted off the end newMidpointValue1 = right.children[rightRedist - 2]; newMidpointValue2 = right.children[rightRedist - 1]; // Shift the right child Array.Copy(right.children, rightRedist, right.children, 0, right.children.Length - rightRedist); children[destP - 2] = midValue.GetEncoded(1); children[destP - 1] = midValue.GetEncoded(2); childrenCount += count; right.childrenCount -= count; } else { // Shift elements from left to right // The amount to move that will leave the left node at min threshold int count = Math.Min(ChildCount - minThreshold, maxShift); // Make room for these elements int rightRedist = (count * 5); Array.Copy(right.children, 0, right.children, rightRedist, right.children.Length - rightRedist); int srcP = (ChildCount - count) * 5; int leftLen = (count * 5) - 2; Array.Copy(children, srcP, right.children, 0, leftLen); right.children[rightRedist - 2] = midValue.GetEncoded(1); right.children[rightRedist - 1] = midValue.GetEncoded(2); // The midpoint value becomes the extent shifted off the end newMidpointValue1 = children[srcP - 2]; newMidpointValue2 = children[srcP - 1]; // Update children counts childrenCount -= count; right.childrenCount += count; } return(new Key(newMidpointValue1, newMidpointValue2)); } }
public TreeBranch(NodeId nodeId, TreeBranch branch, int maxChildrenCount) : this(nodeId, maxChildrenCount) { Array.Copy(branch.children, 0, children, 0, Math.Min(branch.children.Length, children.Length)); childrenCount = branch.ChildCount; }
public Key Merge(TreeBranch right, Key midValue) { // Check mutable CheckReadOnly(); right.CheckReadOnly(); // How many elements in total? int totalElements = ChildCount + right.ChildCount; // If total elements is smaller than max size, if (totalElements <= MaxChildCount) { // Move all the elements into this node, int destP = childrenCount*5; int rightLen = (right.childrenCount*5) - 2; Array.Copy(right.children, 0, children, destP, rightLen); children[destP - 2] = midValue.GetEncoded(1); children[destP - 1] = midValue.GetEncoded(2); // Update children_count childrenCount += right.childrenCount; right.childrenCount = 0; return null; } else { long newMidpointValue1, newMidpointValue2; // Otherwise distribute between the nodes, int maxShift = (MaxChildCount + right.MaxChildCount) - totalElements; if (maxShift <= 2) return midValue; int minThreshold = MaxChildCount/2; if (ChildCount < right.ChildCount) { // Shift elements from right to left // The amount to move that will leave the right node at min threshold int count = Math.Min(right.ChildCount - minThreshold, maxShift); int destP = ChildCount*5; int rightLen = (count*5) - 2; Array.Copy(right.children, 0, children, destP, rightLen); // Redistribute the right elements int rightRedist = (count*5); // The midpoint value becomes the extent shifted off the end newMidpointValue1 = right.children[rightRedist - 2]; newMidpointValue2 = right.children[rightRedist - 1]; // Shift the right child Array.Copy(right.children, rightRedist, right.children, 0, right.children.Length - rightRedist); children[destP - 2] = midValue.GetEncoded(1); children[destP - 1] = midValue.GetEncoded(2); childrenCount += count; right.childrenCount -= count; } else { // Shift elements from left to right // The amount to move that will leave the left node at min threshold int count = Math.Min(ChildCount - minThreshold, maxShift); // Make room for these elements int rightRedist = (count*5); Array.Copy(right.children, 0, right.children, rightRedist, right.children.Length - rightRedist); int srcP = (ChildCount - count)*5; int leftLen = (count*5) - 2; Array.Copy(children, srcP, right.children, 0, leftLen); right.children[rightRedist - 2] = midValue.GetEncoded(1); right.children[rightRedist - 1] = midValue.GetEncoded(2); // The midpoint value becomes the extent shifted off the end newMidpointValue1 = children[srcP - 2]; newMidpointValue2 = children[srcP - 1]; // Update children counts childrenCount -= count; right.childrenCount += count; } return new Key(newMidpointValue1, newMidpointValue2); } }
private ITreeNode FetchNode(NodeId nodeId) { // Is it a special static node? if (nodeId.IsSpecial) { return SpecialStaticNode(nodeId); } // Is this a branch node in the cache? NodeId cacheKey = nodeId; TreeBranch branch; lock (branchCache) { branch = (TreeBranch) branchCache.Get(cacheKey); if (branch != null) { return branch; } } // Not found in the cache, so fetch the area from the backing store and // create the node type. // Get the area for the node IArea nodeArea = nodeStore.GetArea(ToInt64StoreAddress(nodeId)); // Wrap around a buffered BinaryRader for reading values from the store. BinaryReader input = new BinaryReader(new AreaInputStream(nodeArea, 256)); short nodeType = input.ReadInt16(); // Is the node type a leaf node? if (nodeType == StoreLeafType) { // Read the key input.ReadInt16(); // version input.ReadInt32(); // reference count int leafSize = input.ReadInt32(); // Return a leaf that's mapped to the data in the store nodeArea.Position = 0; return new AreaTreeLeaf(nodeId, leafSize, nodeArea); } // Is the node type a branch node? if (nodeType == StoreBranchType) { // Note that the entire branch is loaded into memory now, input.ReadInt16(); // version int childDataSize = input.ReadInt32(); long[] dataArr = new long[childDataSize]; for (int i = 0; i < childDataSize; ++i) { dataArr[i] = input.ReadInt64(); } branch = new TreeBranch(nodeId, dataArr, childDataSize); // Put this branch in the cache, lock (branchCache) { branchCache.Set(cacheKey, branch); // And return the branch return branch; } } throw new ApplicationException("Unknown node type: " + nodeType); }
public void InsertLeaf(Key newLeafKey, TreeLeaf newLeaf, bool before) { int leafSize = newLeaf.Length; if (leafSize <= 0) { throw new ArgumentException("size <= 0"); } // The current absolute position and key Key newKey = newLeafKey; // The frame at the end of the stack, StackFrame frame = StackEnd(0); object[] info; object[] rInfo = new object[5]; Key leftKey; long curAbsolutePos; // If we are inserting the new leaf after, if (!before) { info = new object[] { currentLeaf.Id, (long)currentLeaf.Length, newLeafKey, newLeaf.Id, (long)newLeaf.Length }; leftKey = null; curAbsolutePos = frame.Offset + currentLeaf.Length; } // Otherwise we are inserting the new leaf before, else { // If before and current_leaf key is different than new_leaf key, we // generate an error if (!currentLeafKey.Equals(newLeafKey)) { throw new InvalidOperationException("Can't insert different new key before."); } info = new Object[] { newLeaf.Id, (long)newLeaf.Length, currentLeafKey, currentLeaf.Id, (long)currentLeaf.Length }; leftKey = newLeafKey; curAbsolutePos = frame.Offset - 1; } bool insertTwoNodes = true; int sz = FrameCount; // Walk the stack from the end for (int i = 1; i < sz; ++i) { // child_i is the previous frame's child_i int childIndex = frame.ChildIndex; frame = StackEnd(i); // The child ref of this stack element NodeId childId = frame.NodeId; // Fetch it TreeBranch branch = (TreeBranch)UnfreezeNode(FetchNode(childId)); // Do we have two nodes to insert into the branch? if (insertTwoNodes) { TreeBranch insertBranch; int insertIndex = childIndex; // If the branch is full, if (branch.IsFull) { // Create a new node, TreeBranch leftBranch = branch; TreeBranch rightBranch = CreateBranch(); // Split the branch, Key midpointKey = leftBranch.MidPointKey; // And move half of this branch into the new branch leftBranch.MoveLastHalfInto(rightBranch); // We split so we need to return a split flag, rInfo[0] = leftBranch.Id; rInfo[1] = leftBranch.LeafElementCount; rInfo[2] = midpointKey; rInfo[3] = rightBranch.Id; rInfo[4] = rightBranch.LeafElementCount; // Adjust insert_n and insert_branch if (insertIndex >= leftBranch.ChildCount) { insertIndex -= leftBranch.ChildCount; insertBranch = rightBranch; rInfo[4] = (long)rInfo[4] + newLeaf.Length; // If insert_n == 0, we change the midpoint value to the left // key value, if (insertIndex == 0 && leftKey != null) { rInfo[2] = leftKey; leftKey = null; } } else { insertBranch = leftBranch; rInfo[1] = (long)rInfo[1] + newLeaf.Length; } } // If it's not full, else { insertBranch = branch; rInfo[0] = insertBranch.Id; insertTwoNodes = false; } // Insert the two children nodes insertBranch.Insert((NodeId)info[0], (long)info[1], (Key)info[2], (NodeId)info[3], (long)info[4], insertIndex); // Copy r_nfo to nfo for (int p = 0; p < rInfo.Length; ++p) { info[p] = rInfo[p]; } // Adjust the left key reference if necessary if (leftKey != null && insertIndex > 0) { insertBranch.SetKeyToLeft(leftKey, insertIndex); leftKey = null; } } else { branch.SetChild((NodeId)info[0], childIndex); info[0] = branch.Id; branch.SetChildLeafElementCount( branch.GetChildLeafElementCount(childIndex) + leafSize, childIndex); // Adjust the left key reference if necessary if (leftKey != null && childIndex > 0) { branch.SetKeyToLeft(leftKey, childIndex); leftKey = null; } } } // For all elements in the stack, // At the end, if we still have a split then we make a new root and // adjust the stack accordingly if (insertTwoNodes) { TreeBranch newRoot = CreateBranch(); newRoot.Set((NodeId)info[0], (long)info[1], (Key)info[2], (NodeId)info[3], (long)info[4]); RootNodeId = newRoot.Id; if (TreeHeight != -1) { TreeHeight = TreeHeight + 1; } } else { RootNodeId = (NodeId)info[0]; } // Now reset the position, Reset(); SetupForPosition(newKey, curAbsolutePos); }
public void MoveLastHalfInto(TreeBranch dest) { int midpoint = children.Length/2; // Check mutable CheckReadOnly(); dest.CheckReadOnly(); // Check this is full if (!IsFull) throw new InvalidOperationException("Branch node is not full."); // Check destination is empty if (!dest.IsEmpty) throw new ArgumentException("Destination branch node is not empty."); // Copy, Array.Copy(children, midpoint + 1, dest.children, 0, midpoint - 1); // New child count in each branch node. int newChildCount = MaxChildCount/2; // Set the size of this and the destination node childrenCount = newChildCount; dest.childrenCount = newChildCount; }
public void SetupForPosition(Key key, long posit) { // If the current leaf is set if (currentLeaf != null) { StackFrame frame = StackEnd(0); long leafStart = frame.Offset; long leafEnd = leafStart + currentLeaf.Length; // If the position is at the leaf end, or if the keys aren't equal, we // need to reset the stack. This ensures that we correctly place the // pointer. if (!key.Equals(Key.Tail) && (posit == leafEnd || !key.Equals(currentLeafKey))) { StackClear(); currentLeaf = null; currentLeafKey = null; } else { // Check whether the position is within the bounds of the current leaf // If 'posit' is within this leaf if (posit >= leafStart && posit < leafEnd) { // If the position is within the current leaf, set up the internal // vars as necessary. leafOffset = (int)(posit - leafStart); return; } // If it's not, we reset the stack and start fresh, StackClear(); currentLeaf = null; currentLeafKey = null; } } // ISSUE: It appears looking at the code above, the stack will always be // empty and current_leaf will always be null if we get here. // If the stack is empty, push the root node, if (StackEmpty) { // Push the root node onto the top of the stack. StackPush(-1, 0, RootNodeId); // Set up the current_leaf_key to the default value currentLeafKey = Key.Head; } // Otherwise, we need to setup by querying the BTree. while (true) { if (StackEmpty) { throw new ApplicationException("Position out of bounds. p = " + posit); } // Pop the last stack frame, StackFrame frame = StackPop(); NodeId nodePointer = frame.NodeId; long leftSideOffset = frame.Offset; int nodeChildIndex = frame.ChildIndex; // Relative offset within this node long relativeOffset = posit - leftSideOffset; // If the node is not on the heap, if (!IsHeapNode(nodePointer)) { // The node is not on the heap. We optimize here. // If we know the node is going to be a leaf node, we set up a // temporary leaf node object with as much information as we know. // Check if we know this is a leaf int treeHeight = TreeHeight; if (treeHeight != -1 && (stackSize / StackFrameSize) + 1 == treeHeight) { // Fetch the parent node, frame = StackEnd(0); NodeId twigNodePointer = frame.NodeId; TreeBranch twig = (TreeBranch)FetchNode(twigNodePointer); long leafSize = twig.GetChildLeafElementCount(nodeChildIndex); // This object holds off fetching the contents of the leaf node // unless it's absolutely required. TreeLeaf leaf = new PlaceholderLeaf(ts, nodePointer, (int)leafSize); currentLeaf = leaf; StackPush(nodeChildIndex, leftSideOffset, nodePointer); // Set up the leaf offset and return leafOffset = (int)relativeOffset; return; } } // Fetch the node ITreeNode node = FetchNode(nodePointer); if (node is TreeLeaf) { // Node is a leaf node TreeLeaf leaf = (TreeLeaf)node; currentLeaf = leaf; StackPush(nodeChildIndex, leftSideOffset, nodePointer); // Set up the leaf offset and return leafOffset = (int)relativeOffset; // Update the tree_height value, TreeHeight = stackSize / StackFrameSize; return; } // Node is a branch node TreeBranch branch = (TreeBranch)node; int childIndex = branch.IndexOfChild(key, relativeOffset); if (childIndex != -1) { // Push the current details, StackPush(nodeChildIndex, leftSideOffset, nodePointer); // Found child so push the details StackPush(childIndex, branch.GetChildOffset(childIndex) + leftSideOffset, branch.GetChild(childIndex)); // Set up the left key if (childIndex > 0) { currentLeafKey = branch.GetKey(childIndex); } } } // while (true) }
private bool RedistributeBranchElements(TreeBranch branch, int childIndex, TreeBranch child) { // We distribute the nodes in the child branch with the branch // immediately to the right. If that's not possible, then we distribute // with the left. // If branch has only a single value, return immediately int branchSize = branch.ChildCount; if (branchSize == 1) { return false; } int leftI, rightI; TreeBranch left, right; if (childIndex < branchSize - 1) { // Distribute with the right leftI = childIndex; rightI = childIndex + 1; left = child; right = (TreeBranch)UnfreezeNode(FetchNode(branch.GetChild(childIndex + 1))); branch.SetChild(right.Id, childIndex + 1); } else { // Distribute with the left leftI = childIndex - 1; rightI = childIndex; left = (TreeBranch)UnfreezeNode(FetchNode(branch.GetChild(childIndex - 1))); right = child; branch.SetChild(left.Id, childIndex - 1); } // Get the mid value key reference Key midKey = branch.GetKey(rightI); // Perform the merge, Key newMidKey = left.Merge(right, midKey); // Reset the leaf element count branch.SetChildLeafElementCount(left.LeafElementCount, leftI); branch.SetChildLeafElementCount(right.LeafElementCount, rightI); // If after the merge the right branch is empty, we need to remove it if (right.IsEmpty) { // Delete the node DeleteNode(right.Id); // And remove it from the branch, branch.RemoveChild(rightI); return true; } // Otherwise set the key reference branch.SetKeyToLeft(newMidKey, rightI); return false; }
public HeapTreeBranch(TreeSystemTransaction transaction, NodeId nodeId, TreeBranch branch, int maxChildrenCount) : base(nodeId, branch, maxChildrenCount) { this.transaction = transaction; }
public Key Merge(TreeBranch right, Key midValue) { CheckReadOnly(); right.CheckReadOnly(); // How many elements in total? int total_elements = ChildCount + right.ChildCount; // If total elements is smaller than max size, if (total_elements <= MaxSize) { // Move all the elements into this node, int dest_p = childCount * 4; int right_len = (right.childCount * 4) - 2; Array.Copy(right.children, 0, children, dest_p, right_len); children[dest_p - 2] = midValue.GetEncoded(1); children[dest_p - 1] = midValue.GetEncoded(2); // Update children_count childCount += right.childCount; right.childCount = 0; return null; } else { long new_midpoint_value1, new_midpoint_value2; // Otherwise distribute between the nodes, int max_shift = (MaxSize + right.MaxSize) - total_elements; if (max_shift <= 2) { return midValue; } int min_threshold = MaxSize / 2; // final int half_total_elements = total_elements / 2; if (ChildCount < right.ChildCount) { // Shift elements from right to left // The amount to move that will leave the right node at min threshold int count = Math.Min(right.ChildCount - min_threshold, max_shift); int dest_p = ChildCount * 4; int right_len = (count * 4) - 2; Array.Copy(right.children, 0, children, dest_p, right_len); // Redistribute the right elements int right_redist = (count * 4); // The midpoint value becomes the extent shifted off the end new_midpoint_value1 = right.children[right_redist - 2]; new_midpoint_value2 = right.children[right_redist - 1]; // Shift the right child Array.Copy(right.children, right_redist, right.children, 0, right.children.Length - right_redist); children[dest_p - 2] = midValue.GetEncoded(1); children[dest_p - 1] = midValue.GetEncoded(2); childCount += count; right.childCount -= count; } else { // Shift elements from left to right // The amount to move that will leave the left node at min threshold int count = Math.Min(MaxSize - min_threshold, max_shift); // int count = Math.min(half_total_elements - right.size(), max_shift); // Make room for these elements int right_redist = (count * 4); Array.Copy(right.children, 0, right.children, right_redist, right.children.Length - right_redist); int src_p = (ChildCount - count) * 4; int left_len = (count * 4) - 2; Array.Copy(children, src_p, right.children, 0, left_len); right.children[right_redist - 2] = midValue.GetEncoded(1); right.children[right_redist - 1] = midValue.GetEncoded(2); // The midpoint value becomes the extent shifted off the end new_midpoint_value1 = children[src_p - 2]; new_midpoint_value2 = children[src_p - 1]; // Update children counts childCount -= count; right.childCount += count; } return new Key(new_midpoint_value1, new_midpoint_value2); } }