/// <summary> /// insert key/position entry in self (as leaf) /// </summary> /// <param name="key">Key to associate with the leaf</param> /// <param name="position">position associated with key in external structure</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>smallest key value in keys, or null if no change</returns> public string InsertLeaf(string key, long position, out string splitString, out BplusNode splitNode) { splitString = null; splitNode = null; bool dosplit = false; if (!this.isLeaf) { throw new BplusTreeException("bad call to InsertLeaf: this is not a leaf"); } this.Soil(); int insertposition = this.FindAtOrNextPosition(key, false, true); if (insertposition>=this.Size) { //throw new BplusTreeException("key too big and leaf is full"); dosplit = true; this.PrepareForSplit(); } else { // if it's already there then change the value at the current location (duplicate entries not supported). if (this.ChildKeys[insertposition]==null || this.owner.Compare(this.ChildKeys[insertposition], key, true)==0) // this.ChildKeys[insertposition].Equals(key) { this.ChildBufferNumbers[insertposition] = position; this.ChildKeys[insertposition] = key; if (insertposition==0) { return key; } else { return null; } } } // check for a null position int nullindex = insertposition; while (nullindex<this.ChildKeys.Length && this.ChildKeys[nullindex]!=null) { nullindex++; } if (nullindex>=this.ChildKeys.Length) { if (dosplit) { throw new BplusTreeException("can't split twice!!"); } //throw new BplusTreeException("no space in leaf"); dosplit = true; this.PrepareForSplit(); } // bubble in the new info XXXX THIS SHOULD BUBBLE BACKWARDS string nextkey = this.ChildKeys[insertposition]; long nextposition = this.ChildBufferNumbers[insertposition]; this.ChildKeys[insertposition] = key; this.ChildBufferNumbers[insertposition] = position; while (nextkey!=null) { key = nextkey; position = nextposition; insertposition++; nextkey = this.ChildKeys[insertposition]; nextposition = this.ChildBufferNumbers[insertposition]; this.ChildKeys[insertposition] = key; this.ChildBufferNumbers[insertposition] = position; } // split if needed if (dosplit) { int splitpoint = this.ChildKeys.Length/2; int splitlength = this.ChildKeys.Length - splitpoint; splitNode = new BplusNode(this.owner, this.parent, -1, this.isLeaf); // copy the split info into the splitNode Array.Copy(this.ChildBufferNumbers, splitpoint, splitNode.ChildBufferNumbers, 0, splitlength); Array.Copy(this.ChildKeys, splitpoint, splitNode.ChildKeys, 0, splitlength); Array.Copy(this.MaterializedChildNodes, splitpoint, splitNode.MaterializedChildNodes, 0, splitlength); splitString = splitNode.ChildKeys[0]; // archive the new node splitNode.DumpToFreshBuffer(); // store the node data temporarily long[] buffernumbers = this.ChildBufferNumbers; string[] keys = this.ChildKeys; BplusNode[] nodes = this.MaterializedChildNodes; // repair current node, copy in the other part of the split this.ChildBufferNumbers = new long[this.Size+1]; this.ChildKeys = new string[this.Size]; this.MaterializedChildNodes = new BplusNode[this.Size+1]; Array.Copy(buffernumbers, 0, this.ChildBufferNumbers, 0, splitpoint); Array.Copy(keys, 0, this.ChildKeys, 0, splitpoint); Array.Copy(nodes, 0, this.MaterializedChildNodes, 0, splitpoint); for (int i=splitpoint; i<this.ChildKeys.Length; i++) { this.ChildKeys[i] = null; this.ChildBufferNumbers[i] = BplusTreeLong.NULLBUFFERNUMBER; this.MaterializedChildNodes[i] = null; } // store the new node //splitNode.DumpToFreshBuffer(); this.owner.RecordTerminalNode(splitNode); splitNode.Soil(); } //return this.ChildKeys[0]; if (insertposition==0) { return key; // smallest key changed. } else { return null; // no change in smallest key } }
/// <summary> /// insert key/position entry in self (as leaf) /// </summary> /// <param name="key">Key to associate with the leaf</param> /// <param name="position">position associated with key in external structure</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>smallest key value in keys, or null if no change</returns> public string InsertLeaf(string key, long position, out string splitString, out BplusNode splitNode) { splitString = null; splitNode = null; var dosplit = false; if (!IsLeaf) { throw new BplusTreeException("bad call to InsertLeaf: this is not a leaf"); } Soil(); var insertposition = FindAtOrNextPosition(key, false); if (insertposition>=m_size) { //throw new BplusTreeException("key too big and leaf is full"); dosplit = true; PrepareForSplit(); } else { // if it's already there then change the value at the current location (duplicate entries not supported). if (m_childKeys[insertposition]==null || m_owner.Compare(m_childKeys[insertposition], key)==0) // this.ChildKeys[insertposition].Equals(key) { m_childBufferNumbers[insertposition] = position; m_childKeys[insertposition] = key; if (insertposition==0) { return key; } else { return null; } } } // check for a null position var nullindex = insertposition; while (nullindex<m_childKeys.Length && m_childKeys[nullindex]!=null) { nullindex++; } if (nullindex>=m_childKeys.Length) { if (dosplit) { throw new BplusTreeException("can't split twice!!"); } //throw new BplusTreeException("no space in leaf"); dosplit = true; PrepareForSplit(); } // bubble in the new info XXXX THIS SHOULD BUBBLE BACKWARDS var nextkey = m_childKeys[insertposition]; var nextposition = m_childBufferNumbers[insertposition]; m_childKeys[insertposition] = key; m_childBufferNumbers[insertposition] = position; while (nextkey!=null) { key = nextkey; position = nextposition; insertposition++; nextkey = m_childKeys[insertposition]; nextposition = m_childBufferNumbers[insertposition]; m_childKeys[insertposition] = key; m_childBufferNumbers[insertposition] = position; } // split if needed if (dosplit) { var splitpoint = m_childKeys.Length/2; var splitlength = m_childKeys.Length - splitpoint; splitNode = new BplusNode(m_owner, m_parent, -1, IsLeaf); // copy the split info into the splitNode Array.Copy(m_childBufferNumbers, splitpoint, splitNode.m_childBufferNumbers, 0, splitlength); Array.Copy(m_childKeys, splitpoint, splitNode.m_childKeys, 0, splitlength); Array.Copy(m_materializedChildNodes, splitpoint, splitNode.m_materializedChildNodes, 0, splitlength); splitString = splitNode.m_childKeys[0]; // archive the new node splitNode.DumpToFreshBuffer(); // store the node data temporarily var buffernumbers = m_childBufferNumbers; var keys = m_childKeys; var nodes = m_materializedChildNodes; // repair current node, copy in the other part of the split m_childBufferNumbers = new long[m_size+1]; m_childKeys = new string[m_size]; m_materializedChildNodes = new BplusNode[m_size+1]; Array.Copy(buffernumbers, 0, m_childBufferNumbers, 0, splitpoint); Array.Copy(keys, 0, m_childKeys, 0, splitpoint); Array.Copy(nodes, 0, m_materializedChildNodes, 0, splitpoint); for (var i=splitpoint; i<m_childKeys.Length; i++) { m_childKeys[i] = null; m_childBufferNumbers[i] = BplusTreeLong.Nullbuffernumber; m_materializedChildNodes[i] = null; } // store the new node //splitNode.DumpToFreshBuffer(); m_owner.RecordTerminalNode(splitNode); splitNode.Soil(); } //return this.ChildKeys[0]; if (insertposition==0) { return key; // smallest key changed. } else { return null; // no change in smallest key } }
/// <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 }
/// <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 }