public TreeSystemStack(TreeSystemTransaction ts) { this.ts = ts; stackSize = 0; stack = new long[StackFrameSize*13]; currentLeaf = null; currentLeafKey = null; leafOffset = 0; }
internal DataFile(TreeSystemTransaction transaction, Key key, bool fileReadOnly) { stack = new TreeSystemStack(transaction); this.transaction = transaction; this.key = key; p = 0; version = -1; this.fileReadOnly = fileReadOnly; start = -1; end = -1; }
private long[] GetDataFileBounds(Key key) { Key leftKey = Key.Head; int curHeight = 1; long leftOffset = 0; long nodeTotalSize = -1; ITreeNode node = FetchNode(RootNodeId); TreeBranch lastBranch = (TreeBranch) node; int childIndex = -1; while (true) { // Is the node a leaf? if (node is TreeLeaf) { treeHeight = curHeight; break; } // Must be a branch, TreeBranch branch = (TreeBranch) node; // We ask the node for the child sub-tree that will contain this node childIndex = branch.SearchLast(key); // Child will be in this subtree long childOffset = branch.GetChildOffset(childIndex); nodeTotalSize = branch.GetChildLeafElementCount(childIndex); // Get the left key of the branch if we can if (childIndex > 0) { leftKey = branch.GetKey(childIndex); } // Update left_offset leftOffset += childOffset; lastBranch = branch; // Ok, if we know child_node_ref is a leaf, if (curHeight + 1 == treeHeight) { break; } // Otherwise, descend to the child and repeat NodeId childNodeId = branch.GetChild(childIndex); node = FetchNode(childNodeId); ++curHeight; } // Ok, we've reached the leaf node on the search, // 'left_key' will be the key of the node we are on, // 'node_total_size' will be the size of the node, // 'last_branch' will be the branch immediately above the leaf // 'child_i' will be the offset into the last branch we searched long endPos; // If the key matches, int c = key.CompareTo(leftKey); if (c == 0) { endPos = leftOffset + nodeTotalSize; } // If the searched for key is less than this else if (c < 0) { endPos = -(leftOffset + 1); } // If this key is greater, relative offset is at the end of this node. else { //if (c > 0) { endPos = -((leftOffset + nodeTotalSize) + 1); } // If the key doesn't exist return the bounds as the position data is // entered. if (endPos < 0) { long p = -(endPos + 1); return new long[] {p, p}; } // Now we have the end position of a key that definitely exists, we can // query the parent branch and see if we can easily find the record // start. // Search back through the keys until we find a key that is different, // which is the start bounds of the key, long predictedStartPos = endPos - nodeTotalSize; for (int i = childIndex - 1; i > 0; --i) { Key k = lastBranch.GetKey(i); if (key.CompareTo(k) == 0) { // Equal, predictedStartPos = predictedStartPos - lastBranch.GetChildLeafElementCount(i); } else { // Not equal if (predictedStartPos > endPos) { throw new ApplicationException("Assertion failed: (1) start_pos > end_pos"); } return new long[] {predictedStartPos, endPos}; } } // Otherwise, find the end position of the previous key through a tree // search Key previousKey = PreviousKeyOrder(key); long startPos = AbsKeyEndPosition(previousKey); if (startPos > endPos) { throw new ApplicationException("Assertion failed: (2) start_pos > end_pos"); } return new long[] {startPos, endPos}; }
private void CompactNodeKey(Key key) { Object[] mergeBuffer = new Object[5]; // Compact the node, CompactNode(Key.Head, RootNodeId, mergeBuffer, key, key); }
private long AbsKeyEndPosition(Key key) { long pos = KeyEndPosition(key); return (pos < 0) ? -(pos + 1) : pos; }
protected IDataFile UnsafeGetDataFile(Key key, FileAccess mode) { // Check if the transaction disposed, if (disposed) { throw new InvalidOperationException("Transaction is disposed"); } // Create and return the data file object for this key. return new DataFile(this, key, (mode == FileAccess.Read)); }
internal TreeLeaf CreateLeaf(Key key) { return NodeHeap.CreateLeaf(this, key, MaxLeafByteSize); }
public IDataRange GetRange(Key minKey, Key maxKey) { CheckErrorState(); try { // All key types greater than 0x07F80 are reserved for system data if (OutOfUserDataRange(minKey) || OutOfUserDataRange(maxKey)) { throw new ArgumentException("Key is reserved for system data"); } // Use the unsafe method after checks have been performed return UnsafeGetDataRange(minKey, maxKey); } catch (OutOfMemoryException e) { throw HandleMemoryException(e); } }
public bool LinkLeaf(Key key, long reference) { // If the node is a special node, then we don't need to reference count it. if ((reference & 0x01000000000000000L) != 0) return true; try { store.LockForWrite(); // Get the area as a MutableArea object IMutableArea leafArea = store.GetMutableArea(reference); // We synchronize over a reference count lock // (Pending: should we lock by area instead? Not sure it will be // worth the complexity of a more fine grained locking mechanism for the // performance improvements - maybe we should implement a locking // mechanism inside IMutableArea). lock (refCountLock) { // Assert this is a leaf leafArea.Position = 0; short nodeType = leafArea.ReadInt2(); if (nodeType != LeafType) throw new IOException("Can only link to a leaf node."); leafArea.Position = 4; int refCount = leafArea.ReadInt4(); // If reference counter is near overflowing, return false, if (refCount > Int32.MaxValue - 8) return false; leafArea.Position = 4; leafArea.WriteInt4(refCount + 1); } return true; } finally { store.UnlockForWrite(); } }
internal void SetKeyValueToLeft(Key k, int child_i) { SetKeyValueToLeft(k.GetEncoded(1), k.GetEncoded(2), child_i); }
public int SearchLast(Key key) { int low = 1; int high = ChildCount - 1; while (true) { if (high - low <= 2) { for (int i = high; i >= low; --i) { int cmp1 = GetKey(i).CompareTo(key); if (cmp1 <= 0) return i; } return low - 1; } int mid = (low + high) / 2; int cmp = GetKey(mid).CompareTo(key); if (cmp < 0) { low = mid + 1; } else if (cmp > 0) { high = mid - 1; } else { low = mid; } } }
public int SearchFirst(Key key) { int low = 1; int high = ChildCount - 1; while (true) { if (high - low <= 2) { for (int i = low; i <= high; ++i) { int cmp1 = GetKey(i).CompareTo(key); if (cmp1 > 0) // Value is less than extent so take the left route return i - 1; if (cmp1 == 0) // Equal so need to search left and right of the extent // This is (-(i + 1 - 1)) return -i; } // Value is greater than extent so take the right route return high; } int mid = (low + high) / 2; int cmp = GetKey(mid).CompareTo(key); if (cmp < 0) { low = mid + 1; } else if (cmp > 0) { high = mid - 1; } else { high = mid; } } }
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 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); } }
public int IndexOfChild(Key key, long offset) { if (offset >= 0) { int sz = ChildCount; long left_offset = 0; for (int i = 0; i < sz; ++i) { left_offset += GetChildLeafElementCount(i); // If the relative point must be within this child if (offset < left_offset) return i; // This is a boundary condition, we need to use the key to work out // which child to take if (offset == left_offset) { // If the end has been reached, if (i == sz - 1) return i; Key key_val = GetKey(i + 1); int n = key_val.CompareTo(key); // If the key being inserted is less than the new leaf node, if (n > 0) // Go left, return i; // Otherwise go right return i + 1; } } } return -1; }
public bool DataFileExists(Key key) { CheckErrorState(); try { // All key types above 0x07F80 are reserved for system data if (OutOfUserDataRange(key)) { throw new ApplicationException("Key is reserved for system data."); } // If the key exists, the position will be >= 0 return KeyEndPosition(key) >= 0; } catch (IOException e) { throw HandleIOException(e); } catch (OutOfMemoryException e) { throw HandleMemoryException(e); } }
public IDataFile GetFile(Key key, FileAccess access) { CheckErrorState(); try { // All key types greater than 0x07F80 are reserved for system data if (OutOfUserDataRange(key)) { throw new ArgumentException("Key is reserved for system data", "key"); } // Use the unsafe method after checks have been performed return UnsafeGetDataFile(key, access); } catch (OutOfMemoryException e) { throw HandleMemoryException(e); } }
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; }
public void PreFetchKeys(Key[] keys) { CheckErrorState(); try { foreach (Key k in keys) { prefetchKeymap.Add(k, ""); } } catch (OutOfMemoryException e) { throw HandleMemoryException(e); } }
private NodeId LastUncachedNode(Key key) { int curHeight = 1; NodeId childNodeId = RootNodeId; TreeBranch lastBranch = null; int childIndex = -1; // How this works; // * Descend through the tree and try to find the last node of the // previous key. // * If a node is encoutered that is not cached locally, return it. // * If a leaf is reached, return the next leaf entry from the previous // branch (this should be the first node of key). // This does not perform completely accurately for tree edges but this // should not present too much of a problem. key = PreviousKeyOrder(key); // Try and fetch the node, if it's not available locally then return the // child node ref ITreeNode node = FetchNodeIfLocallyAvailable(childNodeId); if (node == null) { return childNodeId; } while (true) { // Is the node a leaf? if (node is TreeLeaf) { treeHeight = curHeight; break; } // Must be a branch, TreeBranch branch = (TreeBranch) node; lastBranch = branch; // We ask the node for the child sub-tree that will contain this node childIndex = branch.SearchLast(key); // Child will be in this subtree childNodeId = branch.GetChild(childIndex); // Ok, if we know child_node_ref is a leaf, if (curHeight + 1 == treeHeight) { break; } // Try and fetch the node, if it's not available locally then return // the child node ref node = FetchNodeIfLocallyAvailable(childNodeId); if (node == null) { return childNodeId; } // Otherwise, descend to the child and repeat ++curHeight; } // Ok, we've reached the end of the tree, // Fetch the next child_i if we are not at the end already, if (childIndex + 1 < lastBranch.ChildCount) { childNodeId = lastBranch.GetChild(childIndex); } // If the child node is not a heap node, and is not available locally then // return it. if (!IsHeapNode(childNodeId) && !treeStore.IsNodeAvailable(childNodeId)) { return childNodeId; } // The key is available locally, return null; }
internal TreeLeaf CreateSparseLeaf(Key key, byte value, long length) { // Make sure the sparse leaf doesn't exceed the maximum leaf size int sparseSize = (int)Math.Min(length, (long)MaxLeafByteSize); // Make sure the sparse leaf doesn't exceed the maximum size of the // sparse leaf object. sparseSize = Math.Min(65535, sparseSize); // Create node reference for a special sparse node, NodeId nodeId = NodeId.CreateSpecialSparseNode(value, length); return (TreeLeaf)FetchNode(nodeId); }
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; }
protected IDataRange UnsafeGetDataRange(Key minKey, Key maxKey) { // Check if the transaction disposed, if (disposed) { throw new InvalidOperationException("Transaction is disposed"); } // Create and return the data file object for this key. return new DataRange(this, minKey, maxKey); }
private Key PreviousKeyOrder(Key key) { short type = key.Type; int secondary = key.Secondary; long primary = key.Primary; if (primary == Int64.MinValue) { // Should not use negative primary keys. throw new InvalidOperationException(); } return new Key(type, secondary, primary - 1); }
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; } } } }
public static bool OutOfUserDataRange(Key key) { // These types reserved for system use, if (key.Type >= (short) 0x07F80) return true; // Primary key has a reserved group of values at min value if (key.Primary <= Int64.MinValue + 16) return true; return false; }
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 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; }
private long KeyEndPosition(Key key) { Key leftKey = Key.Head; int curHeight = 1; long leftOffset = 0; long nodeTotalSize = -1; ITreeNode node = FetchNode(RootNodeId); while (true) { // Is the node a leaf? if (node is TreeLeaf) { treeHeight = curHeight; break; } // Must be a branch, TreeBranch branch = (TreeBranch) node; // We ask the node for the child sub-tree that will contain this node int childIndex = branch.SearchLast(key); // Child will be in this subtree long childOffset = branch.GetChildOffset(childIndex); NodeId childNodeId = branch.GetChild(childIndex); nodeTotalSize = branch.GetChildLeafElementCount(childIndex); // Get the left key of the branch if we can if (childIndex > 0) { leftKey = branch.GetKey(childIndex); } // Update left_offset leftOffset += childOffset; // Ok, if we know child_node_ref is a leaf, if (curHeight + 1 == treeHeight) { break; } // Otherwise, descend to the child and repeat node = FetchNode(childNodeId); ++curHeight; } // Ok, we've reached the end of the tree, // 'left_key' will be the key of the node we are on, // 'node_total_size' will be the size of the node, // If the key matches, int c = key.CompareTo(leftKey); if (c == 0) return leftOffset + nodeTotalSize; // If the searched for key is less than this if (c < 0) return -(leftOffset + 1); // If this key is greater, relative offset is at the end of this node. //if (c > 0) { return -((leftOffset + nodeTotalSize) + 1); }
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 }; }