/// <summary> /// 删除指定的键和关联的数据项。如果键未找到则抛出异常。 /// </summary> /// <param name="key">被删除的键</param> public void RemoveKey(string key) { if (this.RootNode == null) { throw new BPlusTreeKeyNotFoundException("Tree is empty, cannot remove."); } bool mergeMe; BPlusTreeNode root = this.RootNode; // 从根节点开始遍历删除 root.Delete(key, out mergeMe); // 如果根节点不是一个叶节点,并且仅还有一个子节点,则重新设置根节点 if (mergeMe && !this.RootNode.IsLeaf && this.RootNode.Count == 0) { this.RootNode = this.RootNode.FirstChild(); this.RootNodeBlockNumber = this.RootNode.MakeAsRoot(); root.Free(); } }
/// <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> /// 删除指定键的记录 /// </summary> /// <param name="key">指定键</param> /// <param name="mergeMe">如果为真则意味着删除键后节点已经小于1/2满,需要合并</param> /// <returns>返回节点中最小的键,如无变化则返回空</returns> public string Delete(string key, out bool mergeMe) { // 如果是叶节点,则调用删除叶节点逻辑 if (this.IsLeaf) { return(DeleteLeaf(key, out mergeMe)); } // 假设我是不需要被合并的 mergeMe = false; // 我是内部节点,找到指定键的位置 int deletePosition = this.FindAtOrNextPosition(key, false); // 加载要被删除位置的子节点 BPlusTreeNode deleteChildNode = LoadNodeAtPosition(deletePosition); // 从子节点中删除键 bool isChildNodeNeedMerge; string deletedChildKey = deleteChildNode.Delete(key, out isChildNodeNeedMerge); // 删除完毕,当前节点为脏节点 this.Soil(); // 发现子节点的最小键与被删除的键相同,则认为子节点已经没用了 string result = null; if (deletedChildKey != null && this.Tree.CompareKey(deletedChildKey, key) == 0) { if (this.Capacity > 3) { throw new BPlusTreeException( string.Format("Deletion returned delete key for too large node size: {0}.", this.Capacity)); } // 判断删除的是头或尾 if (deletePosition == 0) { result = this._childKeys[deletePosition]; } else if (deletePosition == this.Capacity) { this._childKeys[deletePosition - 1] = null; } else { this._childKeys[deletePosition - 1] = this._childKeys[deletePosition]; } if (result != null && this.Tree.CompareKey(result, key) == 0) { this.LoadNodeAtPosition(1); result = this._childNodes[1].LeastKey(); } // 这个子节点彻底没用了,释放其空间 deleteChildNode.Free(); // 节点中键位置右侧全部左移 1 位 OverwriteDeletePosition(deletePosition); // 如果节点的使用率小于一半,则需要合并节点 if (this.Count < this.Capacity / 2) { mergeMe = true; } // 重置子节点的父节点 this.ResetAllChildrenParent(); return(result); } if (deletePosition == 0) { result = deletedChildKey; } else if (deletedChildKey != null && deletePosition > 0) { if (this.Tree.CompareKey(deletedChildKey, key) != 0) { this._childKeys[deletePosition - 1] = deletedChildKey; } } // 如果子节点需要合并 if (isChildNodeNeedMerge) { int leftIndex, rightIndex; BPlusTreeNode leftNode, rightNode; string keyBetween; if (deletePosition == 0) { // 和右侧兄弟节点合并 leftIndex = deletePosition; rightIndex = deletePosition + 1; leftNode = deleteChildNode; rightNode = this.LoadNodeAtPosition(rightIndex); } else { // 和左侧兄弟节点合并 leftIndex = deletePosition - 1; rightIndex = deletePosition; leftNode = this.LoadNodeAtPosition(leftIndex); rightNode = deleteChildNode; } keyBetween = this._childKeys[leftIndex]; // 合并节点 string rightLeastKey; bool isDeleteRight; MergeInternal(leftNode, keyBetween, rightNode, out rightLeastKey, out isDeleteRight); // 是否需要删除右节点 if (isDeleteRight) { for (int i = rightIndex; i < this.Capacity; i++) { this._childKeys[i - 1] = this._childKeys[i]; this._childValues[i] = this._childValues[i + 1]; this._childNodes[i] = this._childNodes[i + 1]; } this._childKeys[this.Capacity - 1] = null; this._childValues[this.Capacity] = StorageConstants.NullBlockNumber; this._childNodes[this.Capacity] = null; this.ResetAllChildrenParent(); rightNode.Free(); // 当前节点还需要再合并吗 if (this.Count < this.Capacity / 2) { mergeMe = true; } } else { this._childKeys[rightIndex - 1] = rightLeastKey; } } return(result); }
/// <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(); }
public string Delete(string key, out bool mergeMe) { if (this.IsLeaf) { return(DeleteLeaf(key, out mergeMe)); } mergeMe = false; int deletePosition = this.FindAtOrNextPosition(key, false); BPlusTreeNode deleteChildNode = LoadNodeAtPosition(deletePosition); bool isChildNodeNeedMerge; string deletedChildKey = deleteChildNode.Delete(key, out isChildNodeNeedMerge); this.Soil(); string result = null; if (deletedChildKey != null && this.Tree.CompareKey(deletedChildKey, key) == 0) { if (this.Capacity > 3) { throw new BPlusTreeException( string.Format("Deletion returned delete key for too large node size: {0}.", this.Capacity)); } if (deletePosition == 0) { result = this._childKeys[deletePosition]; } else if (deletePosition == this.Capacity) { this._childKeys[deletePosition - 1] = null; } else { this._childKeys[deletePosition - 1] = this._childKeys[deletePosition]; } if (result != null && this.Tree.CompareKey(result, key) == 0) { this.LoadNodeAtPosition(1); result = this._childNodes[1].LeastKey(); } deleteChildNode.Free(); OverwriteDeletePosition(deletePosition); if (this.Count < this.Capacity / 2) { mergeMe = true; } this.ResetAllChildrenParent(); return(result); } if (deletePosition == 0) { result = deletedChildKey; } else if (deletedChildKey != null && deletePosition > 0) { if (this.Tree.CompareKey(deletedChildKey, key) != 0) { this._childKeys[deletePosition - 1] = deletedChildKey; } } if (isChildNodeNeedMerge) { int leftIndex, rightIndex; BPlusTreeNode leftNode, rightNode; string keyBetween; if (deletePosition == 0) { leftIndex = deletePosition; rightIndex = deletePosition + 1; leftNode = deleteChildNode; rightNode = this.LoadNodeAtPosition(rightIndex); } else { leftIndex = deletePosition - 1; rightIndex = deletePosition; leftNode = this.LoadNodeAtPosition(leftIndex); rightNode = deleteChildNode; } keyBetween = this._childKeys[leftIndex]; string rightLeastKey; bool isDeleteRight; MergeInternal(leftNode, keyBetween, rightNode, out rightLeastKey, out isDeleteRight); if (isDeleteRight) { for (int i = rightIndex; i < this.Capacity; i++) { this._childKeys[i - 1] = this._childKeys[i]; this._childValues[i] = this._childValues[i + 1]; this._childNodes[i] = this._childNodes[i + 1]; } this._childKeys[this.Capacity - 1] = null; this._childValues[this.Capacity] = StorageConstants.NullBlockNumber; this._childNodes[this.Capacity] = null; this.ResetAllChildrenParent(); rightNode.Free(); if (this.Count < this.Capacity / 2) { mergeMe = true; } } else { this._childKeys[rightIndex - 1] = rightLeastKey; } } return(result); }