public override void MaybePrefetchMemory(List <long> pagesToPrefetch) { if (PlatformDetails.CanPrefetch == false) { return; // not supported } if (pagesToPrefetch.Count == 0) { return; } var entries = new Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY[pagesToPrefetch.Count]; for (int i = 0; i < entries.Length; i++) { entries[i].NumberOfBytes = (IntPtr)(4 * Constants.Storage.PageSize); entries[i].VirtualAddress = AcquirePagePointer(null, pagesToPrefetch[i]); } fixed(Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY *entriesPtr = entries) { Win32MemoryMapNativeMethods.PrefetchVirtualMemory(Win32Helper.CurrentProcess, (UIntPtr)PagerState.AllocationInfos.Length, entriesPtr, 0); } }
public override void MaybePrefetchMemory(List <long> pagesToPrefetch) { if (CanPrefetch == false) { return; // not supported } if (pagesToPrefetch.Count == 0) { return; } var entries = new Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY[pagesToPrefetch.Count]; for (int i = 0; i < entries.Length; i++) { // We are prefetching 4 pages that with 4Kb pages is 32Kb but the idea is to really get a few consecutive pages to // exploit locality regardless of the page size. entries[i].NumberOfBytes = (IntPtr)(4 * PageSize); entries[i].VirtualAddress = AcquirePagePointer(null, pagesToPrefetch[i]); } fixed(Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY *entriesPtr = entries) { Win32MemoryMapNativeMethods.PrefetchVirtualMemory(_currentProcess, (UIntPtr)PagerState.AllocationInfos.Length, entriesPtr, 0); } }
private bool TryAllocateMoreContinuousPages(long allocationSize) { Debug.Assert(PagerState != null); Debug.Assert(PagerState.AllocationInfos != null); Debug.Assert(PagerState.Files != null && PagerState.Files.Any()); var allocationInfo = RemapViewOfFileAtAddress(allocationSize, (ulong)_totalAllocationSize, PagerState.MapBase + _totalAllocationSize); if (allocationInfo == null) { return(false); } PagerState.Files = PagerState.Files.Concat(allocationInfo.MappedFile); PagerState.AllocationInfos = PagerState.AllocationInfos.Concat(allocationInfo); if (PlatformDetails.CanPrefetch) { // We are asking to allocate pages. It is a good idea that they should be already in memory to only cause a single page fault (as they are continuous). Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY entry; entry.VirtualAddress = allocationInfo.BaseAddress; entry.NumberOfBytes = (IntPtr)allocationInfo.Size; Win32MemoryMapNativeMethods.PrefetchVirtualMemory(Win32Helper.CurrentProcess, (UIntPtr)1, &entry, 0); } return(true); }
public override void ReleaseAllocationInfo(byte *baseAddress, long size) { if (Win32MemoryMapNativeMethods.UnmapViewOfFile(baseAddress) == false) { throw new Win32Exception(); } }
public override void Sync() { if (Disposed) { ThrowAlreadyDisposedException(); } var currentState = GetPagerStateAndAddRefAtomically(); try { using (var metric = Options.IoMetrics.MeterIoRate(FileName, IoMetrics.MeterType.DataSync, 0)) { foreach (var allocationInfo in currentState.AllocationInfos) { metric.IncrementSize(allocationInfo.Size); if ( Win32MemoryMapNativeMethods.FlushViewOfFile(allocationInfo.BaseAddress, new IntPtr(allocationInfo.Size)) == false) { throw new Win32Exception(); } } if (Win32MemoryMapNativeMethods.FlushFileBuffers(_handle) == false) { throw new Win32Exception(); } } } finally { currentState.Release(); } }
private PagerState.AllocationInfo TryCreateNewFileMappingAtAddress(long allocationSize, byte *baseAddress) { var newMemoryMappedFile = MemoryMappedFile.CreateNew(null, allocationSize); var newFileMappingHandle = newMemoryMappedFile.SafeMemoryMappedFileHandle.DangerousGetHandle(); var newMappingBaseAddress = Win32MemoryMapNativeMethods.MapViewOfFileEx(newFileMappingHandle, Win32MemoryMapNativeMethods.NativeFileMapAccessType.Read | Win32MemoryMapNativeMethods.NativeFileMapAccessType.Write, 0, 0, UIntPtr.Zero, baseAddress); var hasMappingSucceeded = newMappingBaseAddress != null && newMappingBaseAddress != (byte *)0; if (!hasMappingSucceeded) { newMemoryMappedFile.Dispose(); return(null); } return(new PagerState.AllocationInfo { BaseAddress = newMappingBaseAddress, Size = allocationSize, MappedFile = newMemoryMappedFile }); }
private PagerState.AllocationInfo RemapViewOfFileAtAddress(long allocationSize, ulong offsetInFile, byte *baseAddress) { var offset = new SplitValue { Value = offsetInFile }; var mmf = MemoryMappedFile.CreateFromFile(_fileStream, null, _fileStream.Length, _memoryMappedFileAccess, null, HandleInheritability.None, true); var newMappingBaseAddress = Win32MemoryMapNativeMethods.MapViewOfFileEx(mmf.SafeMemoryMappedFileHandle.DangerousGetHandle(), Win32MemoryMapNativeMethods.NativeFileMapAccessType.Read | Win32MemoryMapNativeMethods.NativeFileMapAccessType.Write, offset.High, offset.Low, new UIntPtr((ulong)allocationSize), baseAddress); var hasMappingSucceeded = newMappingBaseAddress != null && newMappingBaseAddress != (byte *)0; if (!hasMappingSucceeded) { mmf.Dispose(); return(null); } return(new PagerState.AllocationInfo { BaseAddress = newMappingBaseAddress, Size = allocationSize, MappedFile = mmf }); }
private static void UndoMappings(IEnumerable <PagerState.AllocationInfo> newAllocationInfos) { foreach (var newAllocationInfo in newAllocationInfos) { Win32MemoryMapNativeMethods.UnmapViewOfFile(newAllocationInfo.BaseAddress); } }
public override void TryPrefetchingWholeFile() { if (CanPrefetch == false) { return; // not supported } var entries = stackalloc Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY[PagerState.AllocationInfos.Length]; for (int i = 0; i < PagerState.AllocationInfos.Length; i++) { entries[i].VirtualAddress = PagerState.AllocationInfos[i].BaseAddress; entries[i].NumberOfBytes = (IntPtr)PagerState.AllocationInfos[i].Size; } // We're deliberately ignoring the return value here and not throwing an exception if it returns false. // // This call is merely an optimization that can fail in low-memory conditions. // See https://msdn.microsoft.com/en-us/library/windows/desktop/hh780543(v=vs.85).aspx // // Because of that, and because this call regularly fails on Windows Azure Web Apps (http://issues.hibernatingrhinos.com/issue/RavenDB-4670), // we ignore the return value and don't throw if it fails. Win32MemoryMapNativeMethods.PrefetchVirtualMemory( Win32NativeMethods.GetCurrentProcess(), (UIntPtr)PagerState.AllocationInfos.Length, entries, 0); }
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 = string.Format( "Unable to allocate more pages - unsuccessfully tried to allocate continuous block of virtual memory with size = {0:##,###;;0} bytes", (_fileStream.Length)); throw new OutOfMemoryException(errorMessage, innerException); } NativeMemory.RegisterFileMapping(_fileInfo.FullName, new IntPtr(startingBaseAddressPtr), _fileStream.Length); // 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) { Files = new[] { mmf }, MapBase = startingBaseAddressPtr, AllocationInfos = new[] { allocationInfo } }; return(newPager); }
public override void ReleaseAllocationInfo(byte *baseAddress, long size) { if (Win32MemoryMapNativeMethods.UnmapViewOfFile(baseAddress) == false) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to UnMapView of file " + FileName); } NativeMemory.UnregisterFileMapping(_fileInfo.FullName, new IntPtr(baseAddress), size); }
public override void ReleaseAllocationInfo(byte *baseAddress, long size) { if (Win32MemoryMapNativeMethods.UnmapViewOfFile(baseAddress) == false) { throw new Win32Exception(); } NativeMemory.UnregisterFileMapping(_fileInfo.FullName, new IntPtr(baseAddress), size); }
public override void Sync() { ThrowObjectDisposedIfNeeded(); if (PagerState.AllocationInfos.Any(allocationInfo => Win32MemoryMapNativeMethods.FlushViewOfFile(allocationInfo.BaseAddress, new IntPtr(allocationInfo.Size)) == false)) { throw new Win32Exception(); } if (Win32MemoryMapNativeMethods.FlushFileBuffers(_handle) == false) { throw new Win32Exception(); } }
private PagerState CreatePagerState() { var mmf = MemoryMappedFile.CreateFromFile(_fileStream, null, _fileStream.Length, _memoryMappedFileAccess, HandleInheritability.None, true); var fileMappingHandle = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle(); var 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(); var errorMessage = string.Format( "Unable to allocate more pages - unsuccessfully tried to allocate continuous block of virtual memory with size = {0:##,###;;0} bytes", (_fileStream.Length)); throw new OutOfMemoryException(errorMessage, innerException); } var allocationInfo = new PagerState.AllocationInfo { BaseAddress = startingBaseAddressPtr, Size = _fileStream.Length, MappedFile = mmf }; var newPager = new PagerState(this) { Files = new[] { mmf }, MapBase = startingBaseAddressPtr, AllocationInfos = new[] { allocationInfo } }; newPager.AddRef(); // one for the pager return(newPager); }
public override void Sync(long totalUnsynced) { if (DisposeOnceRunner.Disposed) { ThrowAlreadyDisposedException(); } if ((_fileAttributes & Win32NativeFileAttributes.Temporary) == Win32NativeFileAttributes.Temporary || (_fileAttributes & Win32NativeFileAttributes.DeleteOnClose) == Win32NativeFileAttributes.DeleteOnClose) { return; // no need to do this } var currentState = GetPagerStateAndAddRefAtomically(); try { using (var metric = Options.IoMetrics.MeterIoRate(FileName.FullPath, IoMetrics.MeterType.DataSync, 0)) { foreach (var allocationInfo in currentState.AllocationInfos) { metric.IncrementFileSize(allocationInfo.Size); if ( Win32MemoryMapNativeMethods.FlushViewOfFile(allocationInfo.BaseAddress, new IntPtr(allocationInfo.Size)) == false) { var lasterr = Marshal.GetLastWin32Error(); throw new Win32Exception(lasterr); } } metric.IncrementSize(totalUnsynced); if (Win32MemoryMapNativeMethods.FlushFileBuffers(_handle) == false) { var lasterr = Marshal.GetLastWin32Error(); throw new Win32Exception(lasterr); } } } finally { currentState.Release(); } }
public override byte *AcquirePagePointer(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState = null) { // We need to decide what pager we are going to use right now or risk inconsistencies when performing prefetches from disk. var state = pagerState ?? _pagerState; if (PlatformDetails.CanPrefetch) { if (this._pagerState.ShouldPrefetchSegment(pageNumber, out void *virtualAddress, out long bytes)) { Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY entry; entry.NumberOfBytes = (IntPtr)bytes; entry.VirtualAddress = virtualAddress; Win32MemoryMapNativeMethods.PrefetchVirtualMemory(Win32Helper.CurrentProcess, (UIntPtr)1, &entry, 0); } } return(base.AcquirePagePointer(tx, pageNumber, state)); }
public override void TryPrefetchingWholeFile() { if (CanPrefetch == false) { return; // not supported } var entries = stackalloc Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY[PagerState.AllocationInfos.Length]; for (int i = 0; i < PagerState.AllocationInfos.Length; i++) { entries[i].VirtualAddress = PagerState.AllocationInfos[i].BaseAddress; entries[i].NumberOfBytes = (IntPtr)PagerState.AllocationInfos[i].Size; } if (Win32MemoryMapNativeMethods.PrefetchVirtualMemory(Win32NativeMethods.GetCurrentProcess(), (UIntPtr)PagerState.AllocationInfos.Length, entries, 0) == false) { throw new Win32Exception(); } }
public override void MaybePrefetchMemory(List <TreePage> sortedPages) { if (Sparrow.Platform.CanPrefetch == false) { return; // not supported } if (sortedPages.Count == 0) { return; } var ranges = SortedPagesToList(sortedPages); fixed(Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY *entries = ranges.ToArray()) { Win32MemoryMapNativeMethods.PrefetchVirtualMemory(Win32Helper.CurrentProcess, (UIntPtr)ranges.Count, entries, 0); } }
public override void Sync() { if (Disposed) { ThrowAlreadyDisposedException(); } foreach (var allocationInfo in PagerState.AllocationInfos) { if (Win32MemoryMapNativeMethods.FlushViewOfFile(allocationInfo.BaseAddress, new IntPtr(allocationInfo.Size)) == false) { throw new Win32Exception(); } } if (Win32MemoryMapNativeMethods.FlushFileBuffers(_handle) == false) { throw new Win32Exception(); } // TODO : Measure IO times (RavenDB-4659) - Flushed & sync {sizeToWrite/1024:#,#} kb in {sp.ElapsedMilliseconds:#,#} ms }
public override void TryPrefetchingWholeFile() { if (PlatformDetails.CanPrefetch == false) { return; // not supported } var pagerState = PagerState; var entries = stackalloc Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY[pagerState.AllocationInfos.Length]; for (var i = 0; i < pagerState.AllocationInfos.Length; i++) { entries[i].VirtualAddress = pagerState.AllocationInfos[i].BaseAddress; entries[i].NumberOfBytes = (IntPtr)pagerState.AllocationInfos[i].Size; } if (Win32MemoryMapNativeMethods.PrefetchVirtualMemory(Win32Helper.CurrentProcess, (UIntPtr)pagerState.AllocationInfos.Length, entries, 0) == false) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to Prefetch Vitrual Memory of file " + FileName); } }
private PagerState CreatePagerState() { var mmf = MemoryMappedFile.CreateFromFile(_fileStream, null, _fileStream.Length, _memoryMappedFileAccess, null, HandleInheritability.None, true); var fileMappingHandle = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle(); var 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 { throw new Win32Exception(); } var allocationInfo = new PagerState.AllocationInfo { BaseAddress = startingBaseAddressPtr, Size = _fileStream.Length, MappedFile = mmf }; var newPager = new PagerState(this) { Files = new[] { mmf }, MapBase = startingBaseAddressPtr, AllocationInfos = new[] { allocationInfo } }; newPager.AddRef(); // one for the pager return(newPager); }
private PagerState CreateInitialPagerState(long size) { var allocationSize = NearestSizeToAllocationGranularity(size); var mmf = MemoryMappedFile.CreateNew(null, allocationSize, MemoryMappedFileAccess.ReadWrite); var fileMappingHandle = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle(); var startingBaseAddressPtr = Win32MemoryMapNativeMethods.MapViewOfFileEx(fileMappingHandle, Win32MemoryMapNativeMethods.NativeFileMapAccessType.Read | Win32MemoryMapNativeMethods.NativeFileMapAccessType.Write, 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 { throw new Win32Exception(); } var allocationInfo = new PagerState.AllocationInfo { BaseAddress = startingBaseAddressPtr, Size = allocationSize, MappedFile = mmf }; var newPager = new PagerState(this) { Files = new[] { mmf }, MapBase = startingBaseAddressPtr, AllocationInfos = new[] { allocationInfo } }; newPager.AddRef(); return(newPager); }
protected internal override unsafe void PrefetchRanges(Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY *list, int count) { Win32MemoryMapNativeMethods.PrefetchVirtualMemory(Win32Helper.CurrentProcess, (UIntPtr)count, list, 0); }
private PagerState AllocateMorePagesAndRemapContinuously(long allocationSize) { var retryCount = 0; while (retryCount++ < MaxAllocationRetries) { byte *newBaseAddress; if (TryFindContinuousMemory((ulong)(_totalAllocationSize + allocationSize), out newBaseAddress) == false) { var message = string.Format( "Unable to allocate more pages - unsuccessfully tried to allocate continuous block of size = {0} bytes\r\n" + "It is likely that we are suffering from virtual memory exhaustion or memory fragmentation.\r\n" + "64 bits process: {1}\r\n" + "If you are running in 32 bits, this is expected, and you need to run in 64 bits to resume normal operations.\r\n" + "If you are running in 64 bits, this is likely an error and should be reported." , (_totalAllocationSize + allocationSize), Environment.Is64BitProcess); throw new OutOfMemoryException(message); } bool failedToAllocate = false; long offset = 0; var allocationInfoAfterReallocation = new List <PagerState.AllocationInfo>(); foreach (var allocationInfo in PagerState.AllocationInfos) { var newAlloctedBaseAddress = Win32MemoryMapNativeMethods.MapViewOfFileEx(allocationInfo.MappedFile.SafeMemoryMappedFileHandle.DangerousGetHandle(), Win32MemoryMapNativeMethods.NativeFileMapAccessType.Read | Win32MemoryMapNativeMethods.NativeFileMapAccessType.Write, 0, 0, UIntPtr.Zero, newBaseAddress + offset); if (newAlloctedBaseAddress == null || newAlloctedBaseAddress == (byte *)0) { Debug.WriteLine("Failed to remap file continuously. Unmapping already mapped files and re-trying"); UndoMappings(allocationInfoAfterReallocation); failedToAllocate = true; break; } offset += allocationInfo.Size; allocationInfoAfterReallocation.Add(new PagerState.AllocationInfo { BaseAddress = newAlloctedBaseAddress, MappedFile = allocationInfo.MappedFile, Size = allocationInfo.Size }); } if (failedToAllocate) { continue; } var newAllocationInfo = TryCreateNewFileMappingAtAddress(allocationSize, newBaseAddress + _totalAllocationSize); if (newAllocationInfo == null) { UndoMappings(allocationInfoAfterReallocation); continue; } var newPagerState = new PagerState(this) { Files = PagerState.Files.Concat(newAllocationInfo.MappedFile), AllocationInfos = allocationInfoAfterReallocation.Concat(newAllocationInfo), MapBase = newBaseAddress }; return(newPagerState); } throw new InvalidOperationException( string.Format( "Something bad has happened, after {0} tries, could not find any spot in virtual memory to remap continuous virtual memory for {1:##,###;;0} bytes", MaxAllocationRetries, allocationSize)); }
public override void MaybePrefetchMemory(List <Page> sortedPages) { if (sortedPages.Count == 0) { return; } if (IsWindows8OrNewer() == false) { return; // not supported } var list = new List <Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY>(); long lastPage = -1; const int numberOfPagesInBatch = 8; int sizeInPages = numberOfPagesInBatch; // OS uses 32K when you touch a page, let us reuse this foreach (var page in sortedPages) { if (lastPage == -1) { lastPage = page.PageNumber; } var numberOfPagesInLastPage = page.IsOverflow == false ? 1 : GetNumberOfOverflowPages(page.OverflowSize); var endPage = page.PageNumber + numberOfPagesInLastPage - 1; if (endPage <= lastPage + sizeInPages) { continue; // already within the allocation granularity we have } if (page.PageNumber <= lastPage + sizeInPages + numberOfPagesInBatch) { while (endPage > lastPage + sizeInPages) { sizeInPages += numberOfPagesInBatch; } continue; } list.Add(new Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY { NumberOfBytes = (IntPtr)(sizeInPages * AbstractPager.PageSize), VirtualAddress = AcquirePagePointer(lastPage) }); lastPage = page.PageNumber; sizeInPages = numberOfPagesInBatch; while (endPage > lastPage + sizeInPages) { sizeInPages += numberOfPagesInBatch; } } list.Add(new Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY { NumberOfBytes = (IntPtr)(sizeInPages * PageSize), VirtualAddress = AcquirePagePointer(lastPage) }); fixed(Win32MemoryMapNativeMethods.WIN32_MEMORY_RANGE_ENTRY *entries = list.ToArray()) { Win32MemoryMapNativeMethods.PrefetchVirtualMemory(Win32NativeMethods.GetCurrentProcess(), (UIntPtr)list.Count, entries, 0); } }