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); } } }