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 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); }
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; } } } }
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); }