/// <summary> /// insert key/position entry in self /// </summary> /// <param name="key">Key to associate with the leaf</param> /// <param name="position">position associated with key in external structur</param> /// <param name="splitString">if not null then the smallest key in the new split leaf</param> /// <param name="splitNode">if not null then the node was split and this is the leaf to the right.</param> /// <returns>null unless the smallest key under this node has changed, in which case it returns the smallest key.</returns> public string Insert(string key, long position, out string splitString, out BplusNode splitNode) { if (this.isLeaf) { return this.InsertLeaf(key, position, out splitString, out splitNode); } splitString = null; splitNode = null; int insertposition = this.FindAtOrNextPosition(key, false, true); long insertBufferNumber = this.ChildBufferNumbers[insertposition]; if (insertBufferNumber==BplusTreeLong.NULLBUFFERNUMBER) { throw new BplusTreeException("key not followed by buffer number in non-leaf"); } // insert in subtree BplusNode InsertChild = this.MaterializeNodeAtIndex(insertposition); BplusNode childSplit; string childSplitString; string childInsert = InsertChild.Insert(key, position, out childSplitString, out childSplit); // if there was a split the node must expand if (childSplit!=null) { // insert the child this.Soil(); // redundant -- a child will have a change so this node will need to be copied int newChildPosition = insertposition+1; bool dosplit = false; // if there is no free space we must do a split if (this.ChildBufferNumbers[this.Size]!=BplusTreeLong.NULLBUFFERNUMBER) { dosplit = true; this.PrepareForSplit(); } // bubble over the current values to make space for new child for (int i=this.ChildKeys.Length-2; i>=newChildPosition-1; i--) { int i1 = i+1; int i2 = i1+1; this.ChildKeys[i1] = this.ChildKeys[i]; this.ChildBufferNumbers[i2] = this.ChildBufferNumbers[i1]; BplusNode childNode = this.MaterializedChildNodes[i2] = this.MaterializedChildNodes[i1]; } // record the new child this.ChildKeys[newChildPosition-1] = childSplitString; //this.MaterializedChildNodes[newChildPosition] = childSplit; //this.ChildBufferNumbers[newChildPosition] = childSplit.myBufferNumber; childSplit.Reparent(this, newChildPosition); // split, if needed if (dosplit) { int splitpoint = this.MaterializedChildNodes.Length/2-1; splitString = this.ChildKeys[splitpoint]; splitNode = new BplusNode(this.owner, this.parent, -1, this.isLeaf); // make copy of expanded node structure BplusNode[] materialized = this.MaterializedChildNodes; long[] buffernumbers = this.ChildBufferNumbers; string[] keys = this.ChildKeys; // repair the expanded node this.ChildKeys = new string[this.Size]; this.MaterializedChildNodes = new BplusNode[this.Size+1]; this.ChildBufferNumbers = new long[this.Size+1]; this.Clear(); Array.Copy(materialized, 0, this.MaterializedChildNodes, 0, splitpoint+1); Array.Copy(buffernumbers, 0, this.ChildBufferNumbers, 0, splitpoint+1); Array.Copy(keys, 0, this.ChildKeys, 0, splitpoint); // initialize the new node splitNode.Clear(); // redundant. int remainingKeys = this.Size-splitpoint; Array.Copy(materialized, splitpoint+1, splitNode.MaterializedChildNodes, 0, remainingKeys+1); Array.Copy(buffernumbers, splitpoint+1, splitNode.ChildBufferNumbers, 0, remainingKeys+1); Array.Copy(keys, splitpoint+1, splitNode.ChildKeys, 0, remainingKeys); // fix pointers in materialized children of splitnode splitNode.reParentAllChildren(); // store the new node splitNode.DumpToFreshBuffer(); splitNode.CheckIfTerminal(); splitNode.Soil(); this.CheckIfTerminal(); } // fix pointers in children this.reParentAllChildren(); } if (insertposition==0) { // the smallest key may have changed return childInsert; } return null; // no change in smallest key }
public static void Merge(BplusNode left, string KeyBetween, BplusNode right, out string rightLeastKey, out bool DeleteRight) { //System.Diagnostics.Debug.WriteLine("\r\n<br> merging "+right.myBufferNumber+" ("+KeyBetween+") "+left.myBufferNumber); //System.Diagnostics.Debug.WriteLine(left.owner.toHtml()); rightLeastKey = null; // only if DeleteRight if (left.isLeaf || right.isLeaf) { if (!(left.isLeaf&&right.isLeaf)) { throw new BplusTreeException("can't merge leaf with non-leaf"); } MergeLeaves(left, right, out DeleteRight); rightLeastKey = right.ChildKeys[0]; return; } // merge non-leaves DeleteRight = false; string[] allkeys = new string[left.Size*2+1]; long[] allseeks = new long[left.Size*2+2]; BplusNode[] allMaterialized = new BplusNode[left.Size*2+2]; if (left.ChildBufferNumbers[0]==BplusTreeLong.NULLBUFFERNUMBER || right.ChildBufferNumbers[0]==BplusTreeLong.NULLBUFFERNUMBER) { throw new BplusTreeException("cannot merge empty non-leaf with non-leaf"); } int index = 0; allseeks[0] = left.ChildBufferNumbers[0]; allMaterialized[0] = left.MaterializedChildNodes[0]; for (int i=0; i<left.Size; i++) { if (left.ChildKeys[i]==null) { break; } allkeys[index] = left.ChildKeys[i]; allseeks[index+1] = left.ChildBufferNumbers[i+1]; allMaterialized[index+1] = left.MaterializedChildNodes[i+1]; index++; } allkeys[index] = KeyBetween; index++; allseeks[index] = right.ChildBufferNumbers[0]; allMaterialized[index] = right.MaterializedChildNodes[0]; int rightcount = 0; for (int i=0; i<right.Size; i++) { if (right.ChildKeys[i]==null) { break; } allkeys[index] = right.ChildKeys[i]; allseeks[index+1] = right.ChildBufferNumbers[i+1]; allMaterialized[index+1] = right.MaterializedChildNodes[i+1]; index++; rightcount++; } if (index<=left.Size) { // it will all fit in one node //System.Diagnostics.Debug.WriteLine("deciding to forget "+right.myBufferNumber+" into "+left.myBufferNumber); DeleteRight = true; for (int i=0; i<index; i++) { left.ChildKeys[i] = allkeys[i]; left.ChildBufferNumbers[i] = allseeks[i]; left.MaterializedChildNodes[i] = allMaterialized[i]; } left.ChildBufferNumbers[index] = allseeks[index]; left.MaterializedChildNodes[index] = allMaterialized[index]; left.reParentAllChildren(); 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.ChildBufferNumbers[i] = allseeks[outputindex]; left.MaterializedChildNodes[i] = allMaterialized[outputindex]; outputindex++; } rightLeastKey = allkeys[outputindex]; left.ChildBufferNumbers[outputindex] = allseeks[outputindex]; left.MaterializedChildNodes[outputindex] = allMaterialized[outputindex]; outputindex++; rightcount = 0; for (int i=0; i<rightcontent; i++) { right.ChildKeys[i] = allkeys[outputindex]; right.ChildBufferNumbers[i] = allseeks[outputindex]; right.MaterializedChildNodes[i] = allMaterialized[outputindex]; outputindex++; rightcount++; } right.ChildBufferNumbers[rightcount] = allseeks[outputindex]; right.MaterializedChildNodes[rightcount] = allMaterialized[outputindex]; left.reParentAllChildren(); right.reParentAllChildren(); }
public static void MergeLeaves(BplusNode left, BplusNode right, out bool DeleteRight) { DeleteRight = false; string[] allkeys = new string[left.Size*2]; long[] allseeks = new long[left.Size*2]; int index = 0; for (int i=0; i<left.Size; i++) { if (left.ChildKeys[i]==null) { break; } allkeys[index] = left.ChildKeys[i]; allseeks[index] = left.ChildBufferNumbers[i]; index++; } for (int i=0; i<right.Size; i++) { if (right.ChildKeys[i]==null) { break; } allkeys[index] = right.ChildKeys[i]; allseeks[index] = right.ChildBufferNumbers[i]; index++; } if (index<=left.Size) { left.Clear(); DeleteRight = true; for (int i=0; i<index; i++) { left.ChildKeys[i] = allkeys[i]; left.ChildBufferNumbers[i] = allseeks[i]; } right.Free(); left.Soil(); 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.ChildBufferNumbers[i] = allseeks[newindex]; newindex++; } for (int i=0; i<rightcontent; i++) { right.ChildKeys[i] = allkeys[newindex]; right.ChildBufferNumbers[i] = allseeks[newindex]; newindex++; } }
/// <summary> /// insert key/position entry in self /// </summary> /// <param name="key">Key to associate with the leaf</param> /// <param name="position">position associated with key in external structur</param> /// <param name="splitString">if not null then the smallest key in the new split leaf</param> /// <param name="splitNode">if not null then the node was split and this is the leaf to the right.</param> /// <returns>null unless the smallest key under this node has changed, in which case it returns the smallest key.</returns> public string Insert(string key, long position, out string splitString, out BplusNode splitNode) { if (IsLeaf) { return InsertLeaf(key, position, out splitString, out splitNode); } splitString = null; splitNode = null; var insertposition = FindAtOrNextPosition(key, false); var insertBufferNumber = m_childBufferNumbers[insertposition]; if (insertBufferNumber==BplusTreeLong.Nullbuffernumber) { throw new BplusTreeException("key not followed by buffer number in non-leaf"); } // insert in subtree var insertChild = MaterializeNodeAtIndex(insertposition); BplusNode childSplit; string childSplitString; var childInsert = insertChild.Insert(key, position, out childSplitString, out childSplit); // if there was a split the node must expand if (childSplit!=null) { // insert the child Soil(); // redundant -- a child will have a change so this node will need to be copied var newChildPosition = insertposition+1; var dosplit = false; // if there is no free space we must do a split if (m_childBufferNumbers[m_size]!=BplusTreeLong.Nullbuffernumber) { dosplit = true; PrepareForSplit(); } // bubble over the current values to make space for new child for (var i=m_childKeys.Length-2; i>=newChildPosition-1; i--) { var i1 = i+1; var i2 = i1+1; m_childKeys[i1] = m_childKeys[i]; m_childBufferNumbers[i2] = m_childBufferNumbers[i1]; var childNode = m_materializedChildNodes[i2] = m_materializedChildNodes[i1]; } // record the new child m_childKeys[newChildPosition-1] = childSplitString; //this.MaterializedChildNodes[newChildPosition] = childSplit; //this.ChildBufferNumbers[newChildPosition] = childSplit.myBufferNumber; childSplit.Reparent(this, newChildPosition); // split, if needed if (dosplit) { var splitpoint = m_materializedChildNodes.Length/2-1; splitString = m_childKeys[splitpoint]; splitNode = new BplusNode(m_owner, m_parent, -1, IsLeaf); // make copy of expanded node structure var materialized = m_materializedChildNodes; var buffernumbers = m_childBufferNumbers; var keys = m_childKeys; // repair the expanded node m_childKeys = new string[m_size]; m_materializedChildNodes = new BplusNode[m_size+1]; m_childBufferNumbers = new long[m_size+1]; Clear(); Array.Copy(materialized, 0, m_materializedChildNodes, 0, splitpoint+1); Array.Copy(buffernumbers, 0, m_childBufferNumbers, 0, splitpoint+1); Array.Copy(keys, 0, m_childKeys, 0, splitpoint); // initialize the new node splitNode.Clear(); // redundant. var remainingKeys = m_size-splitpoint; Array.Copy(materialized, splitpoint+1, splitNode.m_materializedChildNodes, 0, remainingKeys+1); Array.Copy(buffernumbers, splitpoint+1, splitNode.m_childBufferNumbers, 0, remainingKeys+1); Array.Copy(keys, splitpoint+1, splitNode.m_childKeys, 0, remainingKeys); // fix pointers in materialized children of splitnode splitNode.ReParentAllChildren(); // store the new node splitNode.DumpToFreshBuffer(); splitNode.CheckIfTerminal(); splitNode.Soil(); CheckIfTerminal(); } // fix pointers in children ReParentAllChildren(); } if (insertposition==0) { // the smallest key may have changed return childInsert; } return null; // no change in smallest key }