Exemplo n.º 1
0
        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));
        }
Exemplo n.º 2
0
        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;
            }
        }
Exemplo n.º 3
0
        /// <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));
        }
Exemplo n.º 4
0
        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);
        }
Exemplo n.º 5
0
        // 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));
        }
Exemplo n.º 6
0
        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));
        }
Exemplo n.º 7
0
        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);
        }
Exemplo n.º 8
0
        /// <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);
        }