private void Delete(ulong txnId, IInternalNode 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 ILeafNode) { var childLeafNode = childNode as ILeafNode; // Delete the key and mark the node as updated. This may update the child node id childLeafNode.Delete(txnId, key); MarkDirty(txnId, childLeafNode, profiler); if (childLeafNode.PageId != childNodeId) { parentInternalNode.UpdateChildPointer(txnId, childNodeId, childLeafNode.PageId); childNodeId = childLeafNode.PageId; } if (childLeafNode.NeedsJoin) { ulong leftSiblingId, rightSiblingId; ILeafNode leftSibling = null, rightSibling = null; bool hasLeftSibling = parentInternalNode.GetLeftSibling(childNodeId, out leftSiblingId); if (hasLeftSibling) { leftSibling = GetNode(leftSiblingId, profiler) as ILeafNode; if (childLeafNode.RedistributeFromLeft(txnId, leftSibling)) { parentInternalNode.SetLeftKey(txnId, childLeafNode.PageId, childLeafNode.LeftmostKey); MarkDirty(txnId, parentInternalNode, profiler); MarkDirty(txnId, leftSibling, null); parentInternalNode.UpdateChildPointer(txnId, leftSiblingId, leftSibling.PageId); underAllocation = false; return; } } bool hasRightSibling = parentInternalNode.GetRightSiblingId(childNodeId, out rightSiblingId); if (hasRightSibling) { rightSibling = GetNode(rightSiblingId, profiler) as ILeafNode; #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(txnId, rightSibling)) { MarkDirty(txnId, rightSibling, profiler); parentInternalNode.UpdateChildPointer(txnId, rightSiblingId, rightSibling.PageId); parentInternalNode.SetLeftKey(txnId, rightSibling.PageId, rightSibling.LeftmostKey); MarkDirty(txnId, parentInternalNode, profiler); underAllocation = false; return; } } if (hasLeftSibling && childLeafNode.Merge(txnId, leftSibling)) { parentInternalNode.RemoveChildPointer(txnId, leftSiblingId); parentInternalNode.SetLeftKey(txnId, childLeafNode.PageId, childLeafNode.LeftmostKey); MarkDirty(txnId, parentInternalNode, profiler); underAllocation = parentInternalNode.NeedJoin; return; } if (hasRightSibling && childLeafNode.Merge(txnId, rightSibling)) { byte[] nodeKey = parentInternalNode.RemoveChildPointer(txnId, 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(txnId, childLeafNode.PageId, nodeKey); MarkDirty(txnId, parentInternalNode, profiler); underAllocation = parentInternalNode.NeedJoin; return; } } underAllocation = false; return; } if (childNode is IInternalNode) { bool childUnderAllocated; var childInternalNode = childNode as IInternalNode; Delete(txnId, childInternalNode, key, out childUnderAllocated, profiler); if (childInternalNode.PageId != childNodeId) { // Child node page changed parentInternalNode.UpdateChildPointer(txnId, childNodeId, childInternalNode.PageId); MarkDirty(txnId, parentInternalNode, profiler); childNodeId = childInternalNode.PageId; } if (childUnderAllocated) { IInternalNode 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 IInternalNode; byte[] joinKey = parentInternalNode.GetKey(leftSiblingId); var newJoinKey = new byte[_config.KeySize]; if (childInternalNode.RedistributeFromLeft(txnId, leftSibling, joinKey, newJoinKey)) { MarkDirty(txnId, leftSibling, profiler); parentInternalNode.UpdateChildPointer(txnId, leftSiblingId, leftSibling.PageId); parentInternalNode.SetKey(txnId, 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 IInternalNode; byte[] joinKey = parentInternalNode.GetKey(childInternalNode.PageId); byte[] newJoinKey = new byte[_config.KeySize]; if (childInternalNode.RedistributeFromRight(txnId, rightSibling, joinKey, newJoinKey)) { MarkDirty(txnId, rightSibling, profiler); parentInternalNode.UpdateChildPointer(txnId, rightSiblingId, rightSibling.PageId); // parentInternalNode.SetKey(rightSibling.PageId, newJoinKey); -- think this is wrong should be: parentInternalNode.SetKey(txnId, 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(txnId, childInternalNode, joinKey)) { MarkDirty(txnId, leftSibling, profiler); if (leftSibling.PageId != leftSiblingId) { // We have a new page id (append-only stores will do this) parentInternalNode.UpdateChildPointer(txnId, leftSiblingId, leftSibling.PageId); } parentInternalNode.RemoveChildPointer(txnId, childInternalNode.PageId); parentInternalNode.SetKey(txnId, 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(txnId, rightSibling, joinKey)) { MarkDirty(txnId, childInternalNode, profiler); var nodeKey = parentInternalNode.RemoveChildPointer(txnId, rightSiblingId); if (childInternalNode.PageId != childNodeId) { // We have a new page id for the child node (append-only stores will do this) parentInternalNode.UpdateChildPointer(txnId, 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(txnId, 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())); } }