internal bool Insert(string keyword, long dataByteOffset, BPlusTreeNode parentNode) { //i <- n[x] //if leaf[x] // then while i >= 1 and k < keyi[x] // do keyi+1[x] <- keyi[x] // i <- i - 1 // keyi+1[x] <- k // n[x] <- n[x] + 1 // Disk-Write(x) // else while i >= and k < keyi[x] // do i <- i - 1 // i <- i + 1 // Disk-Read(ci[x]) // if n[ci[x]] = 2t - 1 // then B-Tree-Split-Child(x, i, ci[x]) // if k > keyi[x] // then i <- i + 1 // B-Tree-Insert-Nonfull(ci[x], k) int i = KeywordCount - 1; if (IsLeaf) { while (i > -1 && String.Compare(keyword, Keywords[i], false) < 0) { Keywords[i + 1] = Keywords[i]; ChildrenByteOffsets[i + 1] = ChildrenByteOffsets[i]; i--; } Keywords[i + 1] = keyword; ChildrenByteOffsets[i + 1] = dataByteOffset; KeywordCount++; return(Write(parentNode)); } else { while (i > -1 && String.Compare(keyword, Keywords[i], false) < 0) { i--; } i++; BPlusTreeNode child = BPlusTreeNode.Read(_tree, ChildrenByteOffsets[i], true); _tree.Log(("Inspecting node @ " + child.FileOffset + " -> ").PadRight(50) + child.ToString()); if (!child.IsFull) { return(child.Insert(keyword, dataByteOffset, this)); } else { // must first split the child BPlusTreeNode newChild = SplitChild(i, child, parentNode); if (String.Compare(keyword, newChild.Keywords[0], false) < 0) { // new keyword belongs somewhere below the original child return(child.Insert(keyword, dataByteOffset, this)); } else { // new keyword belongs somewhere below the new child return(newChild.Insert(keyword, dataByteOffset, this)); } } } }
// here's the vernacular: // The _keywords array represents all the keywords in this node. // The _byteRanges array represents all the file offsets in this node for either (a) a keyword or (b) the data itself. // a. If it is located in an index node (i.e. non-Leaf), the byte range represents the start/end offsets in the index file (used for traversing to other nodes) // b. If it is located in a Leaf node, the byte range represents the start/end offsets in the data file (for looking up associated hit(s)) // Think ByteRange = pointer to next node or data, Keyword = item we're searching by // So we always have 1 more pointer (or byterange, BR) than search item (or keyword, K): // // |-------- Node ---------| // | go pi | // | / | | | \ | // | BR1 K1 BR2 K2 BR3 | // |-----------------------| /// <summary> /// Creates a new root node for the tree and makes the original root the first child of the new root. /// </summary> /// <param name="tree"></param> /// <returns></returns> internal static BPlusTreeNode ReplaceRoot(BPlusTree tree, BPlusTreeNode originalRoot, string keyword, long dataByteOffset) { // NOTE: This is a very special case. // replacing the root involves creating 2 new nodes: // 1. the new root node // 2. splitting the existing root node into 2 nodes, one of which is a new one BPlusTreeNode newRoot = null; // create a new root node, mark it as not a leaf, put it in exact same spot as original root newRoot = new BPlusTreeNode { IsLeaf = false, _tree = tree, Keywords = new string[tree.Fanout], ChildrenByteOffsets = new long[tree.Fanout + 1], KeywordCount = 0, FileOffset = -1, LeftSiblingFileOffset = -1, RightSiblingFileOffset = -1, }; tree.Log("------------ BEGIN Replacing root ------------"); tree.Log("BEGIN Replacing root. original node -> ".PadRight(50) + originalRoot.ToString()); tree.Log("BEGIN Replacing root. new node -> ".PadRight(50) + newRoot.ToString()); // add our new root to file, update the root node pointer BPlusAbandonedNode abandoned = tree.GetNextAvailableNodeLocation(originalRoot); newRoot.FileOffset = abandoned.FileOffset; newRoot.Write(null); tree.WriteRootNodeOffset(newRoot.FileOffset); // trickle-down insert the new keyword/data if (!String.IsNullOrEmpty(keyword)) { // split the original BPlusTreeNode newChild = newRoot.SplitChild(0, originalRoot, null); tree.Log("CONTINUE Replacing root. new child node -> ".PadRight(50) + originalRoot.ToString()); if (newRoot.Insert(keyword, dataByteOffset, null)) { // the new root was relocated during insertion (outgrew its allotted space) // the insert should take care of it // re-read it in just in case newRoot = BPlusTreeNode.Read(tree, newRoot.FileOffset, true); } } else { newRoot = BPlusTreeNode.Read(tree, newRoot.FileOffset, true); } tree.Log("END Replacing root. original node -> ".PadRight(50) + originalRoot.ToString()); // _tree.Log("END Replacing root. new child node -> ".PadRight(50) + newChild.ToString()); tree.Log("END Replacing root. new root -> ".PadRight(50) + newRoot.ToString()); tree.Log("------------ END Replacing root ------------"); return(newRoot); }