public TreeBranch(NodeId nodeId, long[] data, int dataSize) { if (nodeId.IsInMemory) throw new ArgumentException("Only store nodes permitted."); this.nodeId = nodeId; children = data; childrenCount = (dataSize + 2)/5; }
public TreeSystemTransaction(ITreeSystem treeStore, long versionId, NodeId rootNodeId, bool readOnly) { this.treeStore = treeStore; this.rootNodeId = rootNodeId; this.versionId = versionId; updateVersion = 0; nodeDeletes = null; nodeInserts = null; this.readOnly = readOnly; disposed = false; }
public TreeBranch(NodeId nodeId, int maxChildrenCount) { if (!nodeId.IsInMemory) throw new ArgumentException("Only heap node permitted."); if ((maxChildrenCount%2) != 0) throw new ArgumentException("max_children_count must be a multiple of 2."); if (maxChildrenCount > 65530) throw new ArgumentException("Branch children count is limited to 65530"); if (maxChildrenCount < 6) // While I did test with 4, tree balancing is rather tough at 4 so we // should have this at at least 6. throw new ArgumentException("max_children_count must be >= 6"); this.nodeId = nodeId; children = new long[(maxChildrenCount*5) - 2]; childrenCount = 0; }
internal void FlushNodesToStore(NodeId[] nodeIds) { // If not disposed, if (!disposed) { // Compact the entire tree object[] mergeBuffer = new object[5]; CompactNode(Key.Head, RootNodeId, mergeBuffer, Key.Head, Key.Tail); // Flush the reference node list, RootNodeId = (FlushNodes(RootNodeId, nodeIds)); // Update the version so any data file objects will flush with the // changes. ++updateVersion; // Check out the changes treeStore.CheckPoint(); } }
internal bool IsHeapNode(NodeId nodeId) { return nodeId.IsInMemory; }
private int PopulateSequence(NodeId id, TreeWrite sequence) { // If it's not a heap node, return if (!IsHeapNode(id)) return -1; // It is a heap node, so fetch ITreeNode node = FetchNode(id); // Is it a leaf or a branch? if (node is TreeLeaf) // If it's a leaf, simply write it out return sequence.NodeWrite(node); if (node is TreeBranch) { // This is a branch, // Sequence this branch to be written out, int branchId = sequence.NodeWrite(node); // For each child in the branch, TreeBranch branch = (TreeBranch) node; int sz = branch.ChildCount; for (int i = 0; i < sz; ++i) { NodeId child = branch.GetChild(i); // Sequence the child int childId = PopulateSequence(child, sequence); // If something could be sequenced in the child, if (childId != -1) { // Make the branch command, sequence.BranchLink(branchId, i, childId); } } // Return the id of the branch in the sequence, return branchId; } else { throw new ApplicationException("Unknown node type."); } }
public AreaTreeLeaf(NodeId nodeId, int leafSize, IArea area) { this.nodeId = nodeId; this.leafSize = leafSize; this.area = area; }
internal void SetChild(NodeId childPointer, int n) { CheckReadOnly(); SetChildOverride(childPointer, n); }
private void LogStoreChange(byte type, NodeId pointer) { if (!treeStore.NotifyNodeChanged) return; // Special node type changes are not logged if (pointer.IsSpecial) return; if (type == 0) { // This type is for deleted nodes, NodeDeletes.Add(pointer); } else if (type == 1) { // This type is for inserts, NodeInserts.Add(pointer); } else { throw new ApplicationException("Incorrect type"); } }
public TreeReportNode CreateDiagnosticGraph() { CheckErrorState(); // Create the header node TreeReportNode headerNode = new TreeReportNode("header", headerId); // Get the header area IArea headerArea = nodeStore.GetArea(headerId); headerArea.Position = 8; // Read the versions list, long versionListRef = headerArea.ReadInt8(); // Create the version node TreeReportNode versionsNode = new TreeReportNode("versions list", versionListRef); // Set this as a child to the header headerNode.ChildNodes.Add(versionsNode); // Read the versions list area // magic(int), versions count(int), list of version id objects. IArea versionsArea = nodeStore.GetArea(versionListRef); if (versionsArea.ReadInt4() != 0x01433) { throw new IOException("Incorrect magic value 0x01433"); } int versCount = versionsArea.ReadInt4(); // For each id from the versions area, read in the associated VersionInfo // object into the 'vers' array. for (int i = 0; i < versCount; ++i) { long vInfoRef = versionsArea.ReadInt8(); // Set up the information in our node TreeReportNode vInfoNode = new TreeReportNode("version", vInfoRef); // Read in the version information node IArea vInfoArea = nodeStore.GetArea(vInfoRef); int magic = vInfoArea.ReadInt4(); int ver = vInfoArea.ReadInt4(); long versionId = vInfoArea.ReadInt8(); long rnrHigh = vInfoArea.ReadInt8(); long rnrLow = vInfoArea.ReadInt8(); NodeId rootNodeId = new NodeId(rnrHigh, rnrLow); vInfoNode.SetProperty("MAGIC", magic); vInfoNode.SetProperty("VER", ver); vInfoNode.SetProperty("version_id", versionId); // Make the deleted area list into a property int deletedAreaCount = vInfoArea.ReadInt4(); if (deletedAreaCount > 0) { for (int n = 0; n < deletedAreaCount; ++n) { long delnHigh = vInfoArea.ReadInt8(); long delnLow = vInfoArea.ReadInt8(); NodeId delNodeId = new NodeId(delnHigh, delnLow); vInfoNode.ChildNodes.Add(new TreeReportNode("delete", delNodeId)); } } // Add the child node (the root node of the version graph). vInfoNode.ChildNodes.Add(CreateDiagnosticRootGraph(Key.Head, rootNodeId)); // Add this to the version list node versionsNode.ChildNodes.Add(vInfoNode); } // Return the header node return(headerNode); }
private Object[] DeleteFromLeaf(long leftOffset, NodeId leaf, long startPos, long endPos, Key inLeftKey) { Debug.Assert(startPos < endPos); TreeLeaf treeLeaf = (TreeLeaf) UnfreezeNode(FetchNode(leaf)); const int leafStart = 0; int leafEnd = treeLeaf.Length; int delStart = (int) Math.Max(startPos - leftOffset, (long) leafStart); int delEnd = (int) Math.Min(endPos - leftOffset, (long) leafEnd); int removeAmount = delEnd - delStart; // Remove from the end point, treeLeaf.Shift(delEnd, -removeAmount); return new object[] { treeLeaf.Id, (long) removeAmount, inLeftKey, false }; }
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 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); }
internal static ITreeNode SpecialStaticNode(NodeId nodeId) { return(nodeId.CreateSpecialTreeNode()); }
private void DisposeOldVersions() { List <object> disposeList = new List <object>(); lock (versions) { // size - 1 because we don't want to delete the very last version, int sz = versions.Count - 1; bool foundLockedEntry = false; for (int i = 0; i < sz && foundLockedEntry == false; ++i) { VersionInfo vinfo = versions[i]; // If this version isn't locked, if (vinfo.NotLocked) { // Add to the dispose list disposeList.Add(vinfo); // And delete from the versions list, versions.RemoveAt(i); --sz; --i; } else { // If it is locked, we exit the loop foundLockedEntry = true; } } } // If there are entries to dispose? if (disposeList.Count > 0) { // We synchronize here to ensure the versions list can't be modified by // a commit operation while we are disposing this. lock (this) { // Run within a write lock on the store try { nodeStore.LockForWrite(); // First we write out a modified version header minus the versions we // are to delete, // Get the current version list IMutableArea headerArea = nodeStore.GetMutableArea(headerId); headerArea.Position = 8; long versionListId = headerArea.ReadInt8(); // Read information from the old version info, IArea versionListArea = nodeStore.GetArea(versionListId); versionListArea.ReadInt4(); // The magic int versionCount = versionListArea.ReadInt4(); int newVersionCount = versionCount - disposeList.Count; // Create a new list, IAreaWriter newVersionList = nodeStore.CreateArea(8 + (8 * newVersionCount)); newVersionList.WriteInt4(0x01433); newVersionList.WriteInt4(newVersionCount); // Skip the versions we are deleting, for (int i = 0; i < disposeList.Count; ++i) { versionListArea.ReadInt8(); } // Now copy the list from the new point for (int i = 0; i < newVersionCount; ++i) { newVersionList.WriteInt8(versionListArea.ReadInt8()); } newVersionList.Finish(); // Write the new area to the header, headerArea.Position = 8; headerArea.WriteInt8(newVersionList.Id); // Delete the old version list Area, nodeStore.DeleteArea(versionListId); // Dispose the version info, int sz = disposeList.Count; for (int i = 0; i < sz; ++i) { VersionInfo vinfo = (VersionInfo)disposeList[i]; long vRef = vinfo.VersionInfoRef; IArea versionArea = nodeStore.GetArea(vRef); int magic = versionArea.ReadInt4(); int rev = versionArea.ReadInt4(); // Check the magic, if (magic != 0x04EA23) { throw new ApplicationException("Magic value for version area is incorrect."); } long verId = versionArea.ReadInt8(); long nrnHigh = versionArea.ReadInt8(); long nrnLow = versionArea.ReadInt8(); int nodeCount = versionArea.ReadInt4(); // For each node, for (int n = 0; n < nodeCount; ++n) { // Read the next area long drnHigh = versionArea.ReadInt8(); long drnLow = versionArea.ReadInt8(); NodeId delNodeId = new NodeId(drnHigh, drnLow); // Cleanly disposes the node DoDisposeNode(delNodeId); } // Delete the node header, nodeStore.DeleteArea(vRef); } } finally { nodeStore.UnlockForWrite(); } } } }
private long WriteVersionsList(long versionId, TreeSystemTransaction tran) { lock (this) { // Write the version info and the deleted refs to a new area, NodeId rootNodeId = tran.RootNodeId; if (rootNodeId.IsInMemory) { throw new ApplicationException("Assertion failed, root_node is on heap."); } // Get the list of all nodes deleted in the transaction List <NodeId> deletedRefs = tran.NodeDeletes; // Sort it deletedRefs.Sort(); // Check for any duplicate entries (we shouldn't double delete stuff). for (int i = 1; i < deletedRefs.Count; ++i) { if (deletedRefs[i - 1].Equals(deletedRefs[i])) { // Oops, duplicated delete throw new ApplicationException("PRAGMATIC_CHECK failed: duplicate records in delete list."); } } long theVersionId = WriteSingleVersionInfo(versionId, rootNodeId, deletedRefs); // Now update the version list by copying the list and adding the new ref // to the end. // Get the current version list IMutableArea headerArea = nodeStore.GetMutableArea(headerId); headerArea.Position = 8; long versionListId = headerArea.ReadInt8(); // Read information from the old version info, IArea versionListArea = nodeStore.GetArea(versionListId); versionListArea.ReadInt4(); // The magic int versionCount = versionListArea.ReadInt4(); // Create a new list, IAreaWriter newVersionList = nodeStore.CreateArea(8 + (8 * (versionCount + 1))); newVersionList.WriteInt4(0x01433); newVersionList.WriteInt4(versionCount + 1); for (int i = 0; i < versionCount; ++i) { newVersionList.WriteInt8(versionListArea.ReadInt8()); } newVersionList.WriteInt8(theVersionId); newVersionList.Finish(); // Write the new area to the header, headerArea.Position = 8; headerArea.WriteInt8(newVersionList.Id); // Delete the old version list Area, nodeStore.DeleteArea(versionListId); // Done, return(theVersionId); } }
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; }
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); }
private void CompactNode(Key farLeft, NodeId id, object[] mergeBuffer, Key minBound, Key maxBound) { // If the ref is not on the heap, return the ref, if (!IsHeapNode(id)) return; // Fetch the node, ITreeNode node = FetchNode(id); // If the node is a leaf, return the ref, if (node is TreeLeaf) return; // If the node is a branch, if (node is TreeBranch) { // Cast to a branch TreeBranch branch = (TreeBranch) node; // We ask the node for the child sub-tree that will contain the range // of this key int firstChildI = branch.SearchFirst(minBound); int lastChildI = branch.SearchLast(maxBound); // first_child_i may be negative which means a key reference is equal // to the key being searched, in which case we follow the left branch. if (firstChildI < 0) { firstChildI = -(firstChildI + 1); } // Compact the children, for (int x = firstChildI; x <= lastChildI; ++x) { // Change far left to represent the new far left node Key newFarLeft = (x > 0) ? branch.GetKey(x) : farLeft; // We don't change max_bound because it's not necessary. CompactNode(newFarLeft, branch.GetChild(x), mergeBuffer, minBound, maxBound); } // The number of children in this branch, int sz = branch.ChildCount; // Now try and merge the compacted children, int i = firstChildI; // We must not let there be less than 3 children while (sz > 3 && i <= lastChildI - 1) { // The left and right children nodes, NodeId leftChildId = branch.GetChild(i); NodeId rightChildId = branch.GetChild(i + 1); // If at least one of them is a heap node we attempt to merge the // nodes, if (IsHeapNode(leftChildId) || IsHeapNode(rightChildId)) { // Set the left left key and right left key of the references, Key leftLeftKey = (i > 0) ? branch.GetKey(i) : farLeft; Key rightLeftKey = branch.GetKey(i + 1); // Attempt to merge the nodes, int nodeResult = MergeNodes(branch.GetKey(i + 1), leftChildId, rightChildId, leftLeftKey, rightLeftKey, mergeBuffer); // If we merged into a single node then we update the left and // delete the right if (nodeResult == 1) { branch.SetChild((NodeId) mergeBuffer[0], i); branch.SetChildLeafElementCount((long) mergeBuffer[1], i); branch.RemoveChild(i + 1); // Reduce the size but don't increase i, because we may want to // merge again. --sz; --lastChildI; } else if (nodeResult == 2) { // Two result but there was a change (the left was increased in // size) branch.SetChild((NodeId) mergeBuffer[0], i); branch.SetChildLeafElementCount((long) mergeBuffer[1], i); branch.SetKeyToLeft((Key) mergeBuffer[2], i + 1); branch.SetChild((NodeId) mergeBuffer[3], i + 1); branch.SetChildLeafElementCount((long) mergeBuffer[4], i + 1); ++i; } else { // Otherwise, no change so skip to the next child, ++i; } } // left or right are not nodes on the heap so go to next, else { ++i; } } } }
private long ToInt64StoreAddress(NodeId nodeId) { return(nodeId.Low); }
private ITreeNode FetchNodeIfLocallyAvailable(NodeId nodeId) { // If it's a heap node, if (IsHeapNode(nodeId)) { return FetchNode(nodeId); } // If the node is locally available, return it, if (treeStore.IsNodeAvailable(nodeId)) { return treeStore.FetchNodes(new NodeId[] {nodeId})[0]; } // Otherwise return null return null; }
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(); } }
public SparseLeafNode(NodeId nodeId, byte sparseByte, int leafSize) { this.nodeId = nodeId; this.leafSize = leafSize; this.sparseByte = sparseByte; }
private Object[] RecurseRemoveBranches(long leftOffset, int height, NodeId node, long startPos, long endPos, Key inLeftKey) { // Do we know if this is a leaf node? if (treeHeight == height) return DeleteFromLeaf(leftOffset, node, startPos, endPos, inLeftKey); // Fetch the node, ITreeNode treeNode = FetchNode(node); if (treeNode is TreeLeaf) { // Leaf reach, so set the tree height and return treeHeight = height; return DeleteFromLeaf(leftOffset, node, startPos, endPos, inLeftKey); } // The amount removed, long removeCount = 0; // This is a branch, TreeBranch treeBranch = (TreeBranch) treeNode; treeBranch = (TreeBranch) UnfreezeNode(treeBranch); Key parentLeftKey = inLeftKey; // Find all the children branches between the bounds, int childCount = treeBranch.ChildCount; long pos = leftOffset; for (int i = 0; i < childCount && pos < endPos; ++i) { long childNodeSize = treeBranch.GetChildLeafElementCount(i); long nextPos = pos + childNodeSize; // Test if start_pos/end_pos bounds intersects with this child, if (startPos < nextPos && endPos > pos) { // Yes, we intersect, // Make sure the branch is on the heap, NodeId childNode = treeBranch.GetChild(i); // If we intersect entirely remove the child from the branch, if (pos >= startPos && nextPos <= endPos) { // Delete the child tree, DeleteChildTree(height + 1, childNode); removeCount += childNodeSize; // If removing the first child, bubble up a new left_key if (i == 0) { parentLeftKey = treeBranch.GetKey(1); } // Otherwise parent left key doesn't change else { parentLeftKey = inLeftKey; } // Remove the child from the branch, treeBranch.RemoveChild(i); --i; --childCount; } else { // We don't intersect entirely, so recurse on this, // The left key Key rLeftKey = (i == 0) ? inLeftKey : treeBranch.GetKey(i); object[] rv = RecurseRemoveBranches(pos, height + 1, childNode, startPos, endPos, rLeftKey); NodeId newChildRef = (NodeId) rv[0]; long removedInChild = (long) rv[1]; Key childLeftKey = (Key) rv[2]; removeCount += removedInChild; // Update the child, treeBranch.SetChild(newChildRef, i); treeBranch.SetChildLeafElementCount(childNodeSize - removedInChild, i); if (i == 0) { parentLeftKey = childLeftKey; } else { treeBranch.SetKeyToLeft(childLeftKey, i); parentLeftKey = inLeftKey; } } } // Next child in the branch, pos = nextPos; } // Return the reference and remove count, bool parentRebalance = (treeBranch.ChildCount <= 2); return new Object[] { treeBranch.Id, removeCount, parentLeftKey, parentRebalance }; }
private int MergeNodes(Key middleKeyValue, NodeId leftId, NodeId rightId, Key leftLeftKey, Key rightLeftKey, object[] mergeBuffer) { // Fetch the nodes, ITreeNode leftNode = FetchNode(leftId); ITreeNode rightNode = FetchNode(rightId); // Are we merging branches or leafs? if (leftNode is TreeLeaf) { TreeLeaf lleaf = (TreeLeaf) leftNode; TreeLeaf rleaf = (TreeLeaf) rightNode; // Check the keys are identical, if (leftLeftKey.Equals(rightLeftKey)) { // 80% capacity on a leaf int capacity80 = (int) (0.80*MaxLeafByteSize); // True if it's possible to full merge left and right into a single bool fullyMerge = lleaf.Length + rleaf.Length <= MaxLeafByteSize; // Only proceed if the leafs can be fully merged or the left is less // than 80% full, if (fullyMerge || lleaf.Length < capacity80) { // Move elements from the right leaf to the left leaf so that either // the right node becomes completely empty or if that's not possible // the left node is 80% full. if (fullyMerge) { // We can fit both nodes into a single node so merge into a single // node, TreeLeaf nleaf = (TreeLeaf) UnfreezeNode(lleaf); byte[] copyBuf = new byte[rleaf.Length]; rleaf.Read(0, copyBuf, 0, copyBuf.Length); nleaf.Write(nleaf.Length, copyBuf, 0, copyBuf.Length); // Delete the right node, DeleteNode(rleaf.Id); // Setup the merge state mergeBuffer[0] = nleaf.Id; mergeBuffer[1] = (long) nleaf.Length; return 1; } // Otherwise, we move bytes from the right leaf into the left // leaf until it is 80% full, int toCopy = capacity80 - lleaf.Length; // Make sure we are copying at least 4 bytes and there are enough // bytes available in the right leaf to make the copy, if (toCopy > 4 && rleaf.Length > toCopy) { // Unfreeze both the nodes, TreeLeaf mlleaf = (TreeLeaf) UnfreezeNode(lleaf); TreeLeaf mrleaf = (TreeLeaf) UnfreezeNode(rleaf); // Copy, byte[] copyBuf = new byte[toCopy]; mrleaf.Read(0, copyBuf, 0, toCopy); mlleaf.Write(mlleaf.Length, copyBuf, 0, toCopy); // Shift the data in the right leaf, mrleaf.Shift(toCopy, -toCopy); // Return the merge state mergeBuffer[0] = mlleaf.Id; mergeBuffer[1] = (long) mlleaf.Length; mergeBuffer[2] = rightLeftKey; mergeBuffer[3] = mrleaf.Id; mergeBuffer[4] = (long) mrleaf.Length; return 2; } } } // leaf keys unequal } else if (leftNode is TreeBranch) { // Merge branches, TreeBranch lbranch = (TreeBranch) leftNode; TreeBranch rbranch = (TreeBranch) rightNode; int capacity75 = (int) (0.75*MaxBranchSize); // True if it's possible to full merge left and right into a single bool fullyMerge = lbranch.ChildCount + rbranch.ChildCount <= MaxBranchSize; // Only proceed if left is less than 75% full, if (fullyMerge || lbranch.ChildCount < capacity75) { // Move elements from the right branch to the left leaf only if the // branches can be completely merged into a node if (fullyMerge) { // We can fit both nodes into a single node so merge into a single // node, TreeBranch nbranch = (TreeBranch) UnfreezeNode(lbranch); // Merge, nbranch.MergeLeft(rbranch, middleKeyValue, rbranch.ChildCount); // Delete the right branch, DeleteNode(rbranch.Id); // Setup the merge state mergeBuffer[0] = nbranch.Id; mergeBuffer[1] = nbranch.LeafElementCount; return 1; } // Otherwise, we move children from the right branch into the left // branch until it is 75% full, int toCopy = capacity75 - lbranch.ChildCount; // Make sure we are copying at least 4 bytes and there are enough // bytes available in the right leaf to make the copy, if (toCopy > 2 && rbranch.ChildCount > toCopy + 3) { // Unfreeze the nodes, TreeBranch mlbranch = (TreeBranch) UnfreezeNode(lbranch); TreeBranch mrbranch = (TreeBranch) UnfreezeNode(rbranch); // And merge Key newMiddleValue = mlbranch.MergeLeft(mrbranch, middleKeyValue, toCopy); // Setup and return the merge state mergeBuffer[0] = mlbranch.Id; mergeBuffer[1] = mlbranch.LeafElementCount; mergeBuffer[2] = newMiddleValue; mergeBuffer[3] = mrbranch.Id; mergeBuffer[4] = mrbranch.LeafElementCount; return 2; } } } else { throw new ApplicationException("Unknown node type."); } // Signifies no change to the branch, return 3; }
internal void DeleteNode(NodeId nodeId) { // If we are deleting a node that's on the temporary node heap, we delete // it immediately. We know such nodes are only accessed within the scope of // this transaction so we can free up the resources immediately. // Is this a heap node? if (IsHeapNode(nodeId)) { // Delete it now NodeHeap.Delete(nodeId); } else { // Not a heap node, so we log that this node needs to be deleted when // we are certain it has gone out of scope of any concurrent transaction // that may need access to this data. // Logs a delete operation, LogStoreChange((byte)0, nodeId); } }
private TreeBranch RecurseRebalanceTree(long leftOffset, int height, NodeId nodeId, long absolutePosition, Key inLeftKey) { // Put the node in memory, TreeBranch branch = (TreeBranch) FetchNode(nodeId); int sz = branch.ChildCount; int i; long pos = leftOffset; // Find the first child i that contains the position. for (i = 0; i < sz; ++i) { long childElemCount = branch.GetChildLeafElementCount(i); // abs position falls within bounds, if (absolutePosition >= pos && absolutePosition < pos + childElemCount) { break; } pos += childElemCount; } if (i > 0) { NodeId leftId = branch.GetChild(i - 1); NodeId rightId = branch.GetChild(i); // Only continue if both left and right are on the heap if (IsHeapNode(leftId) && IsHeapNode(rightId) && IsHeapNode(nodeId)) { Key leftKey = (i - 1 == 0) ? inLeftKey : branch.GetKey(i - 1); Key rightKey = branch.GetKey(i); // Perform the merge operation, Key midKeyValue = rightKey; object[] mergeBuffer = new Object[5]; int merge_result = MergeNodes(midKeyValue, leftId, rightId, leftKey, rightKey, mergeBuffer); if (merge_result == 1) { branch.SetChild((NodeId) mergeBuffer[0], i - 1); branch.SetChildLeafElementCount((long) mergeBuffer[1], i - 1); branch.RemoveChild(i); } // else if (merge_result == 2) { branch.SetChild((NodeId) mergeBuffer[0], i - 1); branch.SetChildLeafElementCount((long) mergeBuffer[1], i - 1); branch.SetKeyToLeft((Key) mergeBuffer[2], i); branch.SetChild((NodeId) mergeBuffer[3], i); branch.SetChildLeafElementCount((long) mergeBuffer[4], i); } } } // After merge, we don't know how the children will be placed, so we // do another search on the child to descend to, sz = branch.ChildCount; pos = leftOffset; // Find the first child i that contains the position. for (i = 0; i < sz; ++i) { long childElemCount = branch.GetChildLeafElementCount(i); // abs position falls within bounds, if (absolutePosition >= pos && absolutePosition < pos + childElemCount) { break; } pos += childElemCount; } // Descend on 'i' ITreeNode descendChild = FetchNode(branch.GetChild(i)); // Finish if we hit a leaf if (descendChild is TreeLeaf) { // End if we hit the leaf, return branch; } Key newLeftKey = (i == 0) ? inLeftKey : branch.GetKey(i); // Otherwise recurse on the child, TreeBranch child_branch = RecurseRebalanceTree(pos, height + 1, descendChild.Id, absolutePosition, newLeftKey); // Make sure we unfreeze the branch branch = (TreeBranch) UnfreezeNode(branch); // Update the child, branch.SetChild(child_branch.Id, i); branch.SetChildLeafElementCount(child_branch.LeafElementCount, i); // And return this branch, return branch; }
public VersionInfo(long versionId, NodeId rootNodePointer, long versionInfoRef) { this.versionId = versionId; this.rootNodePointer = rootNodePointer; this.versionInfoRef = versionInfoRef; }
private void WrittenNode(ITreeNode node, NodeId nodeId) { // Delete the reference to the old node, DeleteNode(node.Id); // Log the insert operation. LogStoreChange((byte) 1, nodeId); }
private NodeId WriteNode(NodeId nodeId) { return ts.WriteNode(nodeId); }
internal ITreeNode FetchNode(NodeId nodeId) { // Is it a node we can fetch from the local node heap? if (IsHeapNode(nodeId)) { ITreeNode n = NodeHeap.FetchNode(nodeId); if (n == null) throw new NullReferenceException(nodeId.ToString()); return n; } // If there's nothing in the prefetch keymap, if (prefetchKeymap.Count == 0) { ITreeNode n = treeStore.FetchNodes(new NodeId[] {nodeId})[0]; if (n == null) throw new NullReferenceException(nodeId.ToString()); return n; } List<NodeId> prefetchNodeset = new List<NodeId>(); prefetchNodeset.Add(nodeId); DiscoverPrefetchNodeSet(prefetchNodeset); int len = prefetchNodeset.Count; NodeId[] nodeRefs = new NodeId[len]; for (int i = 0; i < len; ++i) { nodeRefs[i] = prefetchNodeset[i]; } { // Otherwise fetch the node from the tree store ITreeNode n = treeStore.FetchNodes(nodeRefs)[0]; if (n == null) throw new NullReferenceException(nodeId.ToString()); return n; } }
public PlaceholderLeaf(TreeSystemTransaction ts, NodeId nodeId, int size) { this.ts = ts; this.nodeId = nodeId; this.size = size; }
internal bool IsFrozen(NodeId nodeId) { return !nodeId.IsInMemory; // // A node is frozen if either it is in the store (nodeId >= 0) or it has // // the lock bit set to 0 // return nodeId >= 0 || // (nodeId & 0x02000000000000000L) == 0; }
private void DeleteNode(NodeId nodeId) { ts.DeleteNode(nodeId); }
internal NodeId WriteNode(NodeId nodeId) { // Create the sequence, TreeWrite sequence = new TreeWrite(); // Create the command sequence to write this tree out, int rootId = PopulateSequence(nodeId, sequence); if (rootId != -1) { // Write out this sequence, IList<NodeId> refs = treeStore.Persist(sequence); // Update internal structure for each node written, IList<ITreeNode> nodes = sequence.BranchNodes; int sz = nodes.Count; for (int i = 0; i < sz; ++i) { WrittenNode(nodes[i], refs[i]); } int bnodesSz = sz; nodes = sequence.LeafNodes; sz = nodes.Count; for (int i = 0; i < sz; ++i) { WrittenNode(nodes[i], refs[i + bnodesSz]); } // Normalize the pointer, if (rootId >= TreeWrite.BranchPoint) { rootId = rootId - TreeWrite.BranchPoint; } else { rootId = rootId + bnodesSz; } // Return a reference to the node written, return refs[rootId]; } return nodeId; }
private ITreeNode FetchNode(NodeId nodeId) { return ts.FetchNode(nodeId); }
private void ActualDisposeNode(NodeId nodeId) { // Dispose of the node, treeStore.DisposeNode(nodeId); // And return }
private bool IsFrozen(NodeId nodeId) { return ts.IsFrozen(nodeId); }
private void DeleteChildTree(int height, NodeId node) { if (height == treeHeight) { // This is a known leaf node, DeleteNode(node); return; } // Fetch the node, ITreeNode treeNode = FetchNode(node); if (treeNode is TreeLeaf) { // Leaf reached, so set the tree height, delete and return treeHeight = height; DeleteNode(node); return; } // The behaviour here changes depending on the system implementation. // Either we can simply unlink from the entire tree or we need to // recursely free all the leaf nodes. if (treeStore.NotifyNodeChanged) { // Need to account for all nodes so delete the node and all in the // sub-tree. DisposeTree(node); } else { // Otherwise we can simply unlink the branches on the heap and be // done with it. DisposeHeapNodes(node); } }
private bool IsHeapNode(NodeId nodeId) { return ts.IsHeapNode(nodeId); }
private void DisposeTree(NodeId id) { // It is a heap node, so fetch ITreeNode node = FetchNode(id); // Is it a leaf or a branch? if (node is TreeLeaf) { // If it's a leaf, dispose it DeleteNode(id); // And return, return; } if (node is TreeBranch) { // This is a branch, so we need to dipose the children if they are heap TreeBranch branch = (TreeBranch) node; int sz = branch.ChildCount; for (int i = 0; i < sz; ++i) { // Recurse for each child, DisposeTree(branch.GetChild(i)); } // Then dispose this, DeleteNode(id); // And return, return; } throw new ApplicationException("Unknown node type."); }
private void StackPush(int childIndex, long offset, NodeId nodeId) { if (stackSize + StackFrameSize >= stack.Length) { // Expand the size of the stack. // The default size should be plenty for most iterators unless we // happen to be iterating across a particularly deep B+Tree. long[] newStack = new long[stack.Length*2]; Array.Copy(stack, 0, newStack, 0, stack.Length); stack = newStack; } stack[stackSize] = childIndex; stack[stackSize + 1] = offset; stack[stackSize + 2] = nodeId.High; stack[stackSize + 3] = nodeId.Low; stackSize += StackFrameSize; }
private NodeId FlushNodes(NodeId id, NodeId[] includeIds) { if (!IsHeapNode(id)) return id; // Is this reference in the list? int c = Array.BinarySearch(includeIds, id); if (c < 0) { // It was not found, so go to the children, // Note that this node will change if it's a branch node, but the // reference to it will not change. // It is a heap node, so fetch ITreeNode node = FetchNode(id); // Is it a leaf or a branch? if (node is TreeLeaf) return id; if (node is TreeBranch) { // This is a branch, so we need to write out any children that are on // the heap before we write out the branch itself, TreeBranch branch = (TreeBranch) node; int sz = branch.ChildCount; for (int i = 0; i < sz; ++i) { NodeId oldId = branch.GetChild(i); // Recurse NodeId newId = FlushNodes(oldId, includeIds); branch.SetChild(newId, i); } // And return the reference return id; } throw new ApplicationException("Unknown node type."); } // This node was in the 'includeIds' list so write it out now, return WriteNode(id); }
public void SetChildOverride(NodeId childPointer, int n) { children[(n * 5) + 0] = childPointer.High; children[(n * 5) + 1] = childPointer.Low; }