public TreeSystemStack(TreeSystemTransaction ts) { this.ts = ts; stackSize = 0; stack = new long[StackFrameSize*13]; currentLeaf = null; currentLeafKey = null; leafOffset = 0; }
public TreeSystemStack(TreeSystemTransaction ts) { this.ts = ts; stackSize = 0; stack = new long[StackFrameSize * 13]; currentLeaf = null; currentLeafKey = null; leafOffset = 0; }
public HeapTreeLeaf(TreeSystemTransaction transaction, NodeId nodeId, TreeLeaf toCopy, int capacity) { this.nodeId = nodeId; size = toCopy.Length; this.transaction = transaction; // Copy the data into an array in this leaf. data = new byte[capacity]; toCopy.Read(0, data, 0, size); }
public void AddSpaceAfter(Key key, long spaceToAdd) { while (spaceToAdd > 0) { // Create an empty sparse node TreeLeaf emptyLeaf = CreateSparseLeaf(key, 0, spaceToAdd); InsertLeaf(key, emptyLeaf, false); spaceToAdd -= emptyLeaf.Length; } }
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; }
public void SplitLeaf(Key key, long position) { UnfreezeStack(); TreeLeaf sourceLeaf = CurrentLeaf; int splitPoint = LeafOffset; // The amount of data we are copying from the current key. int amount = sourceLeaf.Length - splitPoint; // Create a new empty node TreeLeaf emptyLeaf = CreateLeaf(key); emptyLeaf.SetLength(amount); // Copy the data at the end of the leaf into a buffer byte[] buf = new byte[amount]; sourceLeaf.Read(splitPoint, buf, 0, amount); // And write it out to the new leaf emptyLeaf.Write(0, buf, 0, amount); // Set the new size of the node sourceLeaf.SetLength(splitPoint); // Update the stack properties UpdateStackProperties(-amount); // And insert the new leaf after InsertLeaf(key, emptyLeaf, false); }
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; }
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 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) }
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 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 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 Reset() { StackClear(); currentLeaf = null; currentLeafKey = null; }
private void CopyDataTo(long position, DataFile targetDataFile, long targetPosition, long size) { // If transactions are the same (data is being copied within the same // transaction context). TreeSystemStack targetStack; TreeSystemStack sourceStack; // Keys Key targetKey = targetDataFile.key; Key sourceKey = key; bool modifyPosOnShift = false; if (targetDataFile.Transaction == Transaction) { // We set the source and target stack to the same sourceStack = targetDataFile.stack; targetStack = sourceStack; // If same transaction and target_position is before the position we // set the modify_pos_on_shift boolean. This will update the absolute // position when data is copied. modifyPosOnShift = (targetPosition <= position); } else { // Otherwise, set the target stack to the target file's stack sourceStack = stack; targetStack = targetDataFile.stack; } // Compact the key we are copying from, and in the destination, transaction.CompactNodeKey(sourceKey); targetDataFile.CompactNodeKey(targetKey); // The process works as follows; // 1. If we are not positioned at the start of a leaf, copy all data up // to the next leaf to the target. // 2. Split the target leaf at the new position if the leaf can be // split into 2 leaf nodes. // 3. Copy every full leaf to the target as a new leaf element. // 4. If there is any remaining data to copy, insert it into the target. // Set up for the position sourceStack.SetupForPosition(sourceKey, position); // If we aren't at the start of the leaf, then copy the data to the // target. int leafOff = sourceStack.LeafOffset; if (leafOff > 0) { // We copy the remaining data in the leaf to the target // The amount of data to copy from the leaf to the target int to_copy = (int)Math.Min(size, sourceStack.LeafSize - leafOff); if (to_copy > 0) { // Read into a buffer byte[] buf = new byte[to_copy]; sourceStack.CurrentLeaf.Read(leafOff, buf, 0, to_copy); // Make enough room to insert this data in the target targetStack.ShiftData(targetKey, targetPosition, to_copy); // Update the position if necessary if (modifyPosOnShift) { position += to_copy; } // Write the data to the target stack targetStack.WriteFrom(targetKey, targetPosition, buf, 0, to_copy); // Increment the pointers position += to_copy; targetPosition += to_copy; size -= to_copy; } } // If this is true, the next iteration will use the byte buffer leaf copy // routine. Set if a link to a node failed for whatever reason. bool useByteBufferCopyForNext = false; // The loop while (size > 0) { // We now know we are at the start of a leaf with data left to copy. sourceStack.SetupForPosition(sourceKey, position); // Lets assert that if (sourceStack.LeafOffset != 0) { throw new ApplicationException("Expected to be at the start of a leaf."); } // If the source is a heap node or we are copying less than the data // that's in the leaf then we use the standard shift and write. TreeLeaf currentLeaf = sourceStack.CurrentLeaf; // Check the leaf size isn't 0 if (currentLeaf.Length <= 0) { throw new ApplicationException("Leaf is empty."); } // If the remaining copy is less than the size of the leaf we are // copying from, we just do a byte array copy if (useByteBufferCopyForNext || size < currentLeaf.Length) { // Standard copy through a byte[] buf, useByteBufferCopyForNext = false; int toCopy = (int)Math.Min(size, currentLeaf.Length); // Read into a buffer byte[] buf = new byte[toCopy]; currentLeaf.Read(0, buf, 0, toCopy); // Make enough room in the target targetStack.ShiftData(targetKey, targetPosition, toCopy); if (modifyPosOnShift) { position += toCopy; } // Write the data and finish targetStack.WriteFrom(targetKey, targetPosition, buf, 0, toCopy); // Update pointers position += toCopy; targetPosition += toCopy; size -= toCopy; } else { // We need to copy a complete leaf node, // If the leaf is on the heap, write it out if (transaction.IsHeapNode(currentLeaf.Id)) { sourceStack.WriteLeafOnly(sourceKey); // And update any vars currentLeaf = sourceStack.CurrentLeaf; } // Ok, source current leaf isn't on the heap, and we are copying a // complete leaf node, so we are elegible to play with pointers to // copy the data. targetStack.SetupForPosition(targetKey, targetPosition); bool insertNextBefore = false; // Does the target key exist? bool targetKeyExists = targetStack.CurrentLeafKey.Equals(targetKey); if (targetKeyExists) { // If the key exists, is target_position at the end of the span? insertNextBefore = targetStack.LeafOffset < targetStack.CurrentLeaf.Length; } // If target isn't currently on a boundary if (!targetStack.IsAtEndOfKeyData && targetStack.LeafOffset != 0) { // If we aren't on a boundary we need to split the target leaf targetStack.SplitLeaf(targetKey, targetPosition); } // If the key exists we set up the position to the previous left // to insert the new leaf, otherwise we set it up to the default // position to insert. // Copy the leaf, // Try to link to this leaf bool linkSuccessful = TreeSystem.LinkLeaf(targetKey, currentLeaf.Id); // If the link was successful, if (linkSuccessful) { // Insert the leaf into the tree targetStack.InsertLeaf(targetKey, currentLeaf, insertNextBefore); // Update the pointers int copiedSize = currentLeaf.Length; // Update if we inserting stuff before if (modifyPosOnShift) { position += copiedSize; } position += copiedSize; targetPosition += copiedSize; size -= copiedSize; } // If the link was not successful, else { // We loop back and use the byte buffer copy, useByteBufferCopyForNext = true; } } } }
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 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; }
internal HeapTreeLeaf(ITransaction tran, long nodeId, TreeLeaf toCopy, int maxCapacity) : base() { this.nodeId = nodeId; this.size = toCopy.Length; this.tran = tran; // Copy the data into an array in this leaf. data = new byte[maxCapacity]; toCopy.Read(0, data, 0, size); }