public void AddPage(BTreePage page) { // It is not clear whether new BTree pages should be marked as internal or not // Outlook sometimes chooses to mark them as internal, and sometimes not (for both BBT and NBT) page.BlockID = m_file.Header.AllocateNextPageBlockID(); m_pageBuffer.Add(page.BlockID.Value, page); m_pagesToWrite.Add(page.BlockID.Value); }
/// <summary> /// After modifying a page, we must update its parent's BlockID to refer to the new page /// </summary> protected void UpdatePageAndReferences(BTreePage page) { ulong currentBlockID = page.BlockID.Value; UpdatePage(page); if (currentBlockID != page.BlockID.Value && page.ParentPage != null) { // we must update the parent to refer to the new page, // and cascade the changes up to the root page CascadeUpReferenceUpdate(page.ParentPage, currentBlockID, page.BlockID.Value); } }
public BTreePage GetPage(BlockRef blockRef) { ulong blockID = blockRef.bid.Value; if (m_pageBuffer.ContainsKey(blockID)) { return(m_pageBuffer[blockID]); } else { BTreePage page = BTreePage.ReadFromStream(m_file.BaseStream, blockRef); m_pageBuffer.Add(blockRef.bid.Value, page); return(page); } }
private static int CompareByCLevel(BTreePage x, BTreePage y) { if (x.cLevel > y.cLevel) { return(1); } else if (x.cLevel < y.cLevel) { return(-1); } else { return(0); } }
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; }
public void DeletePage(BTreePage page) { ulong blockID = page.BlockID.Value; if (m_pageBuffer.ContainsKey(blockID)) { // remove the old block from the cache m_pageBuffer.Remove(blockID); } // no need to free a block that has not been written yet if (IsPagePendingWrite(page)) { m_pagesToWrite.Remove(blockID); } else { m_offsetsToFree.Add(page.Offset); } }
/// <summary> /// Find the leaf BTreePage where the entry with the given key should be located /// We use this method for search and insertion /// Note: the returned BTreePage will have its ParentPage set (can be traversed up to the bTreeRootPage) /// </summary> protected BTreePage FindLeafBTreePage(ulong key) { BTreePage currentPage = m_bTreeRootPage; int cLevel = m_bTreeRootPage.cLevel; while (cLevel > 0) { int matchingIndex = ((BTreeIndexPage)currentPage).GetIndexOfEntryWithMatchingRange(key); BTreeIndexEntry matchingEntry = ((BTreeIndexPage)currentPage).IndexEntryList[matchingIndex]; BTreePage childPage = GetPage(matchingEntry.BREF); childPage.ParentPage = (BTreeIndexPage)currentPage; currentPage = childPage; cLevel--; if (cLevel != currentPage.cLevel) { throw new Exception("Invalid Page cLevel"); } } return(currentPage); }
public void UpdatePage(BTreePage page) { if (IsPagePendingWrite(page)) { m_pageBuffer[page.BlockID.Value] = page; } else { ulong oldBlockID = page.BlockID.Value; if (m_pageBuffer.ContainsKey(oldBlockID)) { // remove the old block from the buffer m_pageBuffer.Remove(oldBlockID); } m_offsetsToFree.Add(page.Offset); page.BlockID = m_file.Header.AllocateNextPageBlockID(); m_pageBuffer.Add(page.BlockID.Value, page); m_pagesToWrite.Add(page.BlockID.Value); } }
public BTree(PSTFile file, BTreePage bTreeRootPage) : base(file) { m_bTreeRootPage = bTreeRootPage; }
public BlockBTree(PSTFile file, BTreePage bTreeRootPage) : base(file, bTreeRootPage) { }
public bool IsPagePendingWrite(BTreePage page) { return(IsPagePendingWrite(page.BlockID.Value)); }
public NodeBTree(PSTFile file, BTreePage bTreeRootPage) : base(file, bTreeRootPage) { }