private LoadedPage AddMappingToTransaction(TransactionState state, long startPage, long size, MappedAddresses mappedAddresses) { state.TotalLoadedSize += size; state.AddressesToUnload.Add(mappedAddresses); var loadedPage = new LoadedPage { Pointer = (byte *)mappedAddresses.Address, NumberOfPages = (int)(size / Constants.Storage.PageSize), StartPage = startPage }; state.LoadedPages[startPage] = loadedPage; return(loadedPage); }
private LoadedPage MapPages(TransactionState state, long startPage, long size) { _globalMemory.EnterReadLock(); try { var addresses = _globalMapping.GetOrAdd(startPage, _ => new ConcurrentSet <MappedAddresses>()); foreach (var addr in addresses) { if (addr.Size < size) { continue; } Interlocked.Increment(ref addr.Usages); return(AddMappingToTransaction(state, startPage, size, addr)); } var offset = new WindowsMemoryMapPager.SplitValue { Value = (ulong)startPage * Constants.Storage.PageSize }; if ((long)offset.Value + size > _fileStreamLength) { // this can happen when the file size is not a natural multiple of the allocation granularity // frex: granularity of 64KB, and the file size is 80KB. In this case, a request to map the last // 64 kb will run into a problem, there aren't any. In this case only, we'll map the bytes that are // actually there in the file, and if the code will attempt to access beyond the end of file, we'll get // an access denied error, but this is already handled in higher level of the code, since we aren't just // handing out access to the full range we are mapping immediately. if ((long)offset.Value < _fileStreamLength) { size = _fileStreamLength - (long)offset.Value; } else { ThrowInvalidMappingRequested(startPage, size); } } var result = MapViewOfFileEx(_hFileMappingObject, _mmFileAccessType, offset.High, offset.Low, (UIntPtr)size, null); if (result == null) { var lastWin32Error = Marshal.GetLastWin32Error(); const int ERROR_NOT_ENOUGH_MEMORY = 8; if (lastWin32Error == ERROR_NOT_ENOUGH_MEMORY) { throw new OutOfMemoryException($"Unable to map {size / Constants.Size.Kilobyte:#,#0} kb starting at {startPage} on {FileName}", new Win32Exception(lastWin32Error)); } else { const int INVALID_HANDLE = 6; if (lastWin32Error == INVALID_HANDLE && Disposed) { ThrowAlreadyDisposedException(); } throw new Win32Exception( $"Unable to map {size / Constants.Size.Kilobyte:#,#0} kb starting at {startPage} on {FileName} (lastWin32Error={lastWin32Error})", new Win32Exception(lastWin32Error)); } } if (LockMemory && size > 0) { LockMemory32Bits(result, size, state); } NativeMemory.RegisterFileMapping(_fileInfo.FullName, new IntPtr(result), size, GetAllocatedInBytes); Interlocked.Add(ref _totalMapped, size); var mappedAddresses = new MappedAddresses { Address = (IntPtr)result, File = _fileInfo.FullName, Size = size, StartPage = startPage, Usages = 1 }; addresses.Add(mappedAddresses); return(AddMappingToTransaction(state, startPage, size, mappedAddresses)); } finally { _globalMemory.ExitReadLock(); } }