public static int GetIndexOfFirstMatchingFsmValue(IPage page, FsmValue targetFsm) { FreeSpaceMapPageHeader header = GetFsmPageHeader(page); var content = page.Content; var length = content.Length; var fsmByte = (byte)targetFsm; const int full = ((byte)FsmValue.Full | ((byte)FsmValue.Full << 4)); for (int i = header.Length; i < length; i++) { if (content[i] == full) { continue; } var first = (byte)(0x0F & content[i]); var second = (byte)((0xF0 & content[i]) >> 4); if (first == fsmByte) { return((i - header.Length) * 2); } if (second == fsmByte) { return((i - header.Length) * 2 + 1); } } return(-1); }
public static void SetAllFsmValues(IPage page, FsmValue value) { FreeSpaceMapPageHeader header = GetFsmPageHeader(page); byte byteValue = (byte)((byte)value | ((byte)value << 4)); for (int i = header.Length; i < page.Length; i++) { page.Content[i] = byteValue; } }
public static void SetFsmValue(IPage page, int index, FsmValue newValue) { FreeSpaceMapPageHeader header = GetFsmPageHeader(page); if (index < 0 || index > (page.Length - header.Length) * 2) { throw new ArgumentOutOfRangeException(nameof(index)); } int targetIndex = index / 2 + header.Length; byte b = page.Content[targetIndex]; if (index % 2 == 0) { b = (byte)((b & 0xF0) | (byte)newValue); } else { b = (byte)((b & 0x0F) | ((byte)newValue << 4)); } page.Content[targetIndex] = b; }
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)); } }
public void Set(long pageIndex, FsmValue value) { if (!_isInitialized) { Init(); } IPage page = GetFsmPageByTargetPageIndex(pageIndex); if (page == null) { // fsm-page is missing for requested page index long previousPageIndex = _lastFsmPage.Index; var missingPageCount = (int)((pageIndex - (_fsmPageCount - _fsmPageIndexes.Count) * _entryPerPage) / _entryPerPage + 1); var pages = new List <IPage>(missingPageCount); // allocate new pages for (int i = 0; i < missingPageCount; i++) { pages.Add(_pageManager.CreatePage()); } var baseIndex = PageFormatter.GetBasePageIndex(_lastFsmPage); // initialize them for (int i = 0; i < missingPageCount; i++) { baseIndex += _entryPerPage; InitFsmPage(pages[i], previousPageIndex, i == missingPageCount - 1 ? -1 : pages[i + 1].Index, baseIndex); previousPageIndex = pages[i].Index; } // and update pages.ForEach(_pageManager.UpdatePage); // save reference to added pages var lastPageHeader = (FreeSpaceMapPageHeader)PageFormatter.GetPageHeader(_lastFsmPage); lastPageHeader.NextPageIndex = pages[0].Index; lastPageHeader.WriteToPage(_lastFsmPage); _pageManager.UpdatePage(_lastFsmPage); _lastFsmPage = null; _fsmPageCount = -1; Set(pageIndex, value); } else { PageFormatter.SetFsmValue(page, (int)pageIndex % _entryPerPage, value); _pageManager.UpdatePage(page); var fsmValuesToUpdate = _luckyFsmPages.Where(item => item.Value.Page.Index == page.Index).Select(item => item.Key).ToList(); foreach (var fsmValue in fsmValuesToUpdate) { _luckyFsmPages[fsmValue].Page = page; } if (!_luckyFsmPages.ContainsKey(value)) { _luckyFsmPages[value] = new LuckyPage { Page = page, LastGoodIndex = pageIndex } } ; else { if (_scanned.Contains(value)) { _scanned.Remove(value); } } } }
public long GetFreePageIndex(FsmValue value) { if (!_isInitialized) { Init(); } // try to find in lucky pages if (_luckyFsmPages.ContainsKey(value)) { IPage page = _luckyFsmPages[value].Page; var requestedFsmIndex = (int)(_luckyFsmPages[value].LastGoodIndex % _entryPerPage); int matchingFsmIndex; if (PageFormatter.GetFsmValue(page, requestedFsmIndex) == value) { matchingFsmIndex = requestedFsmIndex; } else { matchingFsmIndex = PageFormatter.GetIndexOfFirstMatchingFsmValue(page, value); _luckyFsmPages[value].LastGoodIndex = matchingFsmIndex; } if (matchingFsmIndex == -1) { // page becomes unlucky _luckyFsmPages.Remove(value); } else { return(PageFormatter.GetBasePageIndex(page) + matchingFsmIndex); } } var currentPageIndex = _firstFsmPageIndex; long index = 0; if (_scanned.Contains(value)) { return(-1); } while (true) { // sequential scan all fsm pages for specified fsm-value var currentPage = _pageManager.FetchPage(currentPageIndex); int matchingFsmIndex = PageFormatter.GetIndexOfFirstMatchingFsmValue(currentPage, value); if (matchingFsmIndex == -1) { index += _entryPerPage; var header = (FreeSpaceMapPageHeader)PageFormatter.GetPageHeader(currentPage); if (header.NextPageIndex == -1) { _scanned.Add(value); return(-1); } currentPageIndex = header.NextPageIndex; } else { // make found page lucky _luckyFsmPages[value] = new LuckyPage { Page = currentPage, LastGoodIndex = matchingFsmIndex + index }; return(index + matchingFsmIndex); } } }