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 void CreateNewRoot() { BTreeIndexPage newRoot = BTreeIndexPage.GetEmptyIndexPage(m_bTreeRootPage.pageTrailer.ptype, m_bTreeRootPage.cLevel + 1); BTreeIndexEntry rootIndexEntry = new BTreeIndexEntry(); // We make sure the old root page has been updated (to prevent the BlockID from changing during update) UpdatePage(m_bTreeRootPage); rootIndexEntry.btkey = m_bTreeRootPage.PageKey; rootIndexEntry.BREF.bid = m_bTreeRootPage.BlockID; rootIndexEntry.BREF.ib = 0; // this will tell BufferedBTreePageStore that the block hasn't been written yet newRoot.IndexEntryList.Add(rootIndexEntry); AddPage(newRoot); m_bTreeRootPage.ParentPage = newRoot; m_bTreeRootPage = newRoot; }
/// <param name="blockID">BlockID of the child page with the new key</param> protected void UpdateIndexEntry(BTreeIndexPage indexPage, BlockID blockIDOfChild, ulong newKeyOfChild) { for (int index = 0; index < indexPage.IndexEntryList.Count; index++) { BTreeIndexEntry entry = indexPage.IndexEntryList[index]; if (entry.BREF.bid.Value == blockIDOfChild.Value) { entry.btkey = newKeyOfChild; UpdatePageAndReferences(indexPage); // parents will now refer to the new blockID if (index == 0 && indexPage.ParentPage != null) { // page key has been modified, we must update the parent as well UpdateIndexEntry(indexPage.ParentPage, indexPage.BlockID, indexPage.PageKey); } } } }
private void CascadeUpReferenceUpdate(BTreeIndexPage indexPage, ulong oldBlockID, ulong newBlockID) { int index = indexPage.GetIndexOfBlockID(oldBlockID); if (index >= 0) { BTreeIndexEntry entry = indexPage.IndexEntryList[index]; entry.BREF.bid = new BlockID(newBlockID); entry.BREF.ib = 0; // this will tell BufferedBTreePageStore that the block hasn't been written yet ulong currentBlockID = indexPage.BlockID.Value; UpdatePage(indexPage); if (currentBlockID != indexPage.BlockID.Value && indexPage.ParentPage != null) { CascadeUpReferenceUpdate(indexPage.ParentPage, currentBlockID, indexPage.BlockID.Value); } } }
public BTreeIndexPage Split() { int newNodeStartIndex = IndexEntryList.Count / 2; BTreeIndexPage newPage = new BTreeIndexPage(); // 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 < IndexEntryList.Count; index++) { newPage.IndexEntryList.Add(IndexEntryList[index]); } IndexEntryList.RemoveRange(newNodeStartIndex, IndexEntryList.Count - newNodeStartIndex); return(newPage); }
protected void InsertIndexEntry(BTreeIndexPage indexPage, BTreeIndexEntry entryToInsert) { if (indexPage.IndexEntryList.Count < BTreeIndexPage.MaximumNumberOfEntries) { int insertIndex = indexPage.InsertSorted(entryToInsert); UpdatePageAndReferences(indexPage); if (insertIndex == 0 && indexPage.ParentPage != null) { // page key has been modified, we must update the parent UpdateIndexEntry(indexPage.ParentPage, indexPage.BlockID, indexPage.PageKey); } } else { // The tree node is full, we have to split it BTreeIndexPage newPage = indexPage.Split(); if (newPage.PageKey < entryToInsert.btkey) { newPage.InsertSorted(entryToInsert); } else { int insertIndex = indexPage.InsertSorted(entryToInsert); if (insertIndex == 0 && indexPage.ParentPage != null) { // page key has been modified, we must update the parent UpdateIndexEntry(indexPage.ParentPage, indexPage.BlockID, indexPage.PageKey); } } UpdatePageAndReferences(indexPage); AddPage(newPage); if (indexPage.ParentPage == null) { // this is a root page and it's full, we have to create a new root CreateNewRoot(); } // We made sure we have a parent to add our new page to InsertIndexEntry(indexPage.ParentPage, newPage.PageKey, newPage.BlockID); } }