private PagerState CreatePagerState()
        {
            var fileSize = GetFileSize();
            var startingBaseAddressPtr = Syscall.mmap(IntPtr.Zero, (ulong)fileSize,
                                                      MmapProts.PROT_READ | MmapProts.PROT_WRITE,
                                                      MmapFlags.MAP_SHARED, _fd, 0);

            if (startingBaseAddressPtr.ToInt64() == -1) //system didn't succeed in mapping the address where we wanted
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }

            var allocationInfo = new PagerState.AllocationInfo
            {
                BaseAddress = (byte *)startingBaseAddressPtr.ToPointer(),
                Size        = fileSize,
                MappedFile  = null
            };

            var newPager = new PagerState(this)
            {
                Files           = null, // unused
                MapBase         = allocationInfo.BaseAddress,
                AllocationInfos = new[] { allocationInfo }
            };

            newPager.AddRef(); // one for the pager
            return(newPager);
        }
示例#2
0
        private PagerState CreatePagerState()
        {
            var fileSize = GetFileSize();
            var mmflags  = _copyOnWriteMode ? MmapFlags.MAP_PRIVATE : MmapFlags.MAP_SHARED;
            var startingBaseAddressPtr = Syscall.mmap64(IntPtr.Zero, (UIntPtr)fileSize,
                                                        MmapProts.PROT_READ | MmapProts.PROT_WRITE,
                                                        mmflags, _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, fileSize, GetAllocatedInBytes);

            var allocationInfo = new PagerState.AllocationInfo
            {
                BaseAddress = (byte *)startingBaseAddressPtr.ToPointer(),
                Size        = fileSize,
                MappedFile  = null
            };

            return(new PagerState(this, Options.PrefetchSegmentSize, Options.PrefetchResetThreshold, allocationInfo));
        }
示例#3
0
        private PagerState CreatePagerState()
        {
            var startingBaseAddressPtr = Syscall.mmap(IntPtr.Zero, (UIntPtr)_totalAllocationSize,
                                                      MmapProts.PROT_READ | MmapProts.PROT_WRITE,
                                                      MmapFlags.MAP_SHARED, _fd, IntPtr.Zero);

            if (startingBaseAddressPtr.ToInt64() == -1) //system didn't succeed in mapping the address where we wanted
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err, "mmap on " + FileName);
            }
            NativeMemory.RegisterFileMapping(FileName, startingBaseAddressPtr, _totalAllocationSize);
            var allocationInfo = new PagerState.AllocationInfo
            {
                BaseAddress = (byte *)startingBaseAddressPtr.ToPointer(),
                Size        = _totalAllocationSize,
                MappedFile  = null
            };

            var newPager = new PagerState(this)
            {
                Files           = null, // unused
                MapBase         = allocationInfo.BaseAddress,
                AllocationInfos = new[] { allocationInfo }
            };

            return(newPager);
        }
示例#4
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);
        }
        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);
        }
示例#6
0
        private PagerState CreatePagerState()
        {
            _fileStreamLength = _fileStream.Length;
            var mmf = MemoryMappedFile.CreateFromFile(_fileStream, null, _fileStreamLength,
                                                      _memoryMappedFileAccess,
                                                      HandleInheritability.None, true);

            var allocation = new PagerState.AllocationInfo
            {
                MappedFile  = mmf,
                BaseAddress = null,
                Size        = 0
            };

            var newPager = new PagerState(this, Options.PrefetchSegmentSize, Options.PrefetchResetThreshold, allocation);

            _hFileMappingObject = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle();
            return(newPager);
        }
示例#7
0
        private PagerState CreatePagerState()
        {
            var mmf = MemoryMappedFile.CreateFromFile(_fileStream, null, _fileStream.Length,
                                                      _memoryMappedFileAccess,
                                                      null, HandleInheritability.None, true);

            var fileMappingHandle = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle();
            var mmFileAccessType  = _access == NativeFileAccess.GenericRead
                                ? MemoryMapNativeMethods.NativeFileMapAccessType.Read
                                : MemoryMapNativeMethods.NativeFileMapAccessType.Read | MemoryMapNativeMethods.NativeFileMapAccessType.Write;

            var startingBaseAddressPtr = MemoryMapNativeMethods.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 },
                Accessor        = null,          //not available since MapViewOfFileEx is used (instead of MapViewOfFile - which is used in managed wrapper)
                MapBase         = startingBaseAddressPtr,
                AllocationInfos = new[] { allocationInfo }
            };

            newPager.AddRef();             // one for the pager
            return(newPager);
        }
示例#8
0
        protected internal override PagerState AllocateMorePages(long newLength)
        {
            if (DisposeOnceRunner.Disposed)
            {
                ThrowAlreadyDisposedException();
            }

            var newLengthAfterAdjustment = NearestSizeToPageSize(newLength);

            if (newLengthAfterAdjustment <= _totalAllocationSize)
            {
                return(null);
            }

            var rc = rvn_allocate_more_space(newLengthAfterAdjustment, _handle, out var newAddress, out var errorCode);

            if (rc != FailCodes.Success)
            {
                PalHelper.ThrowLastError(rc, errorCode, $"can't allocate more pages (rc={rc}) for '{FileName.FullPath}'. Requested {newLength} (adjusted to {newLengthAfterAdjustment})");
            }

            // TODO : Get rid of allocation info
            var allocationInfo = new PagerState.AllocationInfo
            {
                BaseAddress = (byte *)newAddress,
                Size        = newLengthAfterAdjustment,
                MappedFile  = null
            };

            var newPagerState = new PagerState(this, Options.PrefetchSegmentSize, Options.PrefetchResetThreshold, allocationInfo);

            newPagerState.DebugVerify(newLengthAfterAdjustment);

            newPagerState.CopyPrefetchState(_pagerState);
            SetPagerState(newPagerState);

            _totalAllocationSize   = newLengthAfterAdjustment;
            NumberOfAllocatedPages = _totalAllocationSize / Constants.Storage.PageSize;

            return(newPagerState);
        }
        private PagerState CreateInitialPagerState(long size, byte *requestedBaseAddress)
        {
            var allocationSize = NearestSizeToAllocationGranularity(size);
            var mmf            = MemoryMappedFile.CreateNew(null, allocationSize, MemoryMappedFileAccess.ReadWrite);

            var fileMappingHandle = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle();

            var startingBaseAddressPtr = MemoryMapNativeMethods.MapViewOfFileEx(fileMappingHandle,
                                                                                MemoryMapNativeMethods.NativeFileMapAccessType.Read | MemoryMapNativeMethods.NativeFileMapAccessType.Write,
                                                                                0, 0,
                                                                                UIntPtr.Zero, //map all what was "reserved" in CreateFileMapping on previous row
                                                                                requestedBaseAddress);

            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 },
                Accessor        = null,          //not available since MapViewOfFileEx is used (instead of MapViewOfFile - which is used in managed wrapper)
                MapBase         = startingBaseAddressPtr,
                AllocationInfos = new[] { allocationInfo }
            };

            newPager.AddRef();

            return(newPager);
        }
		private PagerState CreateInitialPagerState(long size, byte* requestedBaseAddress)
		{
			var allocationSize = NearestSizeToAllocationGranularity(size);
			var mmf = MemoryMappedFile.CreateNew(null, allocationSize, MemoryMappedFileAccess.ReadWrite);

			var fileMappingHandle = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle();

			var startingBaseAddressPtr = MemoryMapNativeMethods.MapViewOfFileEx(fileMappingHandle,
				MemoryMapNativeMethods.NativeFileMapAccessType.Read | MemoryMapNativeMethods.NativeFileMapAccessType.Write,
				0, 0,
				UIntPtr.Zero, //map all what was "reserved" in CreateFileMapping on previous row
				requestedBaseAddress);

			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 },
				Accessor = null, //not available since MapViewOfFileEx is used (instead of MapViewOfFile - which is used in managed wrapper)
				MapBase = startingBaseAddressPtr,
				AllocationInfos = new[] { allocationInfo }
			};

			newPager.AddRef();

			return newPager;
		}
示例#11
0
        private PagerState CreatePagerState()
        {
            var mmf = MemoryMappedFile.CreateFromFile(_fileStream, null, _fileStream.Length,
                _memoryMappedFileAccess,
                null, HandleInheritability.None, true);

            var fileMappingHandle = mmf.SafeMemoryMappedFileHandle.DangerousGetHandle();
            var mmFileAccessType = _access == NativeFileAccess.GenericRead
                ? MemoryMapNativeMethods.NativeFileMapAccessType.Read
                : MemoryMapNativeMethods.NativeFileMapAccessType.Read | MemoryMapNativeMethods.NativeFileMapAccessType.Write;

            var startingBaseAddressPtr = MemoryMapNativeMethods.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 },
                Accessor = null, //not available since MapViewOfFileEx is used (instead of MapViewOfFile - which is used in managed wrapper)
                MapBase = startingBaseAddressPtr,
                AllocationInfos = new[] { allocationInfo }
            };

            newPager.AddRef(); // one for the pager
            return newPager;
        }
示例#12
0
        private bool TryHandleFailureToLockMemory(PagerState newState, PagerState.AllocationInfo info)
        {
            var currentProcess = Process.GetCurrentProcess();
            var sum            = Bits.NextPowerOf2(newState.AllocationInfos.Sum(x => x.Size) * 2);

            if (PlatformDetails.RunningOnPosix == false)
            {
                // From: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686234(v=vs.85).aspx
                // "The maximum number of pages that a process can lock is equal to the number of pages in its minimum working set minus a small overhead"
                // let's increase the max size of memory we can lock by increasing the MinWorkingSet. On Windows, that is available for all users
                var nextSize = Bits.NextPowerOf2(currentProcess.MinWorkingSet.ToInt64() + sum);
                if (nextSize > int.MaxValue && IntPtr.Size == sizeof(int))
                {
                    nextSize = int.MaxValue;
                }

                // Minimum working set size must be less than or equal to the maximum working set size.
                // Let's increase the max as well.
                if (nextSize > (long)currentProcess.MaxWorkingSet)
                {
                    try
                    {
                        currentProcess.MaxWorkingSet = new IntPtr(nextSize);
                    }
                    catch (Exception e)
                    {
                        throw new InsufficientMemoryException($"Need to increase the min working set size from {(long)currentProcess.MinWorkingSet:#,#;;0} to {nextSize:#,#;;0} but the max working set size was too small: {(long)currentProcess.MaxWorkingSet:#,#;;0}. " +
                                                              $"Failed to increase the max working set size so we can lock {info.Size:#,#;;0} for {FileName}. With encrypted " +
                                                              "databases we lock some memory in order to avoid leaking secrets to disk. Treating this as a catastrophic error " +
                                                              "and aborting the current operation.", e);
                    }
                }

                try
                {
                    currentProcess.MinWorkingSet = new IntPtr(nextSize);
                }
                catch (Exception e)
                {
                    throw new InsufficientMemoryException($"Failed to increase the min working set size so we can lock {info.Size:#,#;;0} for {FileName}. With encrypted " +
                                                          "databases we lock some memory in order to avoid leaking secrets to disk. Treating this as a catastrophic error " +
                                                          "and aborting the current operation.", e);
                }

                // now we can try again, after we raised the limit, we only do so once, though
                if (Sodium.sodium_mlock(info.BaseAddress, (UIntPtr)info.Size) == 0)
                {
                    return(false);
                }
            }

            var msg =
                $"Unable to lock memory for {FileName} with size {info.Size:#,#;;0}), with encrypted databases we lock some memory in order to avoid leaking secrets to disk. Treating this as a catastrophic error and aborting the current operation.{Environment.NewLine}";

            if (PlatformDetails.RunningOnPosix)
            {
                msg +=
                    $"The admin may configure higher limits using: 'sudo prlimit --pid {currentProcess.Id} --memlock={sum}' to increase the limit. (It's recommended to do that as part of the startup script){Environment.NewLine}";
            }
            else
            {
                msg +=
                    $"Already tried to raise the the process min working set to {currentProcess.MinWorkingSet.ToInt64():#,#;;0} but still got a failure.{Environment.NewLine}";
            }

            msg += "This behavior is controlled by the 'Security.DoNotConsiderMemoryLockFailureAsCatastrophicError' setting (expert only, modifications of this setting is not recommended).";

            throw new InsufficientMemoryException(msg);
        }
示例#13
0
        public RvnMemoryMapPager(StorageEnvironmentOptions options, VoronPathSetting file, long?initialFileSize = null, bool canPrefetchAhead = true, bool usePageProtection = false, bool deleteOnClose = false)
            : base(options, canPrefetchAhead, usePageProtection)
        {
            DeleteOnClose = deleteOnClose;
            FileName      = file;
            var copyOnWriteMode = options.CopyOnWriteMode && FileName.FullPath.EndsWith(Constants.DatabaseFilename);

            _logger = LoggingSource.Instance.GetLogger <StorageEnvironment>($"Pager-{file}");

            if (initialFileSize.HasValue == false || initialFileSize.Value == 0)
            {
                initialFileSize = Math.Max(SysInfo.PageSize * 16, 64 * 1024);
            }

            if (initialFileSize % SysInfo.PageSize != 0)
            {
                initialFileSize += SysInfo.PageSize - initialFileSize % SysInfo.PageSize;
            }

            Debug.Assert(file != null);

            var mmapOptions = copyOnWriteMode ? MmapOptions.CopyOnWrite : MmapOptions.None;

            if (DeleteOnClose)
            {
                mmapOptions |= MmapOptions.DeleteOnClose;
            }

            var rc = rvn_create_and_mmap64_file(
                file.FullPath,
                initialFileSize.Value,
                mmapOptions,
                out _handle,
                out var baseAddress,
                out _totalAllocationSize,
                out var errorCode);

            if (rc != FailCodes.Success)
            {
                try
                {
                    PalHelper.ThrowLastError(rc, errorCode, $"rvn_create_and_mmap64_file failed on {rc} for '{file.FullPath}'");
                }
                catch (DiskFullException dfEx)
                {
                    var diskSpaceResult = DiskSpaceChecker.GetDiskSpaceInfo(file.FullPath);
                    throw new DiskFullException(file.FullPath, initialFileSize.Value, diskSpaceResult?.TotalFreeSpace.GetValue(SizeUnit.Bytes), dfEx.Message);
                }
            }

            NumberOfAllocatedPages = _totalAllocationSize / Constants.Storage.PageSize;

            NativeMemory.RegisterFileMapping(FileName.FullPath, new IntPtr(baseAddress), _totalAllocationSize, GetAllocatedInBytes);

            var allocationInfo = new PagerState.AllocationInfo
            {
                BaseAddress = (byte *)baseAddress,
                Size        = _totalAllocationSize,
                MappedFile  = null
            };

            var pager = new PagerState(this, Options.PrefetchSegmentSize, Options.PrefetchResetThreshold, allocationInfo);

            SetPagerState(pager);
        }