public BTreeCell FindCell(DBRecord key, BTreeNode root) { BTreeNode child; BTreeCell cell; UInt16 offset; if (root.PageType == PageTypes.LeafTablePage) { (cell, _, _) = root.FindBTreeCell(key, false); return(cell); } // If it's internal node (cell, offset, _) = root.FindBTreeCell(key); MemoryPage nextpage; if (offset == 0) //rightpage { nextpage = _pager.ReadPage((int)root.RightPage); child = new BTreeNode(nextpage); } else { InternalTableCell internalTableCell = (InternalTableCell)cell; nextpage = _pager.ReadPage((int)internalTableCell.ChildPage); child = new BTreeNode(nextpage); } return(FindCell(key, child)); }
private void MergeCells(InternalTableCell cell, DevExpress.Web.ASPxGridView.ASPxGridViewTableRowEventArgs e, string type) { int startIndex = 0, rowSpan = 0; GetMergeInf(ref startIndex, ref rowSpan, e, type); if (e.VisibleIndex == startIndex) { cell.RowSpan = rowSpan; } else if (e.VisibleIndex <= startIndex + rowSpan) { cell.Visible = false; } }
/// <summary> /// <para>Insert cell into a non-full node `node` if `node` is a leaf node.</para> /// <para>If `node` is not the leaf node, the child node of `node` might need to split before recursively performing this function to the child node.</para> /// <para>`node` should be ensured to be not full.</para> /// </summary> /// <param name="node">node being inserted</param> /// <param name="newKey">new key value</param> /// <param name="dBRecord">new row/record</param> /// <returns>new root node</returns> private BTreeNode InsertNonFull(BTreeNode node, DBRecord newKey, DBRecord dBRecord) { // the actual insertion performs in leaf node if (node.PageType == PageTypes.LeafTablePage) { BTreeCell check_repeat; (check_repeat, _, _) = node.FindBTreeCell(newKey, false); if (check_repeat != null) { throw new RepeatedKeyException($"The primary key to be inserted ({newKey.GetValues()[0]}) is repeated!"); } LeafTableCell newCell = new LeafTableCell(newKey, dBRecord); node.InsertBTreeCell(newCell); return(node); } // find the child node to try to insert BTreeNode child; BTreeCell cell; UInt16 offset; (cell, offset, _) = node.FindBTreeCell(newKey); MemoryPage nextpage; if (offset == 0) // rightest page { nextpage = _pager.ReadPage((int)node.RightPage); child = new BTreeNode(nextpage); } else { InternalTableCell internalTableCell = (InternalTableCell)cell; nextpage = _pager.ReadPage((int)internalTableCell.ChildPage); child = new BTreeNode(nextpage); } // child needs to split if (child.NumCells >= MaxCell) { SplitNode(child, node, newKey); return(InsertNonFull(node, newKey, dBRecord)); } return(InsertNonFull(child, newKey, dBRecord)); }
static void TestInternalTableCell() { // init record DBRecord record = GetTestBRecord(); // make raw bytes List <byte> rawNode = new List <byte>(); rawNode.AddRange(new byte[30]); // build cell InternalTableCell internalTableCell = new InternalTableCell(record, 114514); byte[] raw = internalTableCell.Pack(); rawNode.AddRange(raw); // clone InternalTableCell clone = new InternalTableCell(rawNode.ToArray(), 30); // assert AssertCell(internalTableCell, clone); Assert.Equal(internalTableCell.ChildPage, clone.ChildPage); }
// if `isFuzzySearch`, this function will return the first cell that with key equal or larger than that of `cell`'s private BTreeNode FindNode(DBRecord key, BTreeNode root, bool isFuzzySearch = false) { BTreeNode child; BTreeCell cell; UInt16 offset; if (root.PageType == PageTypes.LeafTablePage) { (cell, _, _) = root.FindBTreeCell(key, isFuzzySearch); if (cell != null) { return(root); } else { return(null); } } //If it's internal node (cell, offset, _) = root.FindBTreeCell(key); MemoryPage nextpage; if (offset == 0) //rightpage { nextpage = _pager.ReadPage((int)root.RightPage); child = new BTreeNode(nextpage); } else { InternalTableCell internalTableCell = (InternalTableCell)cell; nextpage = _pager.ReadPage((int)internalTableCell.ChildPage); child = new BTreeNode(nextpage); } return(FindNode(key, child)); }
private BTreeNode Delete_leaf_redistri(BTreeNode NodetobeDeleted, DBRecord key, BTreeNode Root) { BTreeCell cell; UInt16 offset; int indexInOffsetArray; MemoryPage parentPage = _pager.ReadPage((int)NodetobeDeleted.ParentPage); BTreeNode parentNode = new BTreeNode(parentPage); (cell, offset, indexInOffsetArray) = parentNode.FindBTreeCell(key); //the deleted node is not on the right page of parentNode if (cell != null) { MemoryPage brotherPage = _pager.ReadPage((int)NodetobeDeleted.RightPage); BTreeNode brotherNode = new BTreeNode(brotherPage); //If there is a node on the left of the deleted node,it need to be connected to the brother node. if (indexInOffsetArray >= 1) { InternalTableCell leftNodeCell = (InternalTableCell)parentNode.GetBTreeCell(parentNode.CellOffsetArray[indexInOffsetArray - 1]); MemoryPage leftPage = _pager.ReadPage((int)leftNodeCell.ChildPage); BTreeNode leftNode = new BTreeNode(leftPage); leftNode.RightPage = (uint)brotherNode.RawPage.PageNumber; } if (brotherNode.NumCells + NodetobeDeleted.NumCells <= MaxCell) //merge { //After the merge,one cell in the parentNode will be deleted parentNode.DeleteBTreeCell(cell); //merge two node for (int i = 0; i < NodetobeDeleted.NumCells; i++) { brotherNode.InsertBTreeCell(NodetobeDeleted.GetBTreeCell(NodetobeDeleted.CellOffsetArray[i])); } DeleteNode(NodetobeDeleted); } else //redistribute { BTreeCell movedCell = brotherNode.GetBTreeCell(brotherNode.CellOffsetArray[0]); DBRecord newKey = brotherNode.GetBTreeCell(brotherNode.CellOffsetArray[1]).Key; NodetobeDeleted.InsertBTreeCell(movedCell); brotherNode.DeleteBTreeCell(movedCell); BTreeCell parent_Cell; UInt16 parent_offset; int parent_indexInOffsetArray; (parent_Cell, parent_offset, parent_indexInOffsetArray) = parentNode.FindBTreeCell(key); InternalTableCell newCell = new InternalTableCell(newKey, (uint)NodetobeDeleted.RawPage.PageNumber); parentNode.DeleteBTreeCell(parent_Cell); parentNode.InsertBTreeCell(newCell); } } //The node to be deleted is on the rightpage,the brother node is on the left else { InternalTableCell brotherCell = (InternalTableCell)parentNode.GetBTreeCell(parentNode.CellOffsetArray[parentNode.NumCells - 1]); MemoryPage brotherPage = _pager.ReadPage((int)brotherCell.ChildPage); BTreeNode brotherNode = new BTreeNode(brotherPage); //The right page of brother node should be 0 brotherNode.RightPage = NodetobeDeleted.RightPage; if (brotherNode.NumCells + NodetobeDeleted.NumCells <= MaxCell) //merge { //After the merge,one cell in the parentNode will be deleted parentNode.DeleteBTreeCell(brotherCell); //merge two node for (int i = 0; i < NodetobeDeleted.NumCells; i++) { brotherNode.InsertBTreeCell(NodetobeDeleted.GetBTreeCell(NodetobeDeleted.CellOffsetArray[i])); } DeleteNode(NodetobeDeleted); parentNode.RightPage = (uint)brotherNode.RawPage.PageNumber; } else //redistribute { BTreeCell movedCell = brotherNode.GetBTreeCell(brotherNode.CellOffsetArray[brotherNode.NumCells - 1]); DBRecord newKey = movedCell.Key; NodetobeDeleted.InsertBTreeCell(movedCell); brotherNode.DeleteBTreeCell(movedCell); BTreeCell parent_Cell; UInt16 parent_offset; int parent_indexInOffsetArray; (parent_Cell, parent_offset, parent_indexInOffsetArray) = parentNode.FindBTreeCell(key); InternalTableCell newCell = new InternalTableCell(newKey, (uint)NodetobeDeleted.RawPage.PageNumber); parentNode.DeleteBTreeCell(parent_Cell); parentNode.InsertBTreeCell(newCell); } } NodetobeDeleted = parentNode; //deal with parent Nodes return(Delete_internal_redistribute(NodetobeDeleted, key, Root)); }
private BTreeNode Delete_internal_redistribute(BTreeNode NodetobeDeleted, DBRecord key, BTreeNode Root) { InternalTableCell tmpCell; MemoryPage tmpPage; BTreeNode tmpNode; BTreeCell cell; UInt16 offset; int indexInOffsetArray; MemoryPage parentPage = null; BTreeNode parentNode = null; while (NodetobeDeleted.NumCells < (MaxCell + 1) / 2) { //The root if (NodetobeDeleted.ParentPage == 0) { if (NodetobeDeleted.NumCells == 0) { MemoryPage NewRootPage = _pager.ReadPage((int)NodetobeDeleted.RightPage); BTreeNode newRoot = new BTreeNode(NewRootPage); newRoot.ParentPage = 0; return(newRoot); } return(Root); } else { parentPage = _pager.ReadPage((int)NodetobeDeleted.ParentPage); parentNode = new BTreeNode(parentPage); (cell, offset, indexInOffsetArray) = parentNode.FindBTreeCell(key); //The node to be deleted isn't on the rightpage if (cell != null) { InternalTableCell brotherCell = null; MemoryPage brotherPage = null; BTreeNode brotherNode = null; //if the right brother is on rightpage if (indexInOffsetArray + 1 == parentNode.NumCells) { brotherPage = _pager.ReadPage((int)parentNode.RightPage); brotherNode = new BTreeNode(brotherPage); } else { brotherCell = (InternalTableCell)parentNode.GetBTreeCell(parentNode.CellOffsetArray[indexInOffsetArray + 1]); brotherPage = _pager.ReadPage((int)brotherCell.ChildPage); brotherNode = new BTreeNode(brotherPage); } //merge if (brotherNode.NumCells + NodetobeDeleted.NumCells < MaxCell) { for (int i = 0; i < NodetobeDeleted.NumCells; i++) { tmpCell = (InternalTableCell)NodetobeDeleted.GetBTreeCell(NodetobeDeleted.CellOffsetArray[i]); brotherNode.InsertBTreeCell(tmpCell); tmpPage = _pager.ReadPage((int)tmpCell.ChildPage); tmpNode = new BTreeNode(tmpPage); tmpNode.ParentPage = (uint)brotherNode.RawPage.PageNumber; } //move the cell in parentNode to brotherNode InternalTableCell insertCell = new InternalTableCell(cell.Key, (uint)NodetobeDeleted.RightPage); brotherNode.InsertBTreeCell(insertCell); tmpPage = _pager.ReadPage((int)insertCell.ChildPage); tmpNode = new BTreeNode(tmpPage); tmpNode.ParentPage = (uint)brotherNode.RawPage.PageNumber; DeleteNode(NodetobeDeleted); parentNode.DeleteBTreeCell(cell); } //redistribute else { InternalTableCell movedCell = (InternalTableCell)brotherNode.GetBTreeCell(brotherNode.CellOffsetArray[0]); DBRecord upperKey = movedCell.Key; DBRecord downKey = cell.Key; InternalTableCell insertDeletedCell = new InternalTableCell(downKey, (uint)NodetobeDeleted.RightPage); NodetobeDeleted.InsertBTreeCell(insertDeletedCell); NodetobeDeleted.RightPage = movedCell.ChildPage; tmpPage = _pager.ReadPage((int)movedCell.ChildPage); tmpNode = new BTreeNode(tmpPage); tmpNode.ParentPage = (uint)NodetobeDeleted.RawPage.PageNumber; InternalTableCell insertParentCell = new InternalTableCell(upperKey, (uint)NodetobeDeleted.RawPage.PageNumber); parentNode.DeleteBTreeCell(cell); parentNode.InsertBTreeCell(insertParentCell); brotherNode.DeleteBTreeCell(movedCell); } } //The node to be deleted is on the rightpage else { InternalTableCell brotherCell = null; MemoryPage brotherPage = null; BTreeNode brotherNode = null; brotherCell = (InternalTableCell)parentNode.GetBTreeCell(parentNode.CellOffsetArray[parentNode.NumCells - 1]); brotherPage = _pager.ReadPage((int)brotherCell.ChildPage); brotherNode = new BTreeNode(brotherPage); //merge if (brotherNode.NumCells + NodetobeDeleted.NumCells < MaxCell) { for (int i = 0; i < brotherNode.NumCells; i++) { tmpCell = (InternalTableCell)brotherNode.GetBTreeCell(brotherNode.CellOffsetArray[i]); NodetobeDeleted.InsertBTreeCell(tmpCell); tmpPage = _pager.ReadPage((int)tmpCell.ChildPage); tmpNode = new BTreeNode(tmpPage); tmpNode.ParentPage = (uint)NodetobeDeleted.RawPage.PageNumber; } //move the cell in parentNode to brotherNode InternalTableCell insertCell = new InternalTableCell(brotherCell.Key, (uint)brotherNode.RightPage); NodetobeDeleted.InsertBTreeCell(insertCell); tmpPage = _pager.ReadPage((int)insertCell.ChildPage); tmpNode = new BTreeNode(tmpPage); tmpNode.ParentPage = (uint)NodetobeDeleted.RawPage.PageNumber; DeleteNode(brotherNode); parentNode.DeleteBTreeCell(parentNode.GetBTreeCell(parentNode.CellOffsetArray[parentNode.NumCells - 1])); } //redistribute else { DBRecord downKey = parentNode.GetBTreeCell(parentNode.CellOffsetArray[parentNode.NumCells - 1]).Key; InternalTableCell insertDeletedCell = new InternalTableCell(downKey, brotherNode.RightPage); NodetobeDeleted.InsertBTreeCell(insertDeletedCell); InternalTableCell movedCell = (InternalTableCell)brotherNode.GetBTreeCell(brotherNode.CellOffsetArray[brotherNode.NumCells - 1]); brotherNode.RightPage = movedCell.ChildPage; DBRecord upperKey = movedCell.Key; InternalTableCell insertParentCell = new InternalTableCell(upperKey, (uint)brotherNode.RawPage.PageNumber); parentNode.InsertBTreeCell(insertParentCell); brotherNode.DeleteBTreeCell(movedCell); tmpPage = _pager.ReadPage((int)brotherNode.RightPage); tmpNode = new BTreeNode(tmpPage); tmpNode.ParentPage = (uint)brotherNode.RawPage.PageNumber; } } } NodetobeDeleted = parentNode; } return(Root); }
/// <summary> /// Split `nodeTobeSplit`, which has a `parantNode`. /// </summary> /// <param name="nodeTobeSplit">node to be split.</param> /// <param name="parantNode">parent node of `nodeTobeSplit`.</param> /// <param name="newKey">the value of new key. This could affect where to split.</param> private void SplitNode(BTreeNode nodeTobeSplit, BTreeNode parantNode, DBRecord newKey) { int i; // new node will be appended to `nodeTobeSplit` BTreeNode splitNode = GetNewNode(nodeTobeSplit.PageType); // tmp is used for the change of parentPage InternalTableCell tmpCell; MemoryPage tmpPage; // key should be the primary key to be inserted in the parent node int deleteIndex = nodeTobeSplit.NumCells / 2; // right bound of the left node DBRecord rightmostKeyInLeftNode = nodeTobeSplit[deleteIndex - 1].Key; if ((newKey.GetValues()[0] >= rightmostKeyInLeftNode.GetValues()[0]).BooleanValue) { // the new key should be put at the split node on the right deleteIndex++; rightmostKeyInLeftNode = nodeTobeSplit[deleteIndex - 1].Key; } // `deleteIndex` is now pointing to the first cell of the pending right node // loop through the right part of `nodeTobeSplit` for (i = deleteIndex; i < this.MaxCell; i++) { ushort deleteOffSet = nodeTobeSplit.CellOffsetArray[deleteIndex]; // change the parent Page fields of their children if (nodeTobeSplit.PageType == PageTypes.InternalTablePage) { tmpCell = (InternalTableCell)nodeTobeSplit.GetBTreeCell(deleteOffSet); tmpPage = _pager.ReadPage((int)tmpCell.ChildPage); new BTreeNode(tmpPage) { ParentPage = (uint)splitNode.RawPage.PageNumber }; } // move the cells in `nodeTobeSplit` belonging to the pending right node to `splitNode` splitNode.InsertBTreeCell(nodeTobeSplit.GetBTreeCell(deleteOffSet)); nodeTobeSplit.DeleteBTreeCell(deleteOffSet); } // new cell to be inserted to the parent node of `nodeTobeSplit` // If the `parentNode` need to spilt, this will be wrong. However, it could be ensured not happenning because it is a top-down process. InternalTableCell newCellToAscend = new InternalTableCell(rightmostKeyInLeftNode, (uint)nodeTobeSplit.RawPage.PageNumber); // make alias for readability BTreeNode leftNode = nodeTobeSplit; BTreeNode rightNode = splitNode; // connect two nodes `leftNode` and `rightNode` by `RightPage` pointer rightNode.RightPage = leftNode.RightPage; if (leftNode.PageType == PageTypes.LeafTablePage) { leftNode.RightPage = (uint)rightNode.RawPage.PageNumber; } // if `leftNode` is an internal node, the middle cell in the original `nodeTobeSplit` (the rightmost cell in the now `leftNode`) has to be deleted else if (leftNode.PageType == PageTypes.InternalTablePage) { // for internal node, the `ParentPage` of child page need to be changed // the rightmost child of `leftNode` sets its parent to `rightNode` tmpPage = _pager.ReadPage((int)leftNode.RightPage); new BTreeNode(tmpPage) { ParentPage = (uint)rightNode.RawPage.PageNumber }; // the rightmost Cell In the pending Left Node InternalTableCell rightmostCellInLeftNode = (InternalTableCell)leftNode[deleteIndex - 1]; // set the rightmost child of `leftNode` to the left child of `rightmostCellInLeftNode` leftNode.RightPage = rightmostCellInLeftNode.ChildPage; // leftNode.DeleteBTreeCell(rightmostCellInLeftNode); // the same as the code below, but the code below runs faster leftNode.DeleteBTreeCell(leftNode.CellOffsetArray[deleteIndex - 1]); // the deleted rightmost cell in left node sets the parent of its left child to that left node tmpPage = _pager.ReadPage((int)rightmostCellInLeftNode.ChildPage); new BTreeNode(tmpPage) { ParentPage = (uint)leftNode.RawPage.PageNumber }; } rightNode.ParentPage = (uint)parantNode.RawPage.PageNumber; // reconnect the particular cell (or right) in the parent node because of the change of the child node // This is a new empty root if (parantNode.NumCells == 0) { parantNode.RightPage = (uint)rightNode.RawPage.PageNumber; } // There are some cell in the parents node else { BTreeCell cell; (cell, _, _) = parantNode.FindBTreeCell(rightmostKeyInLeftNode); // The case when the node to be inserted into parent node is in the rightest position if (cell == null) { parantNode.RightPage = (uint)rightNode.RawPage.PageNumber; } // The normal case else { InternalTableCell tmp_cell = new InternalTableCell(cell.Key, (uint)rightNode.RawPage.PageNumber); parantNode.DeleteBTreeCell(cell); parantNode.InsertBTreeCell(tmp_cell); } } // This must be done after we reconnect the treeNode parantNode.InsertBTreeCell(newCellToAscend); }