예제 #1
0
        private void CleanupMemory(TransactionState txState)
        {
            _globalMemory.EnterWriteLock();
            try
            {
                foreach (var addr in txState.AddressesToUnload)
                {
                    if (addr.Usages != 0)
                    {
                        continue;
                    }

                    if (!_globalMapping.TryGetValue(addr.StartPage, out var set))
                    {
                        continue;
                    }

                    if (!set.TryRemove(addr))
                    {
                        continue;
                    }

                    if (LockMemory && addr.Size > 0)
                    {
                        UnlockMemory32Bits((byte *)addr.Address, addr.Size);
                    }

                    Interlocked.Add(ref _totalMapped, -addr.Size);
                    UnmapViewOfFile((byte *)addr.Address);
                    NativeMemory.UnregisterFileMapping(addr.File, addr.Address, addr.Size);

                    if (set.Count == 0)
                    {
                        _globalMapping.TryRemove(addr.StartPage, out set);
                    }
                }
            }
            finally
            {
                _globalMemory.ExitWriteLock();
            }
        }
예제 #2
0
 private void LockMemory32Bits(byte *address, long sizeToLock, TransactionState state)
 {
     try
     {
         if (Sodium.sodium_mlock(address, (UIntPtr)sizeToLock) != 0)
         {
             lock (WorkingSetIncreaseLocker)
             {
                 if (Sodium.sodium_mlock(address, (UIntPtr)sizeToLock) != 0 && DoNotConsiderMemoryLockFailureAsCatastrophicError == false)
                 {
                     TryHandleFailureToLockMemory(address, sizeToLock);
                 }
             }
         }
     }
     catch (Exception e)
     {
         throw new InvalidOperationException("Failed to lock memory in 32-bit mode", e);
     }
 }
예제 #3
0
        private TransactionState GetTransactionState(IPagerLevelTransactionState tx)
        {
            TransactionState transactionState;

            if (tx.SparsePagerTransactionState == null)
            {
                transactionState = new TransactionState();
                tx.SparsePagerTransactionState = new Dictionary <AbstractPager, TransactionState>
                {
                    { this, transactionState }
                };
                tx.OnDispose += TxOnOnDispose;
                return(transactionState);
            }

            if (tx.SparsePagerTransactionState.TryGetValue(this, out transactionState) == false)
            {
                transactionState = new TransactionState();
                tx.SparsePagerTransactionState[this] = transactionState;
            }
            return(transactionState);
        }
예제 #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();
            }
        }
예제 #5
0
        private byte *ReturnPagePointerOrGrowAllocation(LoadedPage page, long distanceFromStart, TransactionState state, bool canUnmap)
        {
            var pageHeader = (PageHeader *)(page.Pointer + (distanceFromStart * PageSize));

            if ((pageHeader->Flags & PageFlags.Overflow) != PageFlags.Overflow)
            {
                // single page, already loaded, can return immediately.
                return((byte *)pageHeader);
            }
            // overflow, so need to make sure it is in the range we mapped.
            var numberOfOverflowPages = this.GetNumberOfOverflowPages(pageHeader->OverflowSize);

            if (numberOfOverflowPages + distanceFromStart < page.NumberOfPages)
            {
                // the entire range is already mapped, can return immediately
                return((byte *)pageHeader);
            }

            if (canUnmap)
            {
                Debug.Assert(state.AddressesToUnload[state.AddressesToUnload.Count - 1] == new IntPtr(page.Pointer));
                state.AddressesToUnload.RemoveAt(state.AddressesToUnload.Count - 1);

                UnmapViewOfFile(page.Pointer);
            }

            var ammountToMapInBytes = NearestSizeToAllocationGranularity((distanceFromStart + numberOfOverflowPages) * PageSize);

            page = MapPages(state, page.StartPage, ammountToMapInBytes);
            return(page.Pointer + distanceFromStart * PageSize);
        }