Ejemplo n.º 1
0
        protected internal override PagerState AllocateMorePages(long newLength)
        {
            if (DisposeOnceRunner.Disposed)
            {
                ThrowAlreadyDisposedException();
            }
            var newLengthAfterAdjustment = NearestSizeToPageSize(newLength);

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

            var allocationSize = newLengthAfterAdjustment - _totalAllocationSize;

            PosixHelper.AllocateFileSpace(_options, _fd, _totalAllocationSize + allocationSize, FileName.FullPath);

            if (DeleteOnClose == false && _isSyncDirAllowed && Syscall.SyncDirectory(FileName.FullPath) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                Syscall.ThrowLastError(err);
            }

            PagerState newPagerState = CreatePagerState();

            if (newPagerState == null)
            {
                var errorMessage = string.Format(
                    "Unable to allocate more pages - unsuccessfully tried to allocate continuous block of virtual memory with size = {0:##,###;;0} bytes",
                    (_totalAllocationSize + allocationSize));

                throw new OutOfMemoryException(errorMessage);
            }

            newPagerState.DebugVerify(newLengthAfterAdjustment);

            SetPagerState(newPagerState);

            _totalAllocationSize  += allocationSize;
            NumberOfAllocatedPages = _totalAllocationSize / Constants.Storage.PageSize;

            return(newPagerState);
        }
Ejemplo n.º 2
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));
        }
Ejemplo n.º 3
0
        private unsafe void WriteFile(long position, byte *p, int numberOf4Kb)
        {
            if (numberOf4Kb == 0)
            {
                return; // nothing to do
            }
            var  nNumberOfBytesToWrite = (ulong)numberOf4Kb * (4 * Constants.Size.Kilobyte);
            long actuallyWritten       = 0;
            long result;

            using (_options.IoMetrics.MeterIoRate(_filename.FullPath, IoMetrics.MeterType.JournalWrite, (long)nNumberOfBytesToWrite))
            {
                do
                {
                    result = Syscall.pwrite(_fd, p, nNumberOfBytesToWrite - (ulong)actuallyWritten,
                                            position * 4 * Constants.Size.Kilobyte);
                    if (result < 1)
                    {
                        break;
                    }
                    actuallyWritten += result;
                    p += actuallyWritten;
                } while ((ulong)actuallyWritten < nNumberOfBytesToWrite);
            }
            if (result == -1)
            {
                var err = Marshal.GetLastWin32Error();
                Syscall.ThrowLastError(err, "when writing to " + _filename);
            }
            else if (result == 0)
            {
                var err = Marshal.GetLastWin32Error();
                throw new IOException($"pwrite reported zero bytes written, after write of {actuallyWritten} bytes out of {nNumberOfBytesToWrite}. lastErrNo={err} on {_filename}");
            }
            else if ((ulong)actuallyWritten != nNumberOfBytesToWrite)
            {
                var err = Marshal.GetLastWin32Error();
                throw new IOException($"pwrite couln't write {nNumberOfBytesToWrite} to file. only {actuallyWritten} written. lastErrNo={err} on {_filename}");
            }
        }
Ejemplo n.º 4
0
        public void Truncate(long size)
        {
            var result = Syscall.ftruncate(_fd, (IntPtr)size);

            if (result == -1)
            {
                var err = Marshal.GetLastWin32Error();
                Syscall.ThrowLastError(err, "when truncating " + _filename);
            }
            result = Syscall.FSync(_fd);
            if (result == -1)
            {
                var err = Marshal.GetLastWin32Error();
                Syscall.ThrowLastError(err, "when fsycning " + _filename);
            }

            if (Syscall.CheckSyncDirectoryAllowed(_filename.FullPath) && Syscall.SyncDirectory(_filename.FullPath) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                Syscall.ThrowLastError(err, "when syncing dir for " + _filename);
            }
        }
Ejemplo n.º 5
0
        public static void AllocateFileSpace(StorageEnvironmentOptions options, int fd, long size, string file)
        {
            bool usingLseek;
            var  result = Syscall.AllocateFileSpace(fd, size, file, out usingLseek);

            if (result == (int)Errno.ENOSPC)
            {
                foreach (var drive in DriveInfo.GetDrives())
                {
                    if (file.StartsWith(drive.RootDirectory.Name))
                    {
                        throw new DiskFullException(drive, file, (long)size);
                    }
                }
                // shouldn't happen, and we can throw normally here
                throw new DiskFullException(null, file, (long)size);
            }
            if (result != 0)
            {
                Syscall.ThrowLastError(result, $"posix_fallocate(\"{file}\", {size})");
            }
        }
Ejemplo n.º 6
0
        protected internal override PagerState AllocateMorePages(long newLength)
        {
            var newLengthAfterAdjustment = NearestSizeToAllocationGranularity(newLength);

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

            var allocationSize = newLengthAfterAdjustment - _totalAllocationSize;

            PosixHelper.AllocateFileSpace(_options, _fd, _totalAllocationSize + allocationSize, FileName.FullPath);

            if (_isSyncDirAllowed && Syscall.SyncDirectory(FileName.FullPath) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                Syscall.ThrowLastError(err);
            }

            _totalAllocationSize  += allocationSize;
            NumberOfAllocatedPages = _totalAllocationSize / Constants.Storage.PageSize;

            return(null);
        }
Ejemplo n.º 7
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);
                }
            }
        }