public void EndSavingChanges() { CommitChanges(); AllocationHelper.ValidateAllocationMap(this); m_isSavingChanges = false; }
/// <summary> /// The caller must update its reference to point to the new root /// </summary> public virtual void SaveChanges() { foreach (ulong blockID in m_blocksToWrite) { Block block = m_blockBuffer[blockID]; long offset = AllocationHelper.AllocateSpaceForBlock(m_file, block.TotalLength); block.WriteToStream(m_file.BaseStream, offset); m_file.BlockBTree.InsertBlockEntry(block.BlockID, offset, block.DataLength); } foreach (ulong blockID in m_blocksToFree) { BlockBTreeEntry entry = m_file.FindBlockEntryByBlockID(blockID); entry.cRef--; // Any leaf BBT entry that points to a BID holds a reference count to it. if (entry.cRef == 1) { // we can mark the allocation to be freed and delete the entry, // We should not free the allocation until the BBT is committed. m_file.MarkAllocationToBeFreed(entry.BREF.ib, Block.GetTotalBlockLength(entry.cb)); m_file.BlockBTree.DeleteBlockEntry(entry.BREF.bid); } else { m_file.BlockBTree.UpdateBlockEntry(entry.BREF.bid, entry.cRef); } } m_blocksToWrite.Clear(); m_blocksToFree.Clear(); }
public void SaveChanges() { List <BTreePage> pages = new List <BTreePage>(); foreach (BTreePage page in m_pageBuffer.Values) { if (m_pagesToWrite.Contains(page.BlockID.Value)) { pages.Add(page); } } SortByCLevel(pages, false); // we now have the pages in ascending cLevel order (i.e. leaves first) // we need them this way because we need to update the offset from old pages to new pages // so we must write children first // for new blocks: Dictionary <ulong, long> blockToOffset = new Dictionary <ulong, long>(); foreach (BTreePage page in pages) { if (page is BTreeIndexPage) // page.cLevel > 0 { // parent page, we may need to update references BTreeIndexPage indexPage = (BTreeIndexPage)page; for (int index = 0; index < indexPage.IndexEntryList.Count; index++) { ulong childBlockID = indexPage.IndexEntryList[index].BREF.bid.Value; if (indexPage.IndexEntryList[index].BREF.ib == 0) // reference to a new / updated block { long blockOffset = blockToOffset[childBlockID]; indexPage.IndexEntryList[index].BREF.ib = (ulong)blockOffset; } } } long newPageAllocationOffset = AllocationHelper.AllocateSpaceForPage(m_file); blockToOffset.Add(page.BlockID.Value, newPageAllocationOffset); page.Offset = (ulong)newPageAllocationOffset; // we may need this later byte[] pageBytes = page.GetBytes((ulong)newPageAllocationOffset); m_file.BaseStream.Seek(newPageAllocationOffset, SeekOrigin.Begin); m_file.BaseStream.Write(pageBytes, 0, pageBytes.Length); } // free all the marked pages foreach (ulong offset in m_offsetsToFree) { AllocationHelper.FreePageAllocation(m_file, (long)offset); } m_pagesToWrite.Clear(); m_offsetsToFree.Clear(); }
public void BeginSavingChanges() { if (!Header.root.IsAllocationMapValid) { throw new InvalidAllocationMapException(); } // We want to make sure outlook will rebuild the allocation map if the operation does not complete successfully AllocationHelper.InvalidateAllocationMap(this); m_isSavingChanges = true; }
public void CommitChanges() { // We must save changes to the SMQ before committing the BBT / NBT if (m_searchManagementQueue != null) { m_searchManagementQueue.SaveChanges(); } this.BlockBTree.SaveChanges(); this.NodeBTree.SaveChanges(); // Only after we saved changes to the BBT, we may free blocks, // this is to prevent blocks that are referenced by the BBT to be freed prematurely (before changes are committed) foreach (KeyValuePair <ulong, int> offsetToFree in m_offsetsToFree) { ulong offset = offsetToFree.Key; int length = offsetToFree.Value; AllocationHelper.FreeAllocation(this, (long)offset, length); } m_offsetsToFree.Clear(); UpdateBlockBTreeRootReference(); UpdateNodeBTreeRootReference(); }