public void SinglePage(int pageSize) { var fsManager = new FileSystemPageManager(pageSize); var manager = new CachingPageManager(fsManager, 100, 100); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); // append a page IPage page = manager.CreatePage(); // fill and update it var r = new Random(); r.NextBytes(page.Content); manager.UpdatePage(page); // fetch updated content IPage fetchedPage = manager.FetchPage(page.Index); Assert.IsTrue(AreEqualByteArrays(page.Content, fetchedPage.Content)); // remove it manager.RemovePage(page.Index); // try to fetch removed page Assert.Throws <PageMapException>(() => manager.FetchPage(page.Index)); // resurrect and check content page = manager.CreatePage(); Assert.IsTrue(AreEqualByteArrays(new byte[manager.PageSize], page.Content)); } }
public void FixedSizeItemsLength() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var fsm = new FreeSpaceMap(manager); var memoryManager = new MemoryManager(fsm, manager); int count = 1000; var items = new Dictionary <DbItemReference, byte[]>(); var r = new Random(); // allocate items for (int i = 0; i < count; i++) { var sizeRange = GetRandomFixedSizeItemsSizeRange(); var content = GenerateRandomSequence(DbItem.GetMaxSize(sizeRange) - r.Next(5)); var reference = memoryManager.Allocate(content); items[reference] = content; } // check lengths foreach (var reference in items.Keys) { Assert.AreEqual(items[reference].Length, memoryManager.GetLength(reference)); } } }
public void MultiPage(int pageSize) { var manager = new FileSystemPageManager(pageSize); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var r = new Random(); // fill storage with random data int pageCount = 1000; var pages = new IPage[pageCount]; for (int i = 0; i < pageCount; i++) { pages[i] = manager.CreatePage(); r.NextBytes(pages[i].Content); manager.UpdatePage(pages[i]); } // fetch and compare pages CheckStoragePages(pages, manager); // generate a random indexes int k = 0; var indexesToDelete = new long[pageCount / 2]; while (k < pageCount / 2) { int index = r.Next(pageCount); if (!indexesToDelete.Contains(index)) { indexesToDelete[k] = index; k++; } } // remove pages with these indexes foreach (long i in indexesToDelete) { manager.RemovePage(i); } // fetch and compare pages CheckStoragePages(pages, manager, indexesToDelete); // add more pages for (int i = 0; i < pageCount; i++) { if (indexesToDelete.Contains(pages[i].Index)) { pages[i] = manager.CreatePage(); r.NextBytes(pages[i].Content); manager.UpdatePage(pages[i]); } } // check again CheckStoragePages(pages, manager); } }
public void InsertVariableSizeItemAfterDelete() { int pageSize = 4096; var dummyPageManager = new FileSystemPageManager(pageSize); var p = new Page(dummyPageManager, 0, new byte[pageSize]); var header = new RadixTreeNodesPageHeader { FreeSpace = (ushort)PageFormatter.GetMaximalFreeSpace((PageSize)p.Length) }; PageFormatter.InitPage(p, header); var r = new Random(); var items = new List <byte[]>(); var item = new byte[r.Next(100) + 1]; r.NextBytes(item); short itemIndex = 0; while (itemIndex != -1) { itemIndex = PageFormatter.AddVariableSizeItem(p, item); items.Add(item); item = new byte[r.Next(100) + 1]; r.NextBytes(item); } bool hasRemainingItems; // replace with the same PageFormatter.DeleteVariableSizeItem(p, 1, out hasRemainingItems); Assert.AreEqual(1, PageFormatter.AddVariableSizeItem(p, items[1])); item = PageFormatter.ReadVariableSizeItem(p, 1); Assert.IsTrue(AreEqualByteArrays(items[1], item)); // replace with smaller one PageFormatter.DeleteVariableSizeItem(p, 1, out hasRemainingItems); var smallItem = new byte[items[1].Length / 2 + 1]; r.NextBytes(smallItem); Assert.AreEqual(1, PageFormatter.AddVariableSizeItem(p, smallItem)); item = PageFormatter.ReadVariableSizeItem(p, 1); Assert.IsTrue(AreEqualByteArrays(smallItem, item)); // and put original again PageFormatter.DeleteVariableSizeItem(p, 1, out hasRemainingItems); PageFormatter.AddVariableSizeItem(p, items[1]); item = PageFormatter.ReadVariableSizeItem(p, 1); Assert.IsTrue(AreEqualByteArrays(items[1], item)); }
public void FixedSizeItemsAllocation() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var fsm = new FreeSpaceMap(manager); var memoryManager = new MemoryManager(fsm, manager); int count = 100000; var items = new Dictionary <DbItemReference, byte[]>(); // allocate items for (int i = 0; i < count; i++) { var sizeRange = GetRandomFixedSizeItemsSizeRange(); var content = GenerateRandomSequence(DbItem.GetMaxSize(sizeRange)); var reference = memoryManager.Allocate(content); items[reference] = content; } // check contents foreach (var reference in items.Keys) { Assert.IsTrue(AreEqualByteArrays(items[reference], memoryManager.Get(reference).RawData)); } // free half of the items var freedItems = new Dictionary <DbItemReference, byte[]>(); foreach (var reference in items.Keys) { if (_r.NextDouble() > 0.5) { memoryManager.Free(reference); freedItems[reference] = items[reference]; } } // check that the items do not exist foreach (var reference in freedItems.Keys) { Assert.IsNull(memoryManager.Get(reference)); } // and the remaining items still available foreach (var reference in items.Keys.Where(item => !freedItems.ContainsKey(item))) { Assert.IsTrue(AreEqualByteArrays(items[reference], memoryManager.Get(reference).RawData)); } } }
public void ShouldSuccessfulyCreateFsm() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); new FreeSpaceMap(manager); } }
/// <summary> /// Initializes a new instance of the RecoveryFile /// </summary> /// <param name="pageManager"></param> /// <param name="pageSize"></param> public RecoveryFile(FileSystemPageManager pageManager, int pageSize) { if (pageManager == null) { throw new ArgumentNullException(nameof(pageManager)); } _pageManager = pageManager; _pageSize = pageSize; }
public void ConcurrentAccess() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); _sharedManager = manager; // create threads var threads = new List <Thread>(); for (int i = 0; i < 5; i++) { threads.Add(new Thread(AddPagesRoutine)); } // and start them foreach (Thread thread in threads) { thread.Start(); } // wait for end of work foreach (Thread thread in threads) { thread.Join(); } // fetch and compare pages CheckStoragePages(_sharedPages, manager); threads.Clear(); // run the same test for random operations for (int i = 0; i < 5; i++) { threads.Add(new Thread(RandomOperationsRoutine)); } foreach (Thread thread in threads) { thread.Start(); } foreach (Thread thread in threads) { thread.Join(); } CheckStoragePages(_sharedPages, manager); } }
public void PageHasNoRemainingItemsAfterDelete() { int pageSize = 4096; var dummyPageManager = new FileSystemPageManager(pageSize); var p = new Page(dummyPageManager, 0, new byte[pageSize]); var header = new RadixTreeNodesPageHeader { FreeSpace = (ushort)PageFormatter.GetMaximalFreeSpace((PageSize)p.Length) }; PageFormatter.InitPage(p, header); var r = new Random(); var items = new List <byte[]>(); var item = new byte[r.Next(100) + 1]; r.NextBytes(item); short itemIndex = 0; while (itemIndex != -1) { itemIndex = PageFormatter.AddVariableSizeItem(p, item); if (itemIndex == -1) { continue; } items.Add(item); item = new byte[r.Next(100) + 1]; r.NextBytes(item); } bool hasRemainingItems; for (short i = 0; i < items.Count; i++) { PageFormatter.DeleteVariableSizeItem(p, i, out hasRemainingItems); if (i < items.Count - 1) { Assert.IsTrue(hasRemainingItems); } else { Assert.IsFalse(hasRemainingItems); } } }
public void RandomAccess() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var r = new Random(); // fill storage with random data int pageCount = 1000; var pages = new List <IPage>(); for (int i = 0; i < pageCount; i++) { pages.Add(manager.CreatePage()); r.NextBytes(pages[i].Content); manager.UpdatePage(pages[i]); } int operationCount = 1000; for (int k = 0; k < operationCount; k++) { int op = r.Next(3); switch (op) { case 0: // update int index = r.Next(pages.Count - 1); r.NextBytes(pages[index].Content); manager.UpdatePage(pages[index]); break; case 1: // add IPage page = manager.CreatePage(); r.NextBytes(page.Content); manager.UpdatePage(page); pages.Add(page); break; case 2: // remove index = r.Next(pages.Count - 1); manager.RemovePage(pages[index].Index); pages.RemoveAt(index); break; } } // fetch and compare pages CheckStoragePages(pages, manager); } }
public void CorrectlyRecoverSequentiallyUpdatedPage() { long index; using (var fileSystemPageManager = new FileSystemPageManager(4096)) using (var storage = new Storage(fileSystemPageManager)) { storage.OpenOrCreate(StoragePath); var page = fileSystemPageManager.CreatePage(); index = page.Index; } string fileName; using (var fileSystemPageManager = new FileSystemPageManager(4096)) using (var storage = new Storage(fileSystemPageManager)) using (var recoveryFile = new RecoveryFile(fileSystemPageManager, fileSystemPageManager.PageSize)) { storage.OpenOrCreate(StoragePath); var page = fileSystemPageManager.FetchPage(index); index = page.Index; fileSystemPageManager.Dispose(); Assert.AreEqual(index, page.Index); Assert.AreNotEqual(0xff, page.Content[10]); // Update twice with different bytes to make sure the latest one wins page.Content[9] = 0xaa; page.Content[10] = 0xaa; recoveryFile.WriteUpdatePageRecord(page); page.Content[10] = 0xff; recoveryFile.WriteUpdatePageRecord(page); recoveryFile.WriteFinalMarker(); fileName = recoveryFile.FileName; } Assert.True(File.Exists(fileName)); Assert.GreaterOrEqual(new FileInfo(fileName).Length, 1); Assert.AreNotEqual(index, 0); using (var manager = new FileSystemPageManager(4096)) using (var storage = new Storage(manager)) { storage.OpenOrCreate(StoragePath); var page = manager.FetchPage(index); Assert.AreEqual(index, page.Index); Assert.AreEqual(0xaa, page.Content[9]); Assert.AreEqual(0xff, page.Content[10]); } }
public void FixedSizeItemsPage() { int pageSize = 32768; var dummyPageManager = new FileSystemPageManager(pageSize); var p = new Page(dummyPageManager, 0, new byte[pageSize]); var header = new FixedSizeItemsPageHeader(); var r = new Random(); foreach (var sizeRange in EnumHelper.FixedSizeItemsSizeRanges()) { header.SizeRange = sizeRange; PageFormatter.InitPage(p, header); var item = new DbItem(new byte[DbItem.GetMaxSize(header.SizeRange)]); r.NextBytes(item.RawData); // fill the page with the items short count = 0; bool spaceRemains = true; while (PageFormatter.HasFreeSpaceForFixedSizeItem(p)) { Assert.IsTrue(spaceRemains); PageFormatter.AddFixedSizeItem(p, item, out spaceRemains); count++; Assert.AreEqual(count, PageFormatter.ReadFixedSizeItemsCount(p)); } Assert.IsFalse(spaceRemains); // check if fetched objects are equal to originals for (short j = 0; j < PageFormatter.ReadFixedSizeItemsCount(p); j++) { DbItem readItem = PageFormatter.ReadFixedSizeItem(p, j); Assert.IsTrue(AreEqualByteArrays(item.RawData, readItem.RawData)); } // delete all added items short itemindex = 0; while (PageFormatter.ReadFixedSizeItemsCount(p) > 0) { PageFormatter.DeleteFixedSizeItem(p, itemindex); count--; itemindex++; Assert.AreEqual(count, PageFormatter.ReadFixedSizeItemsCount(p)); } } }
public void OnEmptyStorageShouldReturnMinusOneForRequestedFreePageIndex() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var fsm = new FreeSpaceMap(manager); foreach (var fsmValue in EnumHelper.FixedSizeItemsFsmValues()) { Assert.AreEqual(-1, fsm.GetFreePageIndex(fsmValue)); } } }
public void OnEmptyStorageAllRequestedPagesShouldBeFull() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var fsm = new FreeSpaceMap(manager); int entryCount = PageFormatter.GetFsmEntryCount(manager.FetchPage(1)); for (int i = 0; i < entryCount; i++) { Assert.AreEqual(FsmValue.Full, fsm.Get(i)); } } }
public void ReadVariableSizeItems() { int pageSize = 4096; var dummyPageManager = new FileSystemPageManager(pageSize); var p = new Page(dummyPageManager, 0, new byte[pageSize]); var header = new RadixTreeNodesPageHeader { FreeSpace = (ushort)PageFormatter.GetMaximalFreeSpace((PageSize)p.Length) }; PageFormatter.InitPage(p, header); var r = new Random(); var items = new List <byte[]>(); var item = new byte[r.Next(100) + 1]; r.NextBytes(item); while (PageFormatter.AddVariableSizeItem(p, item) != -1) { items.Add(item); item = new byte[r.Next(100) + 1]; r.NextBytes(item); } for (short i = 0; i < items.Count; i++) { item = PageFormatter.ReadVariableSizeItem(p, i); Assert.IsTrue(AreEqualByteArrays(items[i], item)); } bool hasRemainingItems; PageFormatter.DeleteVariableSizeItem(p, 0, out hasRemainingItems); PageFormatter.DeleteVariableSizeItem(p, 2, out hasRemainingItems); PageFormatter.DeleteVariableSizeItem(p, (short)(items.Count - 1), out hasRemainingItems); Assert.Throws <PageFormatException>(() => PageFormatter.ReadVariableSizeItem(p, 0)); Assert.Throws <PageFormatException>(() => PageFormatter.ReadVariableSizeItem(p, 2)); Assert.Throws <PageFormatException>(() => PageFormatter.ReadVariableSizeItem(p, (short)(items.Count - 1))); }
public void CorrectlyApplyDeleteRecord() { long deleteIndex; using (var fileSystemPageManager = new FileSystemPageManager(4096)) using (var storage = new Storage(fileSystemPageManager)) { storage.OpenOrCreate(StoragePath); deleteIndex = fileSystemPageManager.CreatePage().Index; } using (var fileSystemPageManager = new FileSystemPageManager(4096)) using (var storage = new Storage(fileSystemPageManager)) { storage.OpenOrCreate(StoragePath); Assert.True(fileSystemPageManager.PageExists(deleteIndex)); } string fileName; using (var fileSystemPageManager = new FileSystemPageManager(4096)) using (var storage = new Storage(fileSystemPageManager)) using (var recoveryFile = new RecoveryFile(fileSystemPageManager, fileSystemPageManager.PageSize)) { storage.OpenOrCreate(StoragePath); fileSystemPageManager.Dispose(); recoveryFile.WriteDeletePageRecord(deleteIndex); recoveryFile.WriteFinalMarker(); fileName = recoveryFile.FileName; } Assert.True(File.Exists(fileName)); Assert.GreaterOrEqual(new FileInfo(fileName).Length, 1); using (var manager = new FileSystemPageManager(4096)) using (var storage = new Storage(manager)) { storage.OpenOrCreate(StoragePath); Assert.False(manager.PageExists(deleteIndex)); Assert.AreEqual(deleteIndex, manager.CreatePage().Index); } }
public void SinglePage(int pageSize) { var manager = new FileSystemPageManager(pageSize); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); // append a page IPage page = manager.CreatePage(); // fill and update it var r = new Random(); r.NextBytes(page.Content); manager.UpdatePage(page); // fetch updated content IPage fetchedPage = manager.FetchPage(page.Index); Assert.IsTrue(AreEqualByteArrays(page.Content, fetchedPage.Content)); // remove it manager.RemovePage(page.Index); bool exceptionThrown = false; // try to fetch removed page try { manager.FetchPage(page.Index); } catch (PageMapException) { exceptionThrown = true; } if (!exceptionThrown) { Assert.Fail("Exception was not thrown"); } // resurrect and check content page = manager.CreatePage(); Assert.IsTrue(AreEqualByteArrays(new byte[manager.PageSize], page.Content)); } }
public void MultiPageOperations() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var fsm = new FreeSpaceMap(manager); int entryPerPage = PageFormatter.GetFsmEntryCount(manager.FetchPage(1)); int entryCount = entryPerPage * 3; // check writing to the last page var value = FsmValue.Class0; var index = entryCount - 1; fsm.Set(index, value); Assert.AreEqual(value, fsm.Get(index)); // middle page value = FsmValue.Class1; index = entryPerPage + 1; fsm.Set(index, value); Assert.AreEqual(value, fsm.Get(index)); // the first page value = FsmValue.Class2; index = entryPerPage - 1; fsm.Set(index, value); Assert.AreEqual(value, fsm.Get(index)); for (int i = 0; i < entryCount; i++) { fsm.Set(i, FsmValue.Class3); } for (int i = 0; i < entryCount; i++) { long pageIndex = fsm.GetFreePageIndex(FsmValue.Class3); Assert.AreNotEqual(-1, pageIndex); fsm.Set(i, FsmValue.Full); } } }
public void MultipageItemSegments() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var fsm = new FreeSpaceMap(manager); var memoryManager = new MemoryManager(fsm, manager); var content = GenerateRandomSequence(4096 * 5 + 100); DbItemReference reference = memoryManager.Allocate(content); // check full content Assert.IsTrue(AreEqualByteArrays(content, memoryManager.GetItemSegment(reference, 0, content.Length - 1))); var bytes = new byte[2]; // check first two bytes Array.Copy(content, 0, bytes, 0, 2); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, 0, 1))); // check next two bytes Array.Copy(content, 2, bytes, 0, 2); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, 2, 3))); // check last two bytes Array.Copy(content, content.Length - 2, bytes, 0, 2); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, content.Length - 2, content.Length - 1))); //last but two bytes Array.Copy(content, content.Length - 4, bytes, 0, 2); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, content.Length - 4, content.Length - 3))); //all except first two bytes and last two bytes bytes = new byte[content.Length - 4]; Array.Copy(content, 2, bytes, 0, content.Length - 4); Assert.IsTrue(AreEqualByteArrays(bytes, memoryManager.GetItemSegment(reference, 2, content.Length - 3))); } }
private void AddPagesRoutine() { FileSystemPageManager manager = _sharedManager; var r = new Random(); // fill storage with random data int pageCount = 1000; for (int i = 0; i < pageCount; i++) { var page = manager.CreatePage(); lock (_locker) { _sharedPages.Add(page); } r.NextBytes(page.Content); manager.UpdatePage(page); } }
public void SinglePageOperations() { var manager = new FileSystemPageManager(4096); using (var storage = new Storage(manager)) { storage.CreateNew(StoragePath); var fsm = new FreeSpaceMap(manager); var r = new Random(); int entryCount = PageFormatter.GetFsmEntryCount(manager.FetchPage(1)); for (int i = 0; i < 100000; i++) { var value = (FsmValue)r.Next((int)FsmValue.Max); var index = r.Next(entryCount); fsm.Set(index, value); Assert.AreEqual(value, fsm.Get(index)); } } }
public void FsmPage() { int pageSize = 32768; var dummyPageManager = new FileSystemPageManager(pageSize); var p = new Page(dummyPageManager, 0, new byte[pageSize]); var fsmh = new FreeSpaceMapPageHeader(); var r = new Random(); PageFormatter.InitPage(p, fsmh); int fsmEntryCount = PageFormatter.GetFsmEntryCount(p); // set all values to "full" PageFormatter.SetAllFsmValues(p, FsmValue.Full); // check if all values are actually "full" for (int i = 0; i < fsmEntryCount; i++) { Assert.AreEqual(FsmValue.Full, PageFormatter.GetFsmValue(p, i)); } var values = new FsmValue[fsmEntryCount]; // set and keep random values for (int i = 0; i < fsmEntryCount; i++) { var value = (byte)r.Next((byte)FsmValue.Full + 1); PageFormatter.SetFsmValue(p, i, (FsmValue)value); values[i] = (FsmValue)value; } // compare it for (int i = 0; i < fsmEntryCount; i++) { Assert.AreEqual(values[i], PageFormatter.GetFsmValue(p, i)); } }
/// <summary> /// Creates a new storage instance with specified types of keys and values. /// </summary> /// <typeparam name="TKey">The type of key</typeparam> /// <typeparam name="TValue">The type of value</typeparam> /// <param name="keySerializer">Object implementing ISerializer interface for key serialization</param> /// <param name="valueSerializer">Object implementing ISerializer interface for value serialization</param> /// <param name="settings">Setiings of creating storage</param> /// <returns>New storage instance</returns> public IBPlusTreeKeyValueStorage <ComparableKeyOf <TKey>, ValueOf <TValue> > CreateBPlusTreeStorage <TKey, TValue>(ISerializer <TKey> keySerializer, ISerializer <TValue> valueSerializer, BPlusTreeStorageSettings settings) where TKey : IComparable { bool usePageCache = settings.CacheSettings != null; if (settings.MaxEmptyPages < 0) { throw new ArgumentException("MaxEmptyPages shouldn't be negative", nameof(settings)); } if (usePageCache) { if (settings.CacheSettings.MaxCachedPages < 0) { throw new ArgumentException("MaxCachedPages shouldn't be negative", nameof(settings)); } if (settings.CacheSettings.MaxDirtyPages < 0) { throw new ArgumentException("MaxDirtyPages shouldn't be negative", nameof(settings)); } if (settings.CacheSettings.MaxDirtyPages > settings.CacheSettings.MaxCachedPages) { throw new ArgumentException("MaxDirtyPages shouldn be equal to or less than MaxCachedPages", nameof(settings)); } } IPageManager pageManager = null; IPageManager fsPageManager = null; try { var asyncWriteBuffer = usePageCache ? Math.Min(settings.CacheSettings.MaxDirtyPages, 1000) : 100; fsPageManager = new FileSystemPageManager((int)settings.PageSize, settings.ForcedWrites, asyncWriteBuffer, true) { MaxEmptyPages = settings.MaxEmptyPages }; pageManager = usePageCache ? new CachingPageManager(fsPageManager, settings.CacheSettings.MaxCachedPages, settings.CacheSettings.MaxDirtyPages) : fsPageManager; var ks = new Serializer <ComparableKeyOf <TKey> >(obj => keySerializer.Serialize(obj), bytes => keySerializer.Deserialize(bytes)); var vs = new Serializer <ValueOf <TValue> >(obj => valueSerializer.Serialize(obj), bytes => valueSerializer.Deserialize(bytes)); if (settings.MaxKeySize <= 0) { throw new ArgumentException("MaxKeySize size should be positive", nameof(settings)); } var bPlusTree = new BPlusTree <ComparableKeyOf <TKey>, ValueOf <TValue> >( new BPlusTreeNodeStorage <ComparableKeyOf <TKey> >(pageManager, ks, settings.MaxKeySize), new ValueStorage <ValueOf <TValue> >(new MemoryManager(new FreeSpaceMap(pageManager), pageManager), vs)); return(new BPlusTreeKeyValueStorage <ComparableKeyOf <TKey>, ValueOf <TValue> >(pageManager, bPlusTree, settings.MaxKeySize, settings.AutoFlushInterval, settings.AutoFlushTimeout)); } catch (Exception) { if (pageManager != null) { pageManager.Close(); } else { fsPageManager?.Close(); } throw; } }
public void CorrectWriteAndReadAllHeaders() { int pageSize = 4096; var dummyPageManager = new FileSystemPageManager(pageSize); var p = new Page(dummyPageManager, 0, new byte[pageSize]); var hph = new HeadingPageHeader(); PageFormatter.InitPage(p, hph); PageHeaderBase phb = PageFormatter.GetPageHeader(p); Assert.IsInstanceOf <HeadingPageHeader>(phb); Assert.AreEqual(hph.Length, phb.Length); Assert.AreEqual(hph.PageType, phb.PageType); Assert.AreEqual(hph.SizeRange, phb.SizeRange); var fsiph = new FixedSizeItemsPageHeader(); PageFormatter.InitPage(p, fsiph); phb = PageFormatter.GetPageHeader(p); Assert.IsInstanceOf <FixedSizeItemsPageHeader>(phb); Assert.AreEqual(fsiph.Length, phb.Length); Assert.AreEqual(fsiph.PageType, phb.PageType); Assert.AreEqual(fsiph.SizeRange, phb.SizeRange); var mpph = new MultipageItemPageHeader(); PageFormatter.InitPage(p, mpph); phb = PageFormatter.GetPageHeader(p); Assert.IsInstanceOf <MultipageItemPageHeader>(phb); Assert.AreEqual(mpph.Length, phb.Length); Assert.AreEqual(mpph.PageType, phb.PageType); Assert.AreEqual(mpph.SizeRange, phb.SizeRange); Assert.AreEqual(mpph.StartPageIndex, ((MultipageItemPageHeader)phb).StartPageIndex); Assert.AreEqual(mpph.PreviousPageIndex, ((MultipageItemPageHeader)phb).PreviousPageIndex); Assert.AreEqual(mpph.NextPageIndex, ((MultipageItemPageHeader)phb).NextPageIndex); var fsmph = new FreeSpaceMapPageHeader(); PageFormatter.InitPage(p, fsmph); phb = PageFormatter.GetPageHeader(p); Assert.IsInstanceOf <FreeSpaceMapPageHeader>(phb); Assert.AreEqual(fsmph.Length, phb.Length); Assert.AreEqual(fsmph.PageType, phb.PageType); Assert.AreEqual(fsmph.SizeRange, phb.SizeRange); Assert.AreEqual(fsmph.BasePageIndex, ((FreeSpaceMapPageHeader)phb).BasePageIndex); var tnph = new BPlusTreeNodePageHeader(); PageFormatter.InitPage(p, tnph); phb = PageFormatter.GetPageHeader(p); Assert.IsInstanceOf <BPlusTreeNodePageHeader>(phb); Assert.AreEqual(tnph.Length, phb.Length); Assert.AreEqual(tnph.PageType, phb.PageType); Assert.AreEqual(tnph.SizeRange, phb.SizeRange); Assert.AreEqual(tnph.ParentPageIndex, ((BPlusTreeNodePageHeader)phb).ParentPageIndex); Assert.AreEqual(tnph.PreviousPageIndex, ((BPlusTreeNodePageHeader)phb).PreviousPageIndex); Assert.AreEqual(tnph.NextPageIndex, ((BPlusTreeNodePageHeader)phb).NextPageIndex); var rtnph = new RadixTreeNodesPageHeader(); PageFormatter.InitPage(p, rtnph); phb = PageFormatter.GetPageHeader(p); Assert.IsInstanceOf <RadixTreeNodesPageHeader>(phb); Assert.AreEqual(rtnph.Length, phb.Length); Assert.AreEqual(rtnph.PageType, phb.PageType); Assert.AreEqual(rtnph.SizeRange, phb.SizeRange); Assert.AreEqual(rtnph.FreeSpace, ((RadixTreeNodesPageHeader)phb).FreeSpace); }
/// <summary> /// Creates a new storage instance with specified types of keys and values. /// </summary> /// <typeparam name="TKey">The type of key</typeparam> /// <typeparam name="TValue">The type of value</typeparam> /// <param name="keySerializer">Object implementing ISerializer interface for key serialization</param> /// <param name="valueSerializer">Object implementing ISerializer interface for value serialization</param> /// <param name="settings">Setiings of creating storage</param> /// <returns>New storage instance</returns> public IKeyValueStorage <KeyOf <TKey>, ValueOf <TValue> > CreateRadixTreeStorage <TKey, TValue>(ISerializer <TKey> keySerializer, ISerializer <TValue> valueSerializer, RadixTreeStorageSettings settings) { bool usePageCache = settings.CacheSettings != null; if (settings.MaxEmptyPages < 0) { throw new ArgumentException("MaxEmptyPages shouldn't be negative", nameof(settings)); } if (usePageCache) { if (settings.CacheSettings.MaxCachedPages < 0) { throw new ArgumentException("MaxCachedPages shouldn't be negative", nameof(settings)); } if (settings.CacheSettings.MaxDirtyPages < 0) { throw new ArgumentException("MaxDirtyPages shouldn't be negative", nameof(settings)); } if (settings.CacheSettings.MaxDirtyPages > settings.CacheSettings.MaxCachedPages) { throw new ArgumentException("MaxDirtyPages shouldn be equal to or less than MaxCachedPages", nameof(settings)); } } IPageManager pageManager = null; IPageManager fsPageManager = null; try { fsPageManager = new FileSystemPageManager((int)settings.PageSize, settings.ForcedWrites, 1, true) { MaxEmptyPages = settings.MaxEmptyPages }; pageManager = usePageCache ? new CachingPageManager(fsPageManager, settings.CacheSettings.MaxCachedPages, settings.CacheSettings.MaxDirtyPages) : fsPageManager; var ks = new Serializer <KeyOf <TKey> >(obj => keySerializer.Serialize(obj), bytes => keySerializer.Deserialize(bytes)); var vs = new Serializer <ValueOf <TValue> >(obj => valueSerializer.Serialize(obj), bytes => valueSerializer.Deserialize(bytes)); var radixTree = new RadixTree <KeyOf <TKey>, ValueOf <TValue> >( new RadixTreeNodeStorage(pageManager), new ValueStorage <ValueOf <TValue> >(new MemoryManager(new FreeSpaceMap(pageManager), pageManager), vs), ks); return(new RadixTreeKeyValueStorage <KeyOf <TKey>, ValueOf <TValue> >(pageManager, radixTree, settings.AutoFlushInterval, settings.AutoFlushTimeout)); } catch (Exception) { if (pageManager != null) { pageManager.Close(); } else { fsPageManager?.Close(); } throw; } }
public void CorrectlyRecoverResurrectedPage() { long index; long resurrectIndex; using (var fileSystemPageManager = new FileSystemPageManager(4096)) using (var storage = new Storage(fileSystemPageManager)) { storage.OpenOrCreate(StoragePath); var page = fileSystemPageManager.CreatePage(); index = page.Index; } using (var fileSystemPageManager = new FileSystemPageManager(4096)) using (var storage = new Storage(fileSystemPageManager)) { storage.OpenOrCreate(StoragePath); var page = fileSystemPageManager.FetchPage(index); Assert.AreEqual(index, page.Index); Assert.AreNotEqual(0xff, page.Content[10]); } string fileName; using (var fileSystemPageManager = new FileSystemPageManager(4096)) using (var storage = new Storage(fileSystemPageManager)) using (var recoveryFile = new RecoveryFile(fileSystemPageManager, fileSystemPageManager.PageSize)) { storage.OpenOrCreate(StoragePath); var page = fileSystemPageManager.FetchPage(index); index = page.Index; page.Content[10] = 0xaf; fileSystemPageManager.RemovePage(index); var resurrectedPage = fileSystemPageManager.CreatePage(); resurrectIndex = resurrectedPage.Index; //check we're not going wrong way Assert.AreEqual(index, resurrectIndex); resurrectedPage.Content[10] = 0xff; Assert.AreNotEqual(0xff, page.Content[10]); fileSystemPageManager.Dispose(); recoveryFile.WriteUpdatePageRecord(page); recoveryFile.WriteDeletePageRecord(index); recoveryFile.WriteUpdatePageRecord(resurrectedPage); recoveryFile.WriteFinalMarker(); fileName = recoveryFile.FileName; } Assert.True(File.Exists(fileName)); Assert.GreaterOrEqual(new FileInfo(fileName).Length, 1); using (var manager = new FileSystemPageManager(4096)) using (var storage = new Storage(manager)) { storage.OpenOrCreate(StoragePath); var page = manager.FetchPage(index); Assert.AreEqual(resurrectIndex, page.Index); Assert.AreEqual(0xff, page.Content[10]); } }