/// <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(); }
/// <summary> /// 合并叶节点,当节点的使用率不足 50% 时,则需要合并 /// </summary> /// <param name="left">左节点</param> /// <param name="right">右节点</param> /// <param name="canDeleteRightNode">是否可以删除右节点</param> public static void MergeLeaves(BPlusTreeNode left, BPlusTreeNode right, out bool canDeleteRightNode) { if (left == null) { throw new ArgumentNullException("left"); } if (right == null) { throw new ArgumentNullException("right"); } canDeleteRightNode = false; string[] allKeys = new string[left.Capacity * 2]; long[] allValues = new long[left.Capacity * 2]; int index = 0; for (int i = 0; i < left.Capacity; i++) { if (left._childKeys[i] == null) { break; } allKeys[index] = left._childKeys[i]; allValues[index] = left._childValues[i]; index++; } for (int i = 0; i < right.Capacity; i++) { if (right._childKeys[i] == null) { break; } allKeys[index] = right._childKeys[i]; allValues[index] = right._childValues[i]; index++; } // 如果左节点的容量足够,则可删除右节点 if (index <= left.Capacity) { canDeleteRightNode = true; left.Clear(); for (int i = 0; i < index; i++) { left._childKeys[i] = allKeys[i]; left._childValues[i] = allValues[i]; } left.Soil(); right.Free(); return; } // 左节点的容量不够了 left.Clear(); right.Clear(); left.Soil(); right.Soil(); int rightContent = index / 2; int leftContent = index - rightContent; int newIndex = 0; for (int i = 0; i < leftContent; i++) { left._childKeys[i] = allKeys[newIndex]; left._childValues[i] = allValues[newIndex]; newIndex++; } for (int i = 0; i < rightContent; i++) { right._childKeys[i] = allKeys[newIndex]; right._childValues[i] = allValues[newIndex]; newIndex++; } }
/// <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(); }