Example #1
0
        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);
        }
Example #2
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();
            }
        }