예제 #1
0
        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();
            }
        }
예제 #2
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 = $"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);
        }
예제 #3
0
        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));
        }
예제 #4
0
        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();
            }
        }