Ejemplo n.º 1
0
 protected AbstractPager()
 {
     _increaseSize = MinIncreaseSize;
     MaxNodeSize = 1024;
     Debug.Assert((PageSize - Constants.PageHeaderSize) / Constants.MinKeysInPage >= 1024);
     PageMinSpace = (int)(PageMaxSpace * 0.33);
     PagerState = new PagerState(this);
   
     PagerState.AddRef();
 }
Ejemplo n.º 2
0
        public unsafe override byte* AcquirePagePointer(long pageNumber, PagerState pagerState = null)
        {
            long page = 0;
            foreach (var buffer in _buffers)
            {
                if (page + buffer.SizeInPages > pageNumber)
                    return buffer.Pointer + ((pageNumber - page)*PageSize);

                page += buffer.SizeInPages;
            }
            throw new InvalidOperationException("Could not find a matching page number: " + pageNumber);
        }
Ejemplo n.º 3
0
        public Page Read(long pageNumber, PagerState pagerState = null)
        {
			ThrowObjectDisposedIfNeeded();
			
            if (pageNumber + 1 > NumberOfAllocatedPages)
            {
                throw new InvalidOperationException("Cannot get page number " + pageNumber +
                                                    " because number of allocated pages is " + NumberOfAllocatedPages);
            }

            return new Page(AcquirePagePointer(pageNumber, pagerState), _source, PageSize);
        }
Ejemplo n.º 4
0
        protected AbstractPager()
        {
            _increaseSize = MinIncreaseSize;

            // MaxNodeSize is usually persisted as an unsigned short. Therefore, we must ensure it is not possible to have an overflow.
            Debug.Assert(NodeMaxSize < ushort.MaxValue);
            Debug.Assert((PageSize - Constants.PageHeaderSize) / Constants.MinKeysInPage >= 1024);
            
            PageMinSpace = (int)(PageMaxSpace * 0.33);
            PagerState = new PagerState(this);
          
            PagerState.AddRef();
        }
Ejemplo n.º 5
0
		public PureMemoryPager()
		{
			var ptr = Marshal.AllocHGlobal(MinIncreaseSize);
			var buffer = new Buffer
			{
				Handle = ptr,
				Base = (byte*)ptr.ToPointer(),
				Size = MinIncreaseSize
			};
			_buffers.Append(buffer);
			NumberOfAllocatedPages = 0;
			PagerState.Release();
			PagerState = new PagerState(this);
			PagerState.AddRef();
		}
Ejemplo n.º 6
0
		public PureMemoryPager(byte[] data)
		{
			var ptr = Marshal.AllocHGlobal(data.Length);
			var buffer = new Buffer
			{
				Handle = ptr,
				Base = (byte*)ptr.ToPointer(),
				Size = data.Length
			};
			_buffers = _buffers.Append(buffer);
			NumberOfAllocatedPages = data.Length / PageSize;
			PagerState.Release();
			PagerState = new PagerState(this);
			PagerState.AddRef();
			fixed (byte* origin = data)
			{
				NativeMethods.memcpy(buffer.Base, origin, data.Length);
			}
		}
Ejemplo n.º 7
0
 public abstract byte *AcquirePagePointer(long pageNumber, PagerState pagerState = null);
        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));
        }
Ejemplo n.º 9
0
 public override byte *AcquirePagePointerForNewPage(IPagerLevelTransactionState tx, long pageNumber, int numberOfPages, PagerState pagerState = null)
 {
     return(AcquirePagePointer(tx, pageNumber, pagerState));
 }
Ejemplo n.º 10
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);
        }
		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 = MemoryMapNativeMethods.MapViewOfFileEx(allocationInfo.MappedFile.SafeMemoryMappedFileHandle.DangerousGetHandle(),
						MemoryMapNativeMethods.NativeFileMapAccessType.Read | MemoryMapNativeMethods.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));
		}
Ejemplo n.º 12
0
		public Page ReadPage(long p, PagerState pagerState = null)
		{
			return _scratchPager.Read(p, pagerState);
		}
Ejemplo n.º 13
0
 public Page ReadPage(int scratchNumber, long p, PagerState pagerState = null)
 {
     return(_scratchBuffers[scratchNumber].ReadPage(p, pagerState));
 }
Ejemplo n.º 14
0
        public static byte *AcquirePagePointerWithOverflowHandling <T>(this AbstractPager pager, T tx, long pageNumber, PagerState pagerState) where T : IPagerLevelTransactionState
        {
            // Case 1: Page is not overflow ==> no problem, returning a pointer to existing mapping
            var pageHeader = (PageHeader *)pager.AcquirePagePointer(tx, pageNumber, pagerState);

            if ((pageHeader->Flags & PageFlags.Overflow) != PageFlags.Overflow)
            {
                return((byte *)pageHeader);
            }

            // Case 2: Page is overflow and already mapped large enough ==> no problem, returning a pointer to existing mapping
            if (pager.EnsureMapped(tx, pageNumber, GetNumberOfOverflowPages(pageHeader->OverflowSize)) == false)
            {
                return((byte *)pageHeader);
            }

            // Case 3: Page is overflow and was ensuredMapped above, view was re-mapped so we need to acquire a pointer to the new mapping.
            return(pager.AcquirePagePointer(tx, pageNumber, pagerState));
        }
Ejemplo n.º 15
0
        public override unsafe byte *AcquirePagePointer(Transaction tx, long pageNumber, PagerState pagerState = null)
        {
            long page = 0;

            foreach (var buffer in _buffers)
            {
                if (page + buffer.SizeInPages > pageNumber)
                {
                    return(buffer.Pointer + ((pageNumber - page) * PageSize));
                }

                page += buffer.SizeInPages;
            }
            throw new InvalidOperationException("Could not find a matching page number: " + pageNumber);
        }
Ejemplo n.º 16
0
 public void EnsurePagerStateReference(ref PagerState state)
 {
 }
Ejemplo n.º 17
0
        public override unsafe 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))
                {
                    Syscall.madvise(new IntPtr(virtualAddress), (UIntPtr)bytes, MAdvFlags.MADV_WILLNEED);
                }
            }

            return(base.AcquirePagePointer(tx, pageNumber, state));
        }
Ejemplo n.º 18
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);
        }
Ejemplo n.º 19
0
        public override byte *AcquirePagePointer(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState = null)
        {
            var state = pagerState ?? _pagerState;

            if (CanPrefetch.Value && state != null)
            {
                if (state.ShouldPrefetchSegment(pageNumber, out var virtualAddress, out var bytes))
                {
                    rvn_prefetch_virtual_memory(virtualAddress, bytes, out _); // ignore if unsuccessful
                }
            }

            return(base.AcquirePagePointer(tx, pageNumber, state));
        }
Ejemplo n.º 20
0
        public override byte *AcquirePagePointerForNewPage(IPagerLevelTransactionState tx, long pageNumber, int numberOfPages, PagerState pagerState = null)
        {
            // New page -> no need to read page, just allocate a new buffer
            var state  = GetTransactionState(tx);
            var size   = numberOfPages * Constants.Storage.PageSize;
            var buffer = GetBufferAndAddToTxState(pageNumber, state, size);

            return(buffer.Pointer);
        }
Ejemplo n.º 21
0
        public override byte *AcquirePagePointer(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState = null)
        {
            var state = GetTransactionState(tx);

            if (state.LoadedBuffers.TryGetValue(pageNumber, out var buffer))
            {
                return(buffer.Pointer);
            }

            var pagePointer = Inner.AcquirePagePointer(tx, pageNumber, pagerState);

            var pageHeader = (PageHeader *)pagePointer;

            var size = GetNumberOfPages(pageHeader) * Constants.Storage.PageSize;

            buffer = GetBufferAndAddToTxState(pageNumber, state, size);

            Memory.Copy(buffer.Pointer, pagePointer, buffer.Size);

            DecryptPage((PageHeader *)buffer.Pointer);

            if (Sodium.crypto_generichash(buffer.Hash, EncryptionBuffer.HashSize, buffer.Pointer, (ulong)buffer.Size, null, UIntPtr.Zero) != 0)
            {
                ThrowInvalidHash();
            }

            return(buffer.Pointer);
        }
Ejemplo n.º 22
0
        public override byte *AcquirePagePointer(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState = null)
        {
            var state = GetTransactionState(tx);

            if (state.LoadedBuffers.TryGetValue(pageNumber, out var buffer))
            {
                return(buffer.Pointer);
            }

            var pagePointer = Inner.AcquirePagePointer(tx, pageNumber, pagerState);

            var pageHeader = (PageHeader *)pagePointer;

            var size = GetNumberOfPages(pageHeader) * Constants.Storage.PageSize;

            buffer = GetBufferAndAddToTxState(pageNumber, state, size);

            Memory.Copy(buffer.Pointer, pagePointer, buffer.Size);

            DecryptPage((PageHeader *)buffer.Pointer);

            buffer.Checksum = Hashing.XXHash64.Calculate(buffer.Pointer, (ulong)buffer.Size);

            return(buffer.Pointer);
        }
Ejemplo n.º 23
0
        public virtual byte* AcquirePagePointer(Transaction tx, long pageNumber, PagerState pagerState = null)
        {
            ThrowObjectDisposedIfNeeded();

            var state = pagerState ?? PagerState;

            if (tx != null)
                tx.EnsurePagerStateReference(state);

            return state.MapBase + pageNumber * PageSize;
        }
Ejemplo n.º 24
0
 public override byte *AcquireRawPagePointer(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState = null)
 {
     return(Inner.AcquireRawPagePointer(tx, pageNumber, pagerState));
 }
		public override byte* AcquirePagePointer(long pageNumber, PagerState pagerState = null)
		{
		    return (pagerState ?? PagerState).MapBase + (pageNumber * PageSize);
		}
Ejemplo n.º 26
0
 void IPagerLevelTransactionState.EnsurePagerStateReference(PagerState state)
 {
     //nothing to do
 }
Ejemplo n.º 27
0
 public Simple4KbBatchWrites(AbstractPager abstractPager)
 {
     _abstractPager = abstractPager;
     _pagerState    = _abstractPager.GetPagerStateAndAddRefAtomically();
 }
Ejemplo n.º 28
0
        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 (CanPrefetch.Value && state != null)
            {
                if (state.ShouldPrefetchSegment(pageNumber, out void *virtualAddress, out long bytes))
                {
                    var command = new PalDefinitions.PrefetchRanges(virtualAddress, bytes);
                    GlobalPrefetchingBehavior.GlobalPrefetcher.Value.CommandQueue.TryAdd(command, 0);
                }
            }

            return(base.AcquirePagePointer(tx, pageNumber, state));
        }
Ejemplo n.º 29
0
        public override int CopyPage(I4KbBatchWrites destI4KbBatchWrites, long pageNumber, PagerState pagerState)
        {
            long sizeToMap               = AllocationGranularity;
            var  distanceFromStart       = (pageNumber % NumberOfPagesInAllocationGranularity);
            var  allocationStartPosition = pageNumber - distanceFromStart;

            var offset  = allocationStartPosition * Constants.Storage.PageSize;
            var mmflags = _copyOnWriteMode ? MmapFlags.MAP_PRIVATE : MmapFlags.MAP_SHARED;

            var result = Syscall.mmap64(IntPtr.Zero, (UIntPtr)sizeToMap,
                                        MmapProts.PROT_READ | MmapProts.PROT_WRITE,
                                        mmflags, _fd, offset);

            try
            {
                if (result.ToInt64() == -1) //system didn't succeed in mapping the address where we wanted
                {
                    var err = Marshal.GetLastWin32Error();
                    Syscall.ThrowLastError(err,
                                           $"Unable to map (default view size) {sizeToMap / Constants.Size.Kilobyte:#,#0} kb for page {pageNumber} starting at {allocationStartPosition} on {FileName}");
                }

                var pageHeader = (PageHeader *)(result.ToInt64() + distanceFromStart * Constants.Storage.PageSize);

                int numberOfPages = 1;
                if ((pageHeader->Flags & PageFlags.Overflow) == PageFlags.Overflow)
                {
                    numberOfPages = VirtualPagerLegacyExtensions.GetNumberOfOverflowPages(pageHeader->OverflowSize);
                }


                if (numberOfPages + distanceFromStart > NumberOfPagesInAllocationGranularity)
                {
                    Syscall.munmap(result, (UIntPtr)sizeToMap);
                    result    = new IntPtr(-1);
                    sizeToMap = NearestSizeToAllocationGranularity((numberOfPages + distanceFromStart) *
                                                                   Constants.Storage.PageSize);
                    result = Syscall.mmap64(IntPtr.Zero, (UIntPtr)sizeToMap, MmapProts.PROT_READ | MmapProts.PROT_WRITE,
                                            mmflags, _fd, offset);

                    if (result.ToInt64() == -1)
                    {
                        var err = Marshal.GetLastWin32Error();
                        Syscall.ThrowLastError(err,
                                               $"Unable to map {sizeToMap / Constants.Size.Kilobyte:#,#0} kb for page {pageNumber} starting at {allocationStartPosition} on {FileName}");
                    }

                    pageHeader = (PageHeader *)(result.ToInt64() + (distanceFromStart * Constants.Storage.PageSize));
                }
                const int adjustPageSize = (Constants.Storage.PageSize) / (4 * Constants.Size.Kilobyte);

                destI4KbBatchWrites.Write(pageHeader->PageNumber * adjustPageSize, numberOfPages * adjustPageSize,
                                          (byte *)pageHeader);

                return(numberOfPages);
            }
            finally
            {
                if (result.ToInt64() != -1)
                {
                    Syscall.munmap(result, (UIntPtr)sizeToMap);
                }
            }
        }
Ejemplo n.º 30
0
        public virtual int CopyPage(IPagerBatchWrites destPagerBatchWrites, int scratchNumber, long p, PagerState pagerState)
        {
            var item = GetScratchBufferFile(scratchNumber);

            ScratchBufferFile bufferFile = item.File;

            return(bufferFile.CopyPage(destPagerBatchWrites, p, pagerState));
        }
Ejemplo n.º 31
0
        public override byte *AcquirePagePointer(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState = null)
        {
            if (DisposeOnceRunner.Disposed)
            {
                ThrowAlreadyDisposedException();
            }

            if (pageNumber > NumberOfAllocatedPages || pageNumber < 0)
            {
                ThrowOnInvalidPageNumber(pageNumber);
            }

            var state = GetTransactionState(tx);

            var distanceFromStart       = (pageNumber % NumberOfPagesInAllocationGranularity);
            var allocationStartPosition = pageNumber - distanceFromStart;

            if (state.LoadedPages.TryGetValue(allocationStartPosition, out var page))
            {
                return(page.Pointer + (distanceFromStart * Constants.Storage.PageSize));
            }

            page = MapPages(state, allocationStartPosition, AllocationGranularity);
            return(page.Pointer + (distanceFromStart * Constants.Storage.PageSize));
        }
Ejemplo n.º 32
0
        private PagerState CreateNewPagerState()
        {
            MemoryMappedFileAccess memoryMappedFileAccess = _access == NativeFileAccess.GenericRead
                ? MemoryMappedFileAccess.Read
                : MemoryMappedFileAccess.ReadWrite;
            MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(_fileStream, null, _fileStream.Length,
                memoryMappedFileAccess,
                null, HandleInheritability.None, true);
            MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(0, _fileStream.Length, memoryMappedFileAccess);
            byte* p = null;
            accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref p);			
            var newPager = new PagerState(this)
            {
                Accessor = accessor,
				Files = new[] { mmf },
                MapBase = p
            };
            newPager.AddRef(); // one for the pager
            return newPager;
        }
 public override byte *AcquirePagePointer(long pageNumber, PagerState pagerState = null)
 {
     return((pagerState ?? PagerState).MapBase + (pageNumber * PageSize));
 }
Ejemplo n.º 34
0
        public override byte* AcquirePagePointer(long pageNumber, PagerState pagerState = null)
        {
            ThrowObjectDisposedIfNeeded();

            return (pagerState ?? PagerState).MapBase + (pageNumber*PageSize);
        }
Ejemplo n.º 35
0
        private PagerState CreateNewPagerState()
        {
            var mmf = MemoryMappedFile.CreateFromFile(_fileStream, Guid.NewGuid().ToString(), _fileStream.Length,
                                                      MemoryMappedFileAccess.Read, null, HandleInheritability.None, true);

            MemoryMappedViewAccessor accessor;
            try
            {
                accessor = mmf.CreateViewAccessor(0, _fileStream.Length, MemoryMappedFileAccess.Read);
            }
            catch (Exception)
            {
                mmf.Dispose();
                throw;
            }
            byte* p = null;
            accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref p);

            var newPager = new PagerState(this)
                 {
                     Accessor = accessor,
					 Files = new[] { mmf },
                     MapBase = p
                 };
            newPager.AddRef(); // one for the pager
            return newPager;
        }
Ejemplo n.º 36
0
 public override byte* AcquirePagePointer(long pageNumber, PagerState pagerState = null)
 {
     if (pageNumber >= NumberOfAllocatedPages)
         throw new InvalidOperationException("Tried to read a page that wasn't committed");
     return _baseAddress + (pageNumber * PageSize);
 }
Ejemplo n.º 37
0
 public override int CopyPage(I4KbBatchWrites destwI4KbBatchWrites, long p, PagerState pagerState)
 {
     return(CopyPageImpl(destwI4KbBatchWrites, p, pagerState));
 }
Ejemplo n.º 38
0
 public Page ReadPage(Transaction tx, long p, PagerState pagerState = null)
 {
     return _scratchPager.Read(tx, p, pagerState);
 }
Ejemplo n.º 39
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;
        }
Ejemplo n.º 40
0
        public override int CopyPage(I4KbBatchWrites destI4KbBatchWrites, long pageNumber, PagerState pagerState)
        {
            var distanceFromStart       = (pageNumber % NumberOfPagesInAllocationGranularity);
            var allocationStartPosition = pageNumber - distanceFromStart;

            var offset = new WindowsMemoryMapPager.SplitValue {
                Value = (ulong)allocationStartPosition * (ulong)Constants.Storage.PageSize
            };
            var result = MapViewOfFileEx(_hFileMappingObject, _mmFileAccessType, offset.High,
                                         offset.Low,
                                         (UIntPtr)AllocationGranularity, null);

            try
            {
                if (result == null)
                {
                    var lastWin32Error = Marshal.GetLastWin32Error();
                    throw new Win32Exception($"Unable to map (default view size) {AllocationGranularity / Constants.Size.Kilobyte:#,#0} kb for page {pageNumber} starting at {allocationStartPosition} on {FileName}",
                                             new Win32Exception(lastWin32Error));
                }

                var pageHeader = (PageHeader *)(result + distanceFromStart * Constants.Storage.PageSize);

                int numberOfPages = 1;
                if ((pageHeader->Flags & PageFlags.Overflow) == PageFlags.Overflow)
                {
                    numberOfPages = VirtualPagerLegacyExtensions.GetNumberOfOverflowPages(pageHeader->OverflowSize);
                }

                if (numberOfPages + distanceFromStart > NumberOfPagesInAllocationGranularity)
                {
                    UnmapViewOfFile(result);
                    result = null;

                    var newSize = NearestSizeToAllocationGranularity((numberOfPages + distanceFromStart) * Constants.Storage.PageSize);
                    result = MapViewOfFileEx(_hFileMappingObject, _mmFileAccessType, offset.High,
                                             offset.Low,
                                             (UIntPtr)newSize, null);

                    if (result == null)
                    {
                        var lastWin32Error = Marshal.GetLastWin32Error();
                        throw new Win32Exception($"Unable to map {newSize / Constants.Size.Kilobyte:#,#0} kb for page {pageNumber} starting at {allocationStartPosition} on {FileName}",
                                                 new Win32Exception(lastWin32Error));
                    }

                    pageHeader = (PageHeader *)(result + (distanceFromStart * Constants.Storage.PageSize));
                }
                const int adjustPageSize = (Constants.Storage.PageSize) / (4 * Constants.Size.Kilobyte);

                destI4KbBatchWrites.Write(pageHeader->PageNumber * adjustPageSize, numberOfPages * adjustPageSize, (byte *)pageHeader);

                return(numberOfPages);
            }
            finally
            {
                if (result != null)
                {
                    UnmapViewOfFile(result);
                }
            }
        }
Ejemplo n.º 41
0
		public Page ReadPage(Transaction tx, long pageNumber, PagerState scratchPagerState)
		{
			// read transactions have to read from journal snapshots
			if (tx.Flags == TransactionFlags.Read)
			{
				// read log snapshots from the back to get the most recent version of a page
				for (var i = tx.JournalSnapshots.Count - 1; i >= 0; i--)
				{
					JournalFile.PagePosition value;
					if (tx.JournalSnapshots[i].PageTranslationTable.TryGetValue(tx, pageNumber, out value))
					{
						var page = _env.ScratchBufferPool.ReadPage(value.ScratchPos, scratchPagerState);

						Debug.Assert(page.PageNumber == pageNumber);

						return page;
					}
				}

				return null;
			}

			// write transactions can read directly from journals
			var files = _files;
			for (var i = files.Count - 1; i >= 0; i--)
			{
				JournalFile.PagePosition value;
				if (files[i].PageTranslationTable.TryGetValue(tx, pageNumber, out value))
				{
					var page = _env.ScratchBufferPool.ReadPage(value.ScratchPos, scratchPagerState);

					Debug.Assert(page.PageNumber == pageNumber);

					return page;
				}
			}

			return null;
		}
Ejemplo n.º 42
0
        public override byte *AcquirePagePointer(long pageNumber, PagerState pagerState = null)
        {
            ThrowObjectDisposedIfNeeded();

            return((pagerState ?? PagerState).MapBase + (pageNumber * PageSize));
        }
Ejemplo n.º 43
0
        public Page ReadPage(int scratchNumber, long p, PagerState pagerState = null)
        {
            ScratchBufferFile bufferFile;
            ScratchBufferCacheItem item = lastScratchBuffer;
            if ( item.Number == scratchNumber )
            {
                bufferFile = item.File;
            }
            else
            {
                bufferFile = _scratchBuffers[scratchNumber];
                lastScratchBuffer = new ScratchBufferCacheItem( scratchNumber, bufferFile );
            }

            return bufferFile.ReadPage(p, pagerState);
        }
Ejemplo n.º 44
0
 public int CopyPage(I4KbBatchWrites destI4KbBatchWrites, long p, PagerState pagerState)
 {
     return(_scratchPager.CopyPage(destI4KbBatchWrites, p, pagerState));
 }
Ejemplo n.º 45
0
 public Page ReadPage(LowLevelTransaction tx, long p, PagerState pagerState = null)
 {
     return(new Page(_scratchPager.AcquirePagePointerWithOverflowHandling(tx, p, pagerState)));
 }
Ejemplo n.º 46
0
        private byte *AcquirePagePointerInternal(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState)
        {
            if (DisposeOnceRunner.Disposed)
            {
                goto AlreadyDisposed;
            }

            if (pageNumber > NumberOfAllocatedPages || pageNumber < 0)
            {
                goto InvalidPageNumber;
            }

            var state = pagerState ?? _pagerState;

            tx?.EnsurePagerStateReference(state);

            return(state.MapBase + pageNumber * Constants.Storage.PageSize);

            AlreadyDisposed   : ThrowAlreadyDisposedException();
            InvalidPageNumber : ThrowOnInvalidPageNumber(pageNumber);
            return(null); // Will never happen.
        }
Ejemplo n.º 47
0
 public abstract byte* AcquirePagePointer(long pageNumber, PagerState pagerState = null);
Ejemplo n.º 48
0
 public abstract int CopyPage(I4KbBatchWrites destwI4KbBatchWrites, long p, PagerState pagerState);
		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;
		}
Ejemplo n.º 50
0
 public virtual byte *AcquireRawPagePointer(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState = null)
 {
     return(AcquirePagePointer(tx, pageNumber, pagerState));
 }
Ejemplo n.º 51
0
		public Page ReadPage(int scratchNumber, long p, PagerState pagerState = null)
		{
			return _scratchBuffers[scratchNumber].ReadPage(p, pagerState);
		}
Ejemplo n.º 52
0
		public override void AllocateMorePages(Transaction tx, long newLength)
		{
			var oldSize = NumberOfAllocatedPages * PageSize;
			if (newLength < oldSize)
				throw new ArgumentException("Cannot set the legnth to less than the current length");
			if (newLength == oldSize)
		        return; // nothing to do

			var increaseSize = (newLength - oldSize);
			NumberOfAllocatedPages += increaseSize / PageSize;
			var newPtr = Marshal.AllocHGlobal(new IntPtr(increaseSize));

			var buffer = new Buffer
			{
				Handle = newPtr,
				Base = (byte*) newPtr.ToPointer(),
				Size = increaseSize
			};

			_buffers = _buffers.Append(buffer);

		    var newPager = new PagerState(this);
			newPager.AddRef(); // one for the pager

			if (tx != null) // we only pass null during startup, and we don't need it there
			{
				newPager.AddRef(); // one for the current transaction
				tx.AddPagerState(newPager);
			}
			PagerState.Release();
			PagerState = newPager;
		}