private byte[] FetchBlock(long index) { if (_blockCache.ContainsKey(index)) { return(_blockCache[index]); } var result = new byte[_blockLength]; var position = _blockLength + index * _blockLength; if (position == _fileStream.Length) { return(result); } _fileStream.Seek(position, SeekOrigin.Begin); _fileStream.BlockingRead(result); _blockCache[index] = result; return(result); }
private void Vacuum() { // here we get all free page indexes and allocations var freePageIndexes = _pagemap.FreePageIndexes; var freePageData = freePageIndexes.Select(freePageIndex => new Tuple <long, long>(_pagemap.GetPageAllocation(freePageIndex), freePageIndex)).ToList(); // sort allocations freePageData.Sort((p1, p2) => p1.Item1.CompareTo(p2.Item1)); var reallocatedPageBytes = new byte[_pageSize]; // reallocate pages at the end of storage file while (freePageData.Any()) { long lastPageIndex = _pagemap.ReadLastPageIndex(); // compute last page allocation long lastPageAllocation = _storageStream.Length - _pageSize; if (freePageData.All(t => t.Item1 != lastPageAllocation)) { // last page is occupied // read its content _storageStream.Seek(-_pageSize, SeekOrigin.End); _storageStream.BlockingRead(reallocatedPageBytes); var firstFreePage = freePageData[0]; var newPageAllocation = firstFreePage.Item1; freePageData.RemoveAt(0); // write a page content to new place _storageStream.Seek(newPageAllocation, SeekOrigin.Begin); _storageStream.Write(reallocatedPageBytes, 0, _pageSize); // write an allocation marker of reallocated page _pagemap.WritePageAllocation(lastPageIndex, newPageAllocation); // write an allocation marker of first free page _pagemap.WritePageAllocation(firstFreePage.Item2, -1); // write a disk-to-virtual entry of reallocated page _pagemap.WritePageIndex(lastPageIndex, newPageAllocation); } else { // last page is empty _pagemap.WritePageAllocation(lastPageIndex, -1); freePageData.RemoveAll(t => t.Item1 == lastPageAllocation); } // truncate pagemap _pagemap.TruncateLastPageIndex(); // truncate storage file _storageStream.SetLength(_storageStream.Length - _pageSize); } // clear free page indexes _pagemap.ClearFreePageMarkers(); Flush(_storageStream); _pagemap.Flush(); }