/// <summary>
        /// 分割当前节点
        /// </summary>
        /// <param name="splitFirstKey">新分割节点的第一个键,也就是最小的键</param>
        /// <param name="splitNode">新分割节点</param>
        private void SplitInternal(ref string splitFirstKey, ref BPlusTreeNode splitNode)
        {
            // 从中间开始分割
            int splitPoint = this._childNodes.Length / 2 - 1;

            // 分割出的新节点的第一个键
            splitFirstKey = this._childKeys[splitPoint];

            // 新建节点,包含分割点右侧所有数据
            splitNode = new BPlusTreeNode(this.Tree, this.Parent, -1, this.IsLeaf);
            splitNode.Clear(); // redundant.

            // 记录已经扩充的数据结构
            long[]          values = this._childValues;
            string[]        keys   = this._childKeys;
            BPlusTreeNode[] nodes  = this._childNodes;

            // 重置和清空数据
            this.Clear();

            // 将分割点左侧的数据拷贝至此节点
            Array.Copy(keys, 0, this._childKeys, 0, splitPoint);
            Array.Copy(values, 0, this._childValues, 0, splitPoint + 1);
            Array.Copy(nodes, 0, this._childNodes, 0, splitPoint + 1);

            // 将分割点右侧的数据拷贝至新的分割节点
            int remainingKeys = this.Capacity - splitPoint;

            Array.Copy(keys, splitPoint + 1, splitNode._childKeys, 0, remainingKeys);
            Array.Copy(values, splitPoint + 1, splitNode._childValues, 0, remainingKeys + 1);
            Array.Copy(nodes, splitPoint + 1, splitNode._childNodes, 0, remainingKeys + 1);

            // 重置新节点中所有的子节点的父节点
            splitNode.ResetAllChildrenParent();

            // 存储新节点
            splitNode.DumpToNewBlock();
            splitNode.CheckIfTerminal();
            splitNode.Soil();

            this.CheckIfTerminal();
        }
Exemple #2
0
        /// <summary>
        /// 合并内部节点,当节点的使用率不足 50% 时,则需要合并
        /// </summary>
        /// <param name="left">左节点</param>
        /// <param name="keyBetween">左右节点的中间键</param>
        /// <param name="right">右节点</param>
        /// <param name="rightLeastKey">合并后的键的最小值</param>
        /// <param name="canDeleteRightNode">是否可以删除右节点</param>
        public static void MergeInternal(BPlusTreeNode left, string keyBetween, BPlusTreeNode right, out string rightLeastKey, out bool canDeleteRightNode)
        {
            if (left == null)
            {
                throw new ArgumentNullException("left");
            }
            if (right == null)
            {
                throw new ArgumentNullException("right");
            }

            rightLeastKey = null; // only if DeleteRight

            // 合并叶节点
            if (left.IsLeaf || right.IsLeaf)
            {
                if (!(left.IsLeaf && right.IsLeaf))
                {
                    throw new BPlusTreeException("Cannot merge leaf with non-leaf.");
                }

                // 合并子节点
                MergeLeaves(left, right, out canDeleteRightNode);

                rightLeastKey = right._childKeys[0];

                return;
            }

            // 合并非叶节点
            canDeleteRightNode = false;

            if (left._childValues[0] == StorageConstants.NullBlockNumber || right._childValues[0] == StorageConstants.NullBlockNumber)
            {
                throw new BPlusTreeException("Cannot merge empty non-leaf with non-leaf.");
            }

            string[]        allKeys   = new string[left.Capacity * 2 + 1];
            long[]          allValues = new long[left.Capacity * 2 + 2];
            BPlusTreeNode[] allNodes  = new BPlusTreeNode[left.Capacity * 2 + 2];

            // 拷贝左节点的数据
            int index = 0;

            allValues[0] = left._childValues[0];
            allNodes[0]  = left._childNodes[0];
            for (int i = 0; i < left.Capacity; i++)
            {
                if (left._childKeys[i] == null)
                {
                    break;
                }

                allKeys[index]       = left._childKeys[i];
                allValues[index + 1] = left._childValues[i + 1];
                allNodes[index + 1]  = left._childNodes[i + 1];

                index++;
            }

            // 拷贝中间键
            allKeys[index] = keyBetween;
            index++;

            // 拷贝右节点的数据
            allValues[index] = right._childValues[0];
            allNodes[index]  = right._childNodes[0];
            int rightCount = 0;

            for (int i = 0; i < right.Capacity; i++)
            {
                if (right._childKeys[i] == null)
                {
                    break;
                }

                allKeys[index]       = right._childKeys[i];
                allValues[index + 1] = right._childValues[i + 1];
                allNodes[index + 1]  = right._childNodes[i + 1];
                index++;

                rightCount++;
            }

            // 如果数量小于左节点的能力,则右节点可以删除掉
            if (index <= left.Capacity)
            {
                // it will all fit in one node
                canDeleteRightNode = true;

                for (int i = 0; i < index; i++)
                {
                    left._childKeys[i]   = allKeys[i];
                    left._childValues[i] = allValues[i];
                    left._childNodes[i]  = allNodes[i];
                }

                left._childValues[index] = allValues[index];
                left._childNodes[index]  = allNodes[index];

                left.ResetAllChildrenParent();
                left.Soil();

                right.Free();

                return;
            }

            // otherwise split the content between the nodes
            left.Clear();
            right.Clear();
            left.Soil();
            right.Soil();

            int leftContent  = index / 2;
            int rightContent = index - leftContent - 1;

            rightLeastKey = allKeys[leftContent];

            int outputIndex = 0;

            for (int i = 0; i < leftContent; i++)
            {
                left._childKeys[i]   = allKeys[outputIndex];
                left._childValues[i] = allValues[outputIndex];
                left._childNodes[i]  = allNodes[outputIndex];
                outputIndex++;
            }

            rightLeastKey = allKeys[outputIndex];

            left._childValues[outputIndex] = allValues[outputIndex];
            left._childNodes[outputIndex]  = allNodes[outputIndex];
            outputIndex++;

            rightCount = 0;
            for (int i = 0; i < rightContent; i++)
            {
                right._childKeys[i]   = allKeys[outputIndex];
                right._childValues[i] = allValues[outputIndex];
                right._childNodes[i]  = allNodes[outputIndex];
                outputIndex++;

                rightCount++;
            }

            right._childValues[rightCount] = allValues[outputIndex];
            right._childNodes[rightCount]  = allNodes[outputIndex];

            left.ResetAllChildrenParent();
            right.ResetAllChildrenParent();
        }