private BTreeNode Delete_entry(BTreeNode NodetobeDeleted, DBRecord key, BTreeNode Root)
        {
            BTreeCell cell;
            UInt16    offset;
            int       indexInOffsetArray;

            (cell, offset, indexInOffsetArray) = NodetobeDeleted.FindBTreeCell(key, false);
            NodetobeDeleted.DeleteBTreeCell(cell);

            if (NodetobeDeleted.NumCells < MaxCell / 2 && NodetobeDeleted.ParentPage != 0)
            {
                return(Delete_leaf_redistri(NodetobeDeleted, key, Root));
            }
            return(Root);
        }
        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));
        }
Beispiel #3
0
        static void TestInsertIntoAndDeletionInsideBTreeNode()
        {
            string dbPath = "./testdbfile.minidb";

            File.Delete(dbPath);

            Pager pager = new Pager(dbPath);

            pager.ExtendNumberOfPages();
            pager.ExtendNumberOfPages();

            MemoryPage page = pager.ReadPage(1);

            BTreeNode node = new BTreeNode(page, PageTypes.InternalIndexPage);


            // `keys` := (1, 6, 2, 5, 3, 4)
            List <DBRecord> keys = new List <DBRecord>();

            keys.Add(GetTestBRecord(1));
            keys.Add(GetTestBRecord(6));
            keys.Add(GetTestBRecord(2));
            keys.Add(GetTestBRecord(5));
            keys.Add(GetTestBRecord(3));
            keys.Add(GetTestBRecord(4));

            // `cells` := ((1, 0), (6, 1), (2, 2), (5, 3), (3, 4), (4, 5))
            List <InternalIndexCell> cells = new List <InternalIndexCell>();

            cells.Add(new InternalIndexCell(keys[0], 114, GetTestBRecord(0)));
            cells.Add(new InternalIndexCell(keys[1], 114, GetTestBRecord(1)));
            cells.Add(new InternalIndexCell(keys[2], 114, GetTestBRecord(2)));
            cells.Add(new InternalIndexCell(keys[3], 114, GetTestBRecord(3)));
            cells.Add(new InternalIndexCell(keys[4], 114, GetTestBRecord(4)));
            cells.Add(new InternalIndexCell(keys[5], 114, GetTestBRecord(5)));

            byte[]            raw       = cells[0].Pack();
            InternalIndexCell cellClone = new InternalIndexCell(raw, 0);

            node.InsertBTreeCell(cells[0]);
            node.InsertBTreeCell(cells[1]);
            node.InsertBTreeCell(cells[2]);
            node.InsertBTreeCell(cells[3]);
            node.InsertBTreeCell(cells[4]);
            node.InsertBTreeCell(cells[5]);

            List <ushort>            offsets    = node.CellOffsetArray;
            List <InternalIndexCell> clonecells = new List <InternalIndexCell>();

            clonecells.Add((InternalIndexCell)node.GetBTreeCell(offsets[0]));
            clonecells.Add((InternalIndexCell)node.GetBTreeCell(offsets[1]));
            clonecells.Add((InternalIndexCell)node.GetBTreeCell(offsets[2]));
            clonecells.Add((InternalIndexCell)node.GetBTreeCell(offsets[3]));
            clonecells.Add((InternalIndexCell)node.GetBTreeCell(offsets[4]));
            clonecells.Add((InternalIndexCell)node.GetBTreeCell(offsets[5]));

            List <AtomValue> cloneCellKey = clonecells[0].Key.GetValues();

            // all cells (not the list `cells`) inside `node`:
            // ((1, 0), (2, 2), (3, 4), (4, 5), (5, 3), (6, 1))
            // they are all pointing to page #114

            // check if the keys are stored in ascending order
            Assert.Equal(1, node.GetBTreeCell(offsets[0]).Key.GetValues()[0].IntegerValue);
            Assert.Equal(2, node.GetBTreeCell(offsets[1]).Key.GetValues()[0].IntegerValue);
            Assert.Equal(3, node.GetBTreeCell(offsets[2]).Key.GetValues()[0].IntegerValue);
            Assert.Equal(4, node.GetBTreeCell(offsets[3]).Key.GetValues()[0].IntegerValue);
            Assert.Equal(5, node.GetBTreeCell(offsets[4]).Key.GetValues()[0].IntegerValue);
            Assert.Equal(6, node.GetBTreeCell(offsets[5]).Key.GetValues()[0].IntegerValue);

            List <AtomValue> tmpAtomList = null;

            // check if `node` could be iterated by "foreach" statement
            int i = 1;

            foreach (var iteratedCell in node)
            {
                tmpAtomList = iteratedCell.Key.GetValues();
                Assert.Equal(tmpAtomList[0].IntegerValue, i);
                i++;
            }

            // check node indexing
            AssertCell(node[0], cells[0]);
            AssertCell(node[1], cells[2]);

            BTreeCell cell;
            ushort    offset;
            int       indexInOffsetArray;

            // find by the keys below and check if it returns currect cells
            // key 6: value 1
            (cell, offset, indexInOffsetArray) = node.FindBTreeCell(keys[1]);
            tmpAtomList = ((InternalIndexCell)cell).Key.GetValues();
            Assert.Equal(6, tmpAtomList[0].IntegerValue);
            tmpAtomList = ((InternalIndexCell)cell).PrimaryKey.GetValues();
            Assert.Equal(1, tmpAtomList[0].IntegerValue);
            // key 5: value 3
            (cell, offset, indexInOffsetArray) = node.FindBTreeCell(keys[3]);
            tmpAtomList = ((InternalIndexCell)cell).Key.GetValues();
            Assert.Equal(5, tmpAtomList[0].IntegerValue);
            tmpAtomList = ((InternalIndexCell)cell).PrimaryKey.GetValues();
            Assert.Equal(3, tmpAtomList[0].IntegerValue);
            // key 2: value 2
            (cell, offset, indexInOffsetArray) = node.FindBTreeCell(keys[2]);
            tmpAtomList = cell.Key.GetValues();
            Assert.Equal(2, tmpAtomList[0].IntegerValue);
            tmpAtomList = ((InternalIndexCell)cell).PrimaryKey.GetValues();
            Assert.Equal(2, tmpAtomList[0].IntegerValue);

            // delete cell with key == 2
            node.DeleteBTreeCell(offset);

            // check deletion
            offsets     = node.CellOffsetArray;
            tmpAtomList = node.GetBTreeCell(offsets[0]).Key.GetValues();
            Assert.Equal(1, tmpAtomList[0].IntegerValue);
            tmpAtomList = node.GetBTreeCell(offsets[1]).Key.GetValues();
            Assert.Equal(3, tmpAtomList[0].IntegerValue);
            tmpAtomList = node.GetBTreeCell(offsets[2]).Key.GetValues();
            Assert.Equal(4, tmpAtomList[0].IntegerValue);
            tmpAtomList = node.GetBTreeCell(offsets[3]).Key.GetValues();
            Assert.Equal(5, tmpAtomList[0].IntegerValue);
            tmpAtomList = node.GetBTreeCell(offsets[4]).Key.GetValues();
            Assert.Equal(6, tmpAtomList[0].IntegerValue);

            // delete cell with key == 4
            node.DeleteBTreeCell(offsets[2]);

            // check deletion
            offsets     = node.CellOffsetArray;
            tmpAtomList = node.GetBTreeCell(offsets[0]).Key.GetValues();
            Assert.Equal(1, tmpAtomList[0].IntegerValue);
            tmpAtomList = node.GetBTreeCell(offsets[1]).Key.GetValues();
            Assert.Equal(3, tmpAtomList[0].IntegerValue);
            tmpAtomList = node.GetBTreeCell(offsets[2]).Key.GetValues();
            Assert.Equal(5, tmpAtomList[0].IntegerValue);
            tmpAtomList = node.GetBTreeCell(offsets[3]).Key.GetValues();
            Assert.Equal(6, tmpAtomList[0].IntegerValue);

            // delete by index 0 (cell with key == 1)
            node.DeleteBTreeCell(node[0]);
            tmpAtomList = node[0].Key.GetValues();
            Assert.Equal(3, tmpAtomList[0].IntegerValue);
            tmpAtomList = node[1].Key.GetValues();
            Assert.Equal(5, tmpAtomList[0].IntegerValue);
            tmpAtomList = node[2].Key.GetValues();
            Assert.Equal(6, tmpAtomList[0].IntegerValue);

            // delete remaining cells
            node.DeleteBTreeCell(offsets[0]);
            offsets = node.CellOffsetArray;
            node.DeleteBTreeCell(offsets[0]);
            offsets = node.CellOffsetArray;
            node.DeleteBTreeCell(offsets[0]);
            offsets = node.CellOffsetArray;

            pager.Close();
        }
        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);
        }