Exemple #1
0
        public bool RedistributeFromRight(InternalNode rightSibling, byte[] joinKey, byte [] newJoinKey)
        {
            int required = _config.InternalSplitIndex - _keyCount;

            if (rightSibling.KeyCount - required < _config.InternalSplitIndex)
            {
                return(false);
            }

            // Copy keys and child pointers
            SetKey(_keyCount, joinKey);
            CopyKeys(rightSibling._keys, 0, _keyCount + 1, required - 1);
            //Array.Copy(rightSibling._keys, 0, _keys, _keyCount + 1, required - 1);
            Array.Copy(rightSibling._childPointers, 0, _childPointers, _keyCount + 1, required);
            Array.Copy(rightSibling._keys[required - 1], newJoinKey, _config.KeySize);

            // Shift up remaining keys and child pointers in the right node
            for (int i = 0; i < rightSibling._keyCount - required; i++)
            {
                rightSibling._keys[i]          = rightSibling._keys[i + required];
                rightSibling._childPointers[i] = rightSibling.ChildPointers[i + required];
            }
            rightSibling._childPointers[rightSibling._keyCount - required] = rightSibling._childPointers[rightSibling.KeyCount];
            rightSibling._keyCount -= required;
            _keyCount += required;
            return(true);
        }
Exemple #2
0
        /// <summary>
        /// Attempts to ensure that the minimum size for this node is achieved by transferring entries from the left-hand sibling
        /// </summary>
        /// <param name="leftSibling">The left-hand sibling that will provide entries</param>
        /// <param name="joinKey">The value of the key that is present in the parent node between the pointer to this node and its left sibling</param>
        /// <param name="newJoinKey">The replacement value for the join key in the parent node</param>
        /// <returns>True if the node achieves its minimum size by the redistribution process, false otherwise</returns>
        public bool RedistributeFromLeft(InternalNode leftSibling, byte[] joinKey, byte[] newJoinKey)
        {
            int required = _config.InternalSplitIndex - _keyCount;

            if (leftSibling.KeyCount - required < _config.InternalSplitIndex)
            {
                // Can't fulfill requirements with a borrow from left sibling
                return(false);
            }

            int evenOut = (_keyCount + leftSibling._keyCount) / 2 - _keyCount;

            if (leftSibling.KeyCount - evenOut > _config.InternalSplitIndex)
            {
                required = evenOut;
            }

            // Make space for new keys and child pointers
            _childPointers[_keyCount + required] = _childPointers[_keyCount];
            for (int i = _keyCount - 1; i >= 0; i--)
            {
                _keys[i + required]          = _keys[i];
                _childPointers[i + required] = _childPointers[i];
            }
            SetKey(required - 1, joinKey);
            CopyKeys(leftSibling._keys, (leftSibling._keyCount - required) + 1, 0, required - 1);
            //Array.Copy(leftSibling._keys, (leftSibling._keyCount - required) + 1, _keys, 0, required-1);
            Array.Copy(leftSibling._childPointers, (leftSibling._keyCount - required) + 1, _childPointers, 0, required);
            Array.Copy(leftSibling._keys[leftSibling.KeyCount - required], newJoinKey, _config.KeySize);
            _keyCount             += required;
            leftSibling._keyCount -= required;
            return(true);
        }
Exemple #3
0
        public INode GetNode(ulong nodeId, BrightstarProfiler profiler)
        {
            using (profiler.Step("BPlusTree.GetNode"))
            {
                INode ret;
                if (_modifiedNodes.TryGetValue(nodeId, out ret))
                {
                    profiler.Incr("NodeCache Hit");
                    return(ret);
                }
                if (_nodeCache.TryGetValue(nodeId, out ret))
                {
                    profiler.Incr("NodeCache Hit");
                    return(ret);
                }

                profiler.Incr("NodeCache Miss");
                using (profiler.Step("Load Node"))
                {
                    var nodePage = _pageStore.Retrieve(nodeId, profiler);
                    var header   = BitConverter.ToInt32(nodePage, 0);
                    if (header < 0)
                    {
                        ret = new InternalNode(nodeId, nodePage, ~header, _config);
                    }
                    else
                    {
                        ret = new LeafNode(nodeId, nodePage, header, _config);
                    }
                    _nodeCache.Add(ret);
                    return(ret);
                }
            }
        }
        /// <summary>
        /// Splits this node into two internal nodes, creating a new node for the right-hand (upper) half of the keys
        /// </summary>
        /// <param name="txnId"></param>
        /// <param name="rightNodePage">The new page reserved to receive the newly created internal node</param>
        /// <param name="splitKey">Receives the value of the key used for the split</param>
        /// <returns>The new right-hand node</returns>
        public IInternalNode Split(ulong txnId, IPage rightNodePage, out byte[] splitKey)
        {
#if DEBUG_BTREE
            _config.BTreeDebug("InternalNode.Split. Id={0}. Structure Before: {1}", PageId, Dump());
#endif
            EnsureWriteable(txnId);
            var splitIndex = _config.InternalSplitIndex;
            splitKey = GetKey(splitIndex);
            rightNodePage.SetData(_page.Data, KeyOffset(splitIndex + 1),
                                  KeyOffset(0),
                                  (KeyCount - (splitIndex + 1)) * _config.KeySize);
            var pointerCopyStart  = PointerOffset(splitIndex + 1);
            var pointerCopyLength = (KeyCount - splitIndex) * 8;
            rightNodePage.SetData(_page.Data, pointerCopyStart,
                                  PointerOffset(0),
                                  pointerCopyLength);
            var rightNodeKeyCount = KeyCount - (splitIndex + 1);
            rightNodePage.SetData(BitConverter.GetBytes(~rightNodeKeyCount), 0, 0, 4);
            var rightNode = new InternalNode(rightNodePage, rightNodeKeyCount, _config);
            KeyCount = splitIndex;
#if DEBUG_BTREE
            _config.BTreeDebug("InternalNode.Split. Structure After: Id={0} {1}\nRight Node After: Id={2} {3}",
                               PageId, Dump(), rightNode.PageId, rightNode.Dump());
#endif
            return(rightNode);
        }
Exemple #5
0
        private IEnumerable <KeyValuePair <byte[], ulong> > MakeInternalNodes(ulong txnId, IEnumerable <KeyValuePair <byte[], ulong> > children, BrightstarProfiler profiler)
        {
            var enumerator = children.GetEnumerator();
            var childList  = enumerator.Next(_internalBranchFactor).ToList();

            if (childList.Count == 1)
            {
                yield return(childList[0]);

                yield break;
            }

            byte[]       prevNodeKey = childList[0].Key;
            InternalNode prevNode    = MakeInternalNode(childList);

            childList = enumerator.Next(_internalBranchFactor).ToList();
            while (childList.Count > 0)
            {
                InternalNode nextNode    = MakeInternalNode(childList);
                var          nextNodeKey = childList[0].Key;
                if (nextNode.NeedJoin)
                {
                    nextNodeKey = new byte[_config.KeySize];
                    nextNode.RedistributeFromLeft(prevNode, childList[0].Key, nextNodeKey);
                }
                yield return(WriteNode(txnId, prevNode, prevNodeKey, profiler));

                prevNode    = nextNode;
                prevNodeKey = nextNodeKey;
                childList   = enumerator.Next(_internalBranchFactor).ToList();
            }

            /*
             * if (enumerator.MoveNext())
             * {
             *  firstChild = enumerator.Current;
             *  InternalNode nextNode;
             *  var nextNodeKey = firstChild.Key;
             *  if (enumerator.MoveNext())
             *  {
             *      nextNode = MakeInternalNode(firstChild, enumerator, _internalBranchFactor);
             *  }
             *  else
             *  {
             *      nextNode = MakeInternalNode(firstChild);
             *  }
             *  if (nextNode.NeedJoin)
             *  {
             *      nextNodeKey = new byte[_config.KeySize];
             *      nextNode.RedistributeFromLeft(prevNode, firstChild.Key, nextNodeKey);
             *  }
             *  yield return WriteNode(txnId, prevNode, prevNodeKey, profiler);
             *  prevNode = nextNode;
             *  prevNodeKey = nextNodeKey;
             * }
             */
            yield return(WriteNode(txnId, prevNode, prevNodeKey, profiler));
        }
 public void TestRightShiftFrom()
 {
     var pageStore = new MemoryPageStore(1024);
     var config = new BPlusTreeConfiguration( pageStore, 8, 8, 1024);
     var n = new InternalNode(pageStore.Create(0), BitConverter.GetBytes(50ul), 2,3, config);
     n.Insert(1, BitConverter.GetBytes(100ul), 4);
     Assert.AreEqual(50ul, BitConverter.ToUInt64(n.LeftmostKey, 0));
     Assert.AreEqual(100ul, BitConverter.ToUInt64(n.RightmostKey, 0));
 }
Exemple #7
0
 public void Insert(ulong txnId, byte[] key, byte[] value, bool overwrite = false, BrightstarProfiler profiler = null)
 {
     using (profiler.Step("BPlusTree.Insert"))
     {
         bool   splitRoot;
         INode  rightNode;
         byte[] rootSplitKey;
         Insert(txnId, _root, key, value, out splitRoot, out rightNode, out rootSplitKey, overwrite, profiler);
         if (splitRoot)
         {
             var newRoot = new InternalNode(_pageStore.Create(), rootSplitKey, _root.PageId, rightNode.PageId,
                                            _config);
             MarkDirty(txnId, _root, profiler);
             _modifiedNodes[newRoot.PageId] = newRoot;
             _root = newRoot;
         }
     }
 }
        /// <summary>
        /// Attempts to ensure that the minimum size for this node is achieved by transferring entries from the left-hand sibling
        /// </summary>
        /// <param name="txnId"></param>
        /// <param name="leftSibling">The left-hand sibling that will provide entries</param>
        /// <param name="joinKey">The value of the key that is present in the parent node between the pointer to this node and its left sibling</param>
        /// <param name="newJoinKey">The replacement value for the join key in the parent node</param>
        /// <returns>True if the node achieves its minimum size by the redistribution process, false otherwise</returns>
        public bool RedistributeFromLeft(ulong txnId, IInternalNode leftSibling, byte[] joinKey, byte[] newJoinKey)
        {
            InternalNode left = leftSibling as InternalNode;

            if (left == null)
            {
                throw new ArgumentException("Expected a InternalNode as left sibling", "leftSibling");
            }

            int required = _config.InternalSplitIndex - KeyCount;

            if (leftSibling.KeyCount - required < _config.InternalSplitIndex)
            {
                // Can't fulfill requirements with a borrow from left sibling
                return(false);
            }

            int evenOut = (KeyCount + left.KeyCount) / 2 - KeyCount;

            if (leftSibling.KeyCount - evenOut > _config.InternalSplitIndex)
            {
                required = evenOut;
            }

            EnsureWriteable(txnId);
            left.EnsureWriteable(txnId);

            // Make space for new keys and child pointers
            RightShift(required);

            _page.SetData(joinKey, 0, KeyOffset(required - 1), _config.KeySize);
            _page.SetData(left.GetData(), KeyOffset(left.KeyCount - (required - 1)),
                          KeyOffset(0), (required - 1) * _config.KeySize);
            _page.SetData(left.GetData(), PointerOffset(left.KeyCount - (required - 1)),
                          PointerOffset(0), (required) * 8);
            Array.Copy(left.GetData(), KeyOffset(left.KeyCount - required), newJoinKey, 0, _config.KeySize);
            KeyCount      += required;
            left.KeyCount -= required;
            return(true);
        }
Exemple #9
0
        /// <summary>
        /// Splits this node into two internal nodes, creating a new node for the right-hand (upper) half of the keys
        /// </summary>
        /// <param name="rightNodeId">The ID of the page reserved to receive the newly created internal node</param>
        /// <param name="splitKey">Receives the value of the key used for the split</param>
        /// <returns>The new right-hand node</returns>
        public InternalNode Split(ulong rightNodeId, out byte[] splitKey)
        {
            var rightNode  = new InternalNode(rightNodeId, _config);
            var splitIndex = _config.InternalSplitIndex;

            splitKey = _keys[splitIndex];

            Array.Copy(_keys, splitIndex + 1,
                       rightNode._keys, 0,
                       _keyCount - (splitIndex + 1));
            int pointerCopyStart  = splitIndex + 1;
            int pointerCopyLength = (_keyCount - splitIndex);

            Array.Copy(_childPointers, pointerCopyStart,
                       rightNode._childPointers, 0,
                       pointerCopyLength);

            rightNode._keyCount = _keyCount - (splitIndex + 1);
            _keyCount           = splitIndex;

            return(rightNode);
        }
Exemple #10
0
        public INode GetNode(ulong nodeId, BrightstarProfiler profiler)
        {
            using (profiler.Step("BPlusTree.GetNode"))
            {
                INode ret;
                if (_modifiedNodes.TryGetValue(nodeId, out ret))
                {
                    profiler.Incr("NodeCache Hit");
                    return ret;
                }
                if (_nodeCache.TryGetValue(nodeId, out ret))
                {
                    profiler.Incr("NodeCache Hit");
                    return ret;
                }

                profiler.Incr("NodeCache Miss");
                using (profiler.Step("Load Node"))
                {
                    var nodePage = _pageStore.Retrieve(nodeId, profiler);
                    var header = BitConverter.ToInt32(nodePage, 0);
                    if (header < 0)
                    {
                        ret = new InternalNode(nodeId, nodePage, ~header, _config);
                    }
                    else
                    {
                        ret = new LeafNode(nodeId, nodePage, header, _config);
                    }
                    _nodeCache.Add(ret);
                    return ret;
                }
            }
        }
Exemple #11
0
        private void Delete(ulong txnId, InternalNode parentInternalNode, byte[] key, out bool underAllocation, BrightstarProfiler profiler)
        {
            if (parentInternalNode.RightmostKey == null)
            {
                throw new ArgumentException("Parent node right key is null");
            }
            var childNodeId = parentInternalNode.GetChildNodeId(key);
            var childNode = GetNode(childNodeId, profiler);
            if (childNode is LeafNode)
            {
                var childLeafNode = childNode as LeafNode;
                // Delete the key and mark the node as updated. This may update the child node id
                childLeafNode.Delete(key);
                MarkDirty(txnId, childLeafNode, profiler);
                if (childLeafNode.PageId != childNodeId)
                {
                    parentInternalNode.UpdateChildPointer(childNodeId, childLeafNode.PageId);
                    childNodeId = childLeafNode.PageId;
                }

                if (childLeafNode.NeedsJoin)
                {
                    ulong leftSiblingId, rightSiblingId;
                    LeafNode leftSibling = null, rightSibling = null;
                    bool hasLeftSibling = parentInternalNode.GetLeftSibling(childNodeId, out leftSiblingId);
                    if (hasLeftSibling)
                    {
                        leftSibling = GetNode(leftSiblingId, profiler) as LeafNode;
                        if (childLeafNode.RedistributeFromLeft(leftSibling))
                        {
                            parentInternalNode.SetLeftKey(childLeafNode.PageId, childLeafNode.LeftmostKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            MarkDirty(txnId, leftSibling, null);
                            parentInternalNode.UpdateChildPointer(leftSiblingId, leftSibling.PageId);
                            underAllocation = false;
                            return;
                        }
                    }
                    bool hasRightSibling = parentInternalNode.GetRightSiblingId(childNodeId, out rightSiblingId);
                    
                        
                    if (hasRightSibling)
                    {
                        rightSibling = GetNode(rightSiblingId, profiler) as LeafNode;
#if DEBUG
                        if (rightSibling.LeftmostKey.Compare(childLeafNode.RightmostKey) <= 0)
                        {
                            throw new Exception("Right-hand sibling has a left key lower than this nodes right key.");
                        }
#endif
                        if (childLeafNode.RedistributeFromRight(rightSibling))
                        {
                            MarkDirty(txnId, rightSibling, profiler);
                            parentInternalNode.UpdateChildPointer(rightSiblingId, rightSibling.PageId);
                            parentInternalNode.SetLeftKey(rightSibling.PageId, rightSibling.LeftmostKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = false;
                            return;
                        }
                    }
                    if (hasLeftSibling && childLeafNode.Merge(leftSibling))
                    {
                        parentInternalNode.RemoveChildPointer(leftSiblingId);
                        parentInternalNode.SetLeftKey(childLeafNode.PageId, childLeafNode.LeftmostKey);
                        MarkDirty(txnId, parentInternalNode, profiler);
                        underAllocation = parentInternalNode.NeedJoin;
                        return;
                    }
                    if (hasRightSibling && childLeafNode.Merge(rightSibling))
                    {
                        byte[] nodeKey = parentInternalNode.RemoveChildPointer(rightSiblingId);
                        if (nodeKey == null)
                        {
                            // We merged in the right-most node, so we need to generate a key
                            nodeKey = new byte[_config.KeySize];
                            Array.Copy(rightSibling.RightmostKey, nodeKey, _config.KeySize);
                            ByteArrayHelper.Increment(nodeKey);
                        }
                        parentInternalNode.SetKey(childLeafNode.PageId, nodeKey);
                        MarkDirty(txnId, parentInternalNode, profiler);
                        underAllocation = parentInternalNode.NeedJoin;
                        return;
                    }
                }
                underAllocation = false;
                return;
            }


            if (childNode is InternalNode)
            {
                bool childUnderAllocated;
                var childInternalNode = childNode as InternalNode;
                Delete(txnId, childInternalNode, key, out childUnderAllocated, profiler);
                if (childInternalNode.PageId != childNodeId)
                {
                    // Child node page changed
                    parentInternalNode.UpdateChildPointer(childNodeId, childInternalNode.PageId);
                    MarkDirty(txnId, parentInternalNode, profiler);
                    childNodeId = childInternalNode.PageId;
                }

                if (childUnderAllocated)
                {
                    InternalNode leftSibling = null, rightSibling = null;
                    ulong leftSiblingId, rightSiblingId;

                    // Redistribute values from left-hand sibling
                    bool hasLeftSibling = parentInternalNode.GetLeftSibling(childNodeId, out leftSiblingId);
                    if (hasLeftSibling)
                    {
                        leftSibling = GetNode(leftSiblingId, profiler) as InternalNode;
                        byte[] joinKey = parentInternalNode.GetKey(leftSiblingId);
                        var newJoinKey = new byte[_config.KeySize];
                        if (childInternalNode.RedistributeFromLeft(leftSibling, joinKey, newJoinKey))
                        {
                            MarkDirty(txnId, leftSibling, profiler);
                            parentInternalNode.UpdateChildPointer(leftSiblingId, leftSibling.PageId);
                            parentInternalNode.SetKey(leftSibling.PageId, newJoinKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = false;
                            return;
                        }
                    }

                    // Redistribute values from right-hand sibling
                    bool hasRightSibling = parentInternalNode.GetRightSiblingId(childNodeId, out rightSiblingId);
                    if (hasRightSibling)
                    {
                        rightSibling = GetNode(rightSiblingId, profiler) as InternalNode;
                        byte[] joinKey = parentInternalNode.GetKey(childInternalNode.PageId);
                        byte[] newJoinKey = new byte[_config.KeySize];
                        if (childInternalNode.RedistributeFromRight(rightSibling, joinKey, newJoinKey))
                        {
                            MarkDirty(txnId, rightSibling, profiler);
                            parentInternalNode.UpdateChildPointer(rightSiblingId, rightSibling.PageId);
                            // parentInternalNode.SetKey(rightSibling.PageId, newJoinKey); -- think this is wrong should be:
                            parentInternalNode.SetKey(childInternalNode.PageId, newJoinKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = false;
                            return;
                        }
                    }

                    // Merge with left-hand sibling
                    if (hasLeftSibling)
                    {
                        // Attempt to merge child node into its left sibling
                        var joinKey = parentInternalNode.GetKey(leftSibling.PageId);
                        var mergedNodeKey = parentInternalNode.GetKey(childInternalNode.PageId);
                        if (mergedNodeKey == null)
                        {
                            mergedNodeKey = new byte[_config.KeySize];
                            Array.Copy(childInternalNode.RightmostKey, mergedNodeKey, _config.KeySize);
                            ByteArrayHelper.Increment(mergedNodeKey);
                        }
                        if (leftSibling.Merge(childInternalNode, joinKey))
                        {
                            MarkDirty(txnId, leftSibling, profiler);
                            if (leftSibling.PageId != leftSiblingId)
                            {
                                // We have a new page id (append-only stores will do this)
                                parentInternalNode.UpdateChildPointer(leftSiblingId, leftSibling.PageId);
                            }
                            parentInternalNode.RemoveChildPointer(childInternalNode.PageId);
                            parentInternalNode.SetKey(leftSibling.PageId, mergedNodeKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = parentInternalNode.NeedJoin;
                            return;
                        }
                    }

                    // Merge with right-hand sibling
                    if (hasRightSibling)
                    {
                        // Attempt to merge right sibling into child node
                        var joinKey = parentInternalNode.GetKey(childNodeId);
                        if (childInternalNode.Merge(rightSibling, joinKey))
                        {
                            MarkDirty(txnId, childInternalNode, profiler);
                            var nodeKey = parentInternalNode.RemoveChildPointer(rightSiblingId);
                            if (childInternalNode.PageId != childNodeId)
                            {
                                // We have a new page id for the child node (append-only stores will do this)
                                parentInternalNode.UpdateChildPointer(childNodeId, childInternalNode.PageId);
                            }
                            if (nodeKey == null)
                            {
                                // We merged in the right-most node, so we need to generate a key
                                nodeKey = new byte[_config.KeySize];
                                Array.Copy(rightSibling.RightmostKey, nodeKey, _config.KeySize);
                                ByteArrayHelper.Increment(nodeKey);
                            }
                            parentInternalNode.SetKey(childInternalNode.PageId, nodeKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = parentInternalNode.NeedJoin;
                            return;
                        }
                    }

                    throw new NotImplementedException(
                        "Not yet implemented handling for internal node becoming under allocated");
                }
                underAllocation = false;
            }
            else
            {
                throw new BrightstarInternalException(String.Format("Unrecognised B+ Tree node class : {0}",
                                                                    childNode.GetType()));
            }
        }
Exemple #12
0
 public void Insert(ulong txnId, byte[] key, byte[] value, bool overwrite = false, BrightstarProfiler profiler = null)
 {
     using (profiler.Step("BPlusTree.Insert"))
     {
         bool splitRoot;
         INode rightNode;
         byte[] rootSplitKey;
         Insert(txnId, _root, key, value, out splitRoot, out rightNode, out rootSplitKey, overwrite, profiler);
         if (splitRoot)
         {
             var newRoot = new InternalNode(_pageStore.Create(), rootSplitKey, _root.PageId, rightNode.PageId,
                                            _config);
             MarkDirty(txnId, _root, profiler);
             _modifiedNodes[newRoot.PageId] = newRoot;
             _root = newRoot;
         }
     }
 }
        /// <summary>
        /// Splits this node into two internal nodes, creating a new node for the right-hand (upper) half of the keys
        /// </summary>
        /// <param name="txnId"></param>
        /// <param name="rightNodePage">The new page reserved to receive the newly created internal node</param>
        /// <param name="splitKey">Receives the value of the key used for the split</param>
        /// <returns>The new right-hand node</returns>
        public IInternalNode Split(ulong txnId, IPage rightNodePage, out byte[] splitKey)
        {
#if DEBUG_BTREE
            _config.BTreeDebug("InternalNode.Split. Id={0}. Structure Before: {1}", PageId, Dump());
#endif
            EnsureWriteable(txnId);
            var splitIndex = _config.InternalSplitIndex;
            splitKey = GetKey(splitIndex);
            rightNodePage.SetData(_page.Data, KeyOffset(splitIndex + 1),
                                  KeyOffset(0),
                                  (KeyCount - (splitIndex + 1))*_config.KeySize);
            var pointerCopyStart = PointerOffset(splitIndex + 1);
            var pointerCopyLength = (KeyCount - splitIndex)*8;
            rightNodePage.SetData(_page.Data, pointerCopyStart,
                                  PointerOffset(0),
                                  pointerCopyLength);
            var rightNodeKeyCount = KeyCount - (splitIndex + 1);
            rightNodePage.SetData(BitConverter.GetBytes(~rightNodeKeyCount), 0, 0, 4);
            var rightNode = new InternalNode(rightNodePage, rightNodeKeyCount, _config);
            KeyCount = splitIndex;
#if DEBUG_BTREE
            _config.BTreeDebug("InternalNode.Split. Structure After: Id={0} {1}\nRight Node After: Id={2} {3}",
                PageId, Dump(), rightNode.PageId, rightNode.Dump());
#endif
            return rightNode;
        }
Exemple #14
0
        private void Delete(ulong txnId, InternalNode parentInternalNode, byte[] key, out bool underAllocation, BrightstarProfiler profiler)
        {
            if (parentInternalNode.RightmostKey == null)
            {
                throw new ArgumentException("Parent node right key is null");
            }
            var childNodeId = parentInternalNode.GetChildNodeId(key);
            var childNode   = GetNode(childNodeId, profiler);

            if (childNode is LeafNode)
            {
                var childLeafNode = childNode as LeafNode;
                // Delete the key and mark the node as updated. This may update the child node id
                childLeafNode.Delete(key);
                MarkDirty(txnId, childLeafNode, profiler);
                if (childLeafNode.PageId != childNodeId)
                {
                    parentInternalNode.UpdateChildPointer(childNodeId, childLeafNode.PageId);
                    childNodeId = childLeafNode.PageId;
                }

                if (childLeafNode.NeedsJoin)
                {
                    ulong    leftSiblingId, rightSiblingId;
                    LeafNode leftSibling = null, rightSibling = null;
                    bool     hasLeftSibling = parentInternalNode.GetLeftSibling(childNodeId, out leftSiblingId);
                    if (hasLeftSibling)
                    {
                        leftSibling = GetNode(leftSiblingId, profiler) as LeafNode;
                        if (childLeafNode.RedistributeFromLeft(leftSibling))
                        {
                            parentInternalNode.SetLeftKey(childLeafNode.PageId, childLeafNode.LeftmostKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            MarkDirty(txnId, leftSibling, null);
                            parentInternalNode.UpdateChildPointer(leftSiblingId, leftSibling.PageId);
                            underAllocation = false;
                            return;
                        }
                    }
                    bool hasRightSibling = parentInternalNode.GetRightSiblingId(childNodeId, out rightSiblingId);


                    if (hasRightSibling)
                    {
                        rightSibling = GetNode(rightSiblingId, profiler) as LeafNode;
#if DEBUG
                        if (rightSibling.LeftmostKey.Compare(childLeafNode.RightmostKey) <= 0)
                        {
                            throw new Exception("Right-hand sibling has a left key lower than this nodes right key.");
                        }
#endif
                        if (childLeafNode.RedistributeFromRight(rightSibling))
                        {
                            MarkDirty(txnId, rightSibling, profiler);
                            parentInternalNode.UpdateChildPointer(rightSiblingId, rightSibling.PageId);
                            parentInternalNode.SetLeftKey(rightSibling.PageId, rightSibling.LeftmostKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = false;
                            return;
                        }
                    }
                    if (hasLeftSibling && childLeafNode.Merge(leftSibling))
                    {
                        parentInternalNode.RemoveChildPointer(leftSiblingId);
                        parentInternalNode.SetLeftKey(childLeafNode.PageId, childLeafNode.LeftmostKey);
                        MarkDirty(txnId, parentInternalNode, profiler);
                        underAllocation = parentInternalNode.NeedJoin;
                        return;
                    }
                    if (hasRightSibling && childLeafNode.Merge(rightSibling))
                    {
                        byte[] nodeKey = parentInternalNode.RemoveChildPointer(rightSiblingId);
                        if (nodeKey == null)
                        {
                            // We merged in the right-most node, so we need to generate a key
                            nodeKey = new byte[_config.KeySize];
                            Array.Copy(rightSibling.RightmostKey, nodeKey, _config.KeySize);
                            ByteArrayHelper.Increment(nodeKey);
                        }
                        parentInternalNode.SetKey(childLeafNode.PageId, nodeKey);
                        MarkDirty(txnId, parentInternalNode, profiler);
                        underAllocation = parentInternalNode.NeedJoin;
                        return;
                    }
                }
                underAllocation = false;
                return;
            }


            if (childNode is InternalNode)
            {
                bool childUnderAllocated;
                var  childInternalNode = childNode as InternalNode;
                Delete(txnId, childInternalNode, key, out childUnderAllocated, profiler);
                if (childInternalNode.PageId != childNodeId)
                {
                    // Child node page changed
                    parentInternalNode.UpdateChildPointer(childNodeId, childInternalNode.PageId);
                    MarkDirty(txnId, parentInternalNode, profiler);
                    childNodeId = childInternalNode.PageId;
                }

                if (childUnderAllocated)
                {
                    InternalNode leftSibling = null, rightSibling = null;
                    ulong        leftSiblingId, rightSiblingId;

                    // Redistribute values from left-hand sibling
                    bool hasLeftSibling = parentInternalNode.GetLeftSibling(childNodeId, out leftSiblingId);
                    if (hasLeftSibling)
                    {
                        leftSibling = GetNode(leftSiblingId, profiler) as InternalNode;
                        byte[] joinKey    = parentInternalNode.GetKey(leftSiblingId);
                        var    newJoinKey = new byte[_config.KeySize];
                        if (childInternalNode.RedistributeFromLeft(leftSibling, joinKey, newJoinKey))
                        {
                            MarkDirty(txnId, leftSibling, profiler);
                            parentInternalNode.UpdateChildPointer(leftSiblingId, leftSibling.PageId);
                            parentInternalNode.SetKey(leftSibling.PageId, newJoinKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = false;
                            return;
                        }
                    }

                    // Redistribute values from right-hand sibling
                    bool hasRightSibling = parentInternalNode.GetRightSiblingId(childNodeId, out rightSiblingId);
                    if (hasRightSibling)
                    {
                        rightSibling = GetNode(rightSiblingId, profiler) as InternalNode;
                        byte[] joinKey    = parentInternalNode.GetKey(childInternalNode.PageId);
                        byte[] newJoinKey = new byte[_config.KeySize];
                        if (childInternalNode.RedistributeFromRight(rightSibling, joinKey, newJoinKey))
                        {
                            MarkDirty(txnId, rightSibling, profiler);
                            parentInternalNode.UpdateChildPointer(rightSiblingId, rightSibling.PageId);
                            // parentInternalNode.SetKey(rightSibling.PageId, newJoinKey); -- think this is wrong should be:
                            parentInternalNode.SetKey(childInternalNode.PageId, newJoinKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = false;
                            return;
                        }
                    }

                    // Merge with left-hand sibling
                    if (hasLeftSibling)
                    {
                        // Attempt to merge child node into its left sibling
                        var joinKey       = parentInternalNode.GetKey(leftSibling.PageId);
                        var mergedNodeKey = parentInternalNode.GetKey(childInternalNode.PageId);
                        if (mergedNodeKey == null)
                        {
                            mergedNodeKey = new byte[_config.KeySize];
                            Array.Copy(childInternalNode.RightmostKey, mergedNodeKey, _config.KeySize);
                            ByteArrayHelper.Increment(mergedNodeKey);
                        }
                        if (leftSibling.Merge(childInternalNode, joinKey))
                        {
                            MarkDirty(txnId, leftSibling, profiler);
                            if (leftSibling.PageId != leftSiblingId)
                            {
                                // We have a new page id (append-only stores will do this)
                                parentInternalNode.UpdateChildPointer(leftSiblingId, leftSibling.PageId);
                            }
                            parentInternalNode.RemoveChildPointer(childInternalNode.PageId);
                            parentInternalNode.SetKey(leftSibling.PageId, mergedNodeKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = parentInternalNode.NeedJoin;
                            return;
                        }
                    }

                    // Merge with right-hand sibling
                    if (hasRightSibling)
                    {
                        // Attempt to merge right sibling into child node
                        var joinKey = parentInternalNode.GetKey(childNodeId);
                        if (childInternalNode.Merge(rightSibling, joinKey))
                        {
                            MarkDirty(txnId, childInternalNode, profiler);
                            var nodeKey = parentInternalNode.RemoveChildPointer(rightSiblingId);
                            if (childInternalNode.PageId != childNodeId)
                            {
                                // We have a new page id for the child node (append-only stores will do this)
                                parentInternalNode.UpdateChildPointer(childNodeId, childInternalNode.PageId);
                            }
                            if (nodeKey == null)
                            {
                                // We merged in the right-most node, so we need to generate a key
                                nodeKey = new byte[_config.KeySize];
                                Array.Copy(rightSibling.RightmostKey, nodeKey, _config.KeySize);
                                ByteArrayHelper.Increment(nodeKey);
                            }
                            parentInternalNode.SetKey(childInternalNode.PageId, nodeKey);
                            MarkDirty(txnId, parentInternalNode, profiler);
                            underAllocation = parentInternalNode.NeedJoin;
                            return;
                        }
                    }

                    throw new NotImplementedException(
                              "Not yet implemented handling for internal node becoming under allocated");
                }
                underAllocation = false;
            }
            else
            {
                throw new BrightstarInternalException(String.Format("Unrecognised B+ Tree node class : {0}",
                                                                    childNode.GetType()));
            }
        }
Exemple #15
0
        /// <summary>
        /// Splits this node into two internal nodes, creating a new node for the right-hand (upper) half of the keys
        /// </summary>
        /// <param name="rightNodeId">The ID of the page reserved to receive the newly created internal node</param>
        /// <param name="splitKey">Receives the value of the key used for the split</param>
        /// <returns>The new right-hand node</returns>
        public InternalNode Split(ulong rightNodeId, out byte[] splitKey)
        {
            var rightNode = new InternalNode(rightNodeId, _config);
            var splitIndex = _config.InternalSplitIndex;
            splitKey = _keys[splitIndex];

            Array.Copy(_keys, splitIndex + 1,
                       rightNode._keys, 0,
                       _keyCount - (splitIndex + 1));
            int pointerCopyStart = splitIndex + 1;
            int pointerCopyLength = (_keyCount - splitIndex);
            Array.Copy(_childPointers, pointerCopyStart,
                       rightNode._childPointers, 0,
                       pointerCopyLength);

            rightNode._keyCount = _keyCount - (splitIndex + 1);
            _keyCount = splitIndex;

            return rightNode;
        }
Exemple #16
0
 private KeyValuePair <byte[], ulong> WriteNode(ulong txnId, InternalNode node, byte[] lowestLeafKey, BrightstarProfiler profiler)
 {
     _pageStore.Write(txnId, node.PageId, node.GetData(), profiler: profiler);
     return(new KeyValuePair <byte[], ulong>(lowestLeafKey, node.PageId));
 }
 private KeyValuePair<byte[], ulong > WriteNode(ulong  txnId, InternalNode node, byte[] lowestLeafKey, BrightstarProfiler profiler)
 {
     _pageStore.Write(txnId, node.PageId, node.GetData(), profiler:profiler);
     return new KeyValuePair<byte[], ulong>(lowestLeafKey, node.PageId);
 }
Exemple #18
0
        /// <summary>
        /// Attempts to ensure that the minimum size for this node is achieved by transferring entries from the left-hand sibling
        /// </summary>
        /// <param name="leftSibling">The left-hand sibling that will provide entries</param>
        /// <param name="joinKey">The value of the key that is present in the parent node between the pointer to this node and its left sibling</param>
        /// <param name="newJoinKey">The replacement value for the join key in the parent node</param>
        /// <returns>True if the node achieves its minimum size by the redistribution process, false otherwise</returns>
        public bool RedistributeFromLeft(InternalNode leftSibling, byte[] joinKey, byte[] newJoinKey)
        {
            int required = _config.InternalSplitIndex - _keyCount;
            if (leftSibling.KeyCount - required < _config.InternalSplitIndex)
            {
                // Can't fulfill requirements with a borrow from left sibling
                return false;
            }

            int evenOut = (_keyCount + leftSibling._keyCount) / 2 - _keyCount;
            if (leftSibling.KeyCount  - evenOut > _config.InternalSplitIndex)
            {
                required = evenOut;
            }

            // Make space for new keys and child pointers
            _childPointers[_keyCount + required] = _childPointers[_keyCount];
            for(int i = _keyCount -1; i >= 0; i-- )
            {
                _keys[i + required] = _keys[i];
                _childPointers[i + required] = _childPointers[i];
            }
            SetKey(required-1, joinKey);
            CopyKeys(leftSibling._keys, (leftSibling._keyCount - required) + 1, 0, required - 1);
            //Array.Copy(leftSibling._keys, (leftSibling._keyCount - required) + 1, _keys, 0, required-1);
            Array.Copy(leftSibling._childPointers, (leftSibling._keyCount-required) + 1, _childPointers, 0, required);
            Array.Copy(leftSibling._keys[leftSibling.KeyCount-required], newJoinKey, _config.KeySize);
            _keyCount += required;
            leftSibling._keyCount -= required;
            return true;
        }
Exemple #19
0
        public bool RedistributeFromRight(InternalNode rightSibling, byte[] joinKey, byte [] newJoinKey)
        {
            int required = _config.InternalSplitIndex - _keyCount;
            if (rightSibling.KeyCount - required < _config.InternalSplitIndex)
            {
                return false;
            }

            // Copy keys and child pointers
            SetKey(_keyCount, joinKey);
            CopyKeys(rightSibling._keys, 0, _keyCount + 1, required - 1);
            //Array.Copy(rightSibling._keys, 0, _keys, _keyCount + 1, required - 1);
            Array.Copy(rightSibling._childPointers, 0, _childPointers, _keyCount + 1, required);
            Array.Copy(rightSibling._keys[required - 1], newJoinKey, _config.KeySize);

            // Shift up remaining keys and child pointers in the right node
            for(int i  = 0; i < rightSibling._keyCount - required; i++)
            {
                rightSibling._keys[i] = rightSibling._keys[i + required];
                rightSibling._childPointers[i] = rightSibling.ChildPointers[i + required];
            }
            rightSibling._childPointers[rightSibling._keyCount - required] = rightSibling._childPointers[rightSibling.KeyCount];
            rightSibling._keyCount -= required;
            _keyCount += required;
            return true;
        }