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 = startPage * Constants.Storage.PageSize; if (offset + size > _totalAllocationSize) { ThrowInvalidMappingRequested(startPage, size); } var mmflags = _copyOnWriteMode ? MmapFlags.MAP_PRIVATE : MmapFlags.MAP_SHARED; var startingBaseAddressPtr = Syscall.mmap64(IntPtr.Zero, (UIntPtr)size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, mmflags, _fd, offset); if (startingBaseAddressPtr.ToInt64() == -1) //system didn't succeed in mapping the address where we wanted { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, $"Unable to map {size / Constants.Size.Kilobyte:#,#0} kb starting at {startPage} on {FileName}"); } NativeMemory.RegisterFileMapping(FileName.FullPath, startingBaseAddressPtr, size, GetAllocatedInBytes); Interlocked.Add(ref _totalMapped, size); var mappedAddresses = new MappedAddresses { Address = startingBaseAddressPtr, File = FileName.FullPath, Size = size, StartPage = startPage, Usages = 1 }; addresses.Add(mappedAddresses); return(AddMappingToTransaction(state, startPage, size, mappedAddresses)); } finally { _globalMemory.ExitReadLock(); } }
private PagerState CreatePagerState() { var mmf = MemoryMappedFile.CreateFromFile(_fileStream, null, _fileStream.Length, _memoryMappedFileAccess, HandleInheritability.None, true); var fileMappingHandle = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle(); Win32MemoryMapNativeMethods.NativeFileMapAccessType mmFileAccessType; if (_copyOnWriteMode) { mmFileAccessType = Win32MemoryMapNativeMethods.NativeFileMapAccessType.Copy; } else { mmFileAccessType = _access == Win32NativeFileAccess.GenericRead ? Win32MemoryMapNativeMethods.NativeFileMapAccessType.Read : Win32MemoryMapNativeMethods.NativeFileMapAccessType.Read | Win32MemoryMapNativeMethods.NativeFileMapAccessType.Write; } var startingBaseAddressPtr = Win32MemoryMapNativeMethods.MapViewOfFileEx(fileMappingHandle, mmFileAccessType, 0, 0, UIntPtr.Zero, //map all what was "reserved" in CreateFileMapping on previous row null); if (startingBaseAddressPtr == (byte *)0) //system didn't succeed in mapping the address where we wanted { var innerException = new Win32Exception(Marshal.GetLastWin32Error(), "Failed to MapView of file " + FileName); var errorMessage = $"Unable to allocate more pages - unsuccessfully tried to allocate continuous block of virtual memory with size = {new Size(_fileStream.Length, SizeUnit.Bytes)}"; throw new OutOfMemoryException(errorMessage, innerException); } NativeMemory.RegisterFileMapping(_fileInfo.FullName, new IntPtr(startingBaseAddressPtr), _fileStream.Length, GetAllocatedInBytes); // If we are working on memory validation mode, then protect the pages by default. ProtectPageRange(startingBaseAddressPtr, (ulong)_fileStream.Length); var allocationInfo = new PagerState.AllocationInfo { BaseAddress = startingBaseAddressPtr, Size = _fileStream.Length, MappedFile = mmf }; var newPager = new PagerState(this, Options.PrefetchSegmentSize, Options.PrefetchResetThreshold, allocationInfo); return(newPager); }
private PagerState CreatePagerState() { var startingBaseAddressPtr = Syscall.mmap64(IntPtr.Zero, (UIntPtr)_totalAllocationSize, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_SHARED, _fd, 0L); if (startingBaseAddressPtr.ToInt64() == -1) //system didn't succeed in mapping the address where we wanted { var err = Marshal.GetLastWin32Error(); Syscall.ThrowLastError(err, "mmap on " + FileName); } NativeMemory.RegisterFileMapping(FileName.FullPath, startingBaseAddressPtr, _totalAllocationSize, GetAllocatedInBytes); var allocationInfo = new PagerState.AllocationInfo { BaseAddress = (byte *)startingBaseAddressPtr.ToPointer(), Size = _totalAllocationSize, MappedFile = null }; return(new PagerState(this, Options.PrefetchSegmentSize, Options.PrefetchResetThreshold, allocationInfo)); }
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(); } }