public void DeleteNodeEntry(NodeID nodeID)
        {
            NodeBTreeLeafPage leaf = (NodeBTreeLeafPage)FindLeafBTreePage(nodeID.Value);

            // Remove the entry
            int index = leaf.RemoveEntry(nodeID.Value);

            if (index == 0)
            {
                // scanpst.exe report an error if page key does not match the first entry,
                // so we want to update the parent
                if (leaf.ParentPage != null)
                {
                    if (leaf.NodeEntryList.Count > 0)
                    {
                        UpdateIndexEntry(leaf.ParentPage, leaf.BlockID, leaf.PageKey);
                    }
                    else
                    {
                        DeleteIndexEntry(leaf.ParentPage, leaf.BlockID);
                        DeletePage(leaf);
                        return;
                    }
                }
            }

            // now we have to store the new leaf page, and cascade the changes up to the root page
            UpdatePageAndReferences(leaf);
        }
Exemple #2
0
        public static BTreePage ReadFromStream(Stream stream, BlockRef blockRef)
        {
            long offset = (long)blockRef.ib;

            stream.Seek(offset, SeekOrigin.Begin);
            byte[] buffer = new byte[Length];
            stream.Read(buffer, 0, Length);
            PageTypeName ptype = (PageTypeName)buffer[PageTrailer.OffsetFromPageStart + 0];
            BTreePage    page;
            byte         cLevel = buffer[491];

            if (cLevel > 0)
            {
                // If cLevel is greater than 0, then each entry in the array is of type BTENTRY.
                page = new BTreeIndexPage(buffer);
            }
            else
            {
                // If cLevel is 0, then each entry is either of type BBTENTRY or NBTENTRY, depending on the ptype of the page.
                if (ptype == PageTypeName.ptypeBBT)
                {
                    page = new BlockBTreeLeafPage(buffer);
                }
                else if (ptype == PageTypeName.ptypeNBT)
                {
                    page = new NodeBTreeLeafPage(buffer);
                }
                else
                {
                    throw new ArgumentException("BTreePage has incorrect ptype");
                }
            }
            page.Offset = (ulong)blockRef.ib;
            if (blockRef.bid.Value != page.BlockID.Value)
            {
                throw new InvalidBlockIDException();
            }
            uint crc = PSTCRCCalculation.ComputeCRC(buffer, PageTrailer.OffsetFromPageStart);

            if (page.pageTrailer.dwCRC != crc)
            {
                throw new InvalidChecksumException();
            }

            uint signature = BlockTrailer.ComputeSignature(blockRef.ib, blockRef.bid.Value);

            if (page.pageTrailer.wSig != signature)
            {
                throw new InvalidChecksumException();
            }
            return(page);
        }
        public NodeBTreeEntry FindNodeEntryByNodeID(uint nodeID)
        {
            NodeBTreeLeafPage page = (NodeBTreeLeafPage)FindLeafBTreePage(nodeID);

            if (page != null)
            {
                // page.cLevel is now 0
                List <NodeBTreeEntry> nodeEntryList = page.NodeEntryList;
                foreach (NodeBTreeEntry entry in nodeEntryList)
                {
                    if (entry.nid.Value == nodeID)
                    {
                        return(entry);
                    }
                }
            }
            return(null);
        }
        public NodeBTreeLeafPage Split()
        {
            int newNodeStartIndex     = NodeEntryList.Count / 2;
            NodeBTreeLeafPage newPage = new NodeBTreeLeafPage();

            // BlockID will be given when the page will be added
            newPage.cEntMax           = cEntMax;
            newPage.cbEnt             = cbEnt;
            newPage.cLevel            = cLevel;
            newPage.pageTrailer.ptype = pageTrailer.ptype;
            for (int index = newNodeStartIndex; index < NodeEntryList.Count; index++)
            {
                newPage.NodeEntryList.Add(NodeEntryList[index]);
            }

            NodeEntryList.RemoveRange(newNodeStartIndex, NodeEntryList.Count - newNodeStartIndex);
            return(newPage);
        }
        public void InsertNodeEntry(NodeBTreeEntry entryToInsert)
        {
            ulong             key  = entryToInsert.nid.Value;
            NodeBTreeLeafPage page = (NodeBTreeLeafPage)FindLeafBTreePage(key);

            if (page.NodeEntryList.Count < NodeBTreeLeafPage.MaximumNumberOfEntries)
            {
                int insertIndex = page.InsertSorted(entryToInsert);
                UpdatePageAndReferences(page);
                if (insertIndex == 0 && page.ParentPage != null)
                {
                    // page key has been modified, we must update the parent
                    UpdateIndexEntry(page.ParentPage, page.BlockID, page.PageKey);
                }
            }
            else
            {
                // We have to split the tree node
                NodeBTreeLeafPage newPage = page.Split();
                if (newPage.PageKey < key)
                {
                    newPage.InsertSorted(entryToInsert);
                }
                else
                {
                    int insertIndex = page.InsertSorted(entryToInsert);
                    if (insertIndex == 0 && page.ParentPage != null)
                    {
                        // page key has been modified, we must update the parent
                        UpdateIndexEntry(page.ParentPage, page.BlockID, page.PageKey);
                    }
                }
                UpdatePageAndReferences(page);
                AddPage(newPage);

                if (page.ParentPage == null)
                {
                    // this is a root page and it's full, we have to create a new root
                    CreateNewRoot();
                }

                InsertIndexEntry(page.ParentPage, newPage.NodeEntryList[0].nid.Value, newPage.BlockID);
            }
        }
        public void UpdateNodeEntry(NodeID nodeID, DataTree dataTree, SubnodeBTree subnodeBTree)
        {
            NodeBTreeLeafPage leaf = (NodeBTreeLeafPage)FindLeafBTreePage(nodeID.Value);
            int index = leaf.GetIndexOfEntry(nodeID.Value);

            if (index >= 0)
            {
                leaf.NodeEntryList[index].bidData = new BlockID(0);
                if (dataTree != null && dataTree.RootBlock != null)
                {
                    leaf.NodeEntryList[index].bidData = dataTree.RootBlock.BlockID;
                }

                leaf.NodeEntryList[index].bidSub = new BlockID(0);
                if (subnodeBTree != null && subnodeBTree.RootBlock != null)
                {
                    leaf.NodeEntryList[index].bidSub = subnodeBTree.RootBlock.BlockID;
                }

                // now we have to store the new leaf page, and cascade the changes up to the root page
                UpdatePageAndReferences(leaf);
            }
        }