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); }
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)); }
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}"); } }
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); } }
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})"); } }
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); }
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); } } }