예제 #1
0
        public PosixMemoryMapPager(string file, long?initialFileSize = null)
        {
            _file = file;
            //todo, do we need O_SYNC here?
            //todo, ALLPERMS ?
            _fd = Syscall.open(file, OpenFlags.O_RDWR | OpenFlags.O_CREAT | OpenFlags.O_SYNC,
                               FilePermissions.ALLPERMS);
            if (_fd == -1)
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }

            SysPageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE);

            _totalAllocationSize = GetFileSize();
            if (_totalAllocationSize == 0 && initialFileSize.HasValue)
            {
                _totalAllocationSize = NearestSizeToPageSize(initialFileSize.Value);
            }
            if (_totalAllocationSize == 0 || _totalAllocationSize % SysPageSize != 0)
            {
                _totalAllocationSize = NearestSizeToPageSize(_totalAllocationSize);
                var result = Syscall.ftruncate(_fd, _totalAllocationSize);
                if (result != 0)
                {
                    PosixHelper.ThrowLastError(result);
                }
            }

            NumberOfAllocatedPages = _totalAllocationSize / PageSize;
            PagerState.Release();
            PagerState = CreatePagerState();
        }
예제 #2
0
        public unsafe bool Read(long pageNumber, byte *buffer, int count)
        {
            if (_fdReads == -1)
            {
                _fdReads = Syscall.open(_filename, OpenFlags.O_RDONLY, FilePermissions.S_IRUSR);
                if (_fdReads == -1)
                {
                    var err = Marshal.GetLastWin32Error();
                    PosixHelper.ThrowLastError(err, "when opening " + _filename);
                }
            }
            long position = pageNumber * _options.PageSize;

            while (count > 0)
            {
                var result = Syscall.pread(_fdReads, buffer, (ulong)count, position);
                if (result == 0) //eof
                {
                    return(false);
                }
                count    -= (int)result;
                buffer   += result;
                position += result;
            }
            return(true);
        }
예제 #3
0
        private PagerState CreatePagerState()
        {
            var startingBaseAddressPtr = Syscall.mmap(IntPtr.Zero, (UIntPtr)_totalAllocationSize,
                                                      MmapProts.PROT_READ | MmapProts.PROT_WRITE,
                                                      MmapFlags.MAP_SHARED, _fd, IntPtr.Zero);

            if (startingBaseAddressPtr.ToInt64() == -1) //system didn't succeed in mapping the address where we wanted
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err, "mmap on " + FileName);
            }
            NativeMemory.RegisterFileMapping(FileName, startingBaseAddressPtr, _totalAllocationSize);
            var allocationInfo = new PagerState.AllocationInfo
            {
                BaseAddress = (byte *)startingBaseAddressPtr.ToPointer(),
                Size        = _totalAllocationSize,
                MappedFile  = null
            };

            var newPager = new PagerState(this)
            {
                Files           = null, // unused
                MapBase         = allocationInfo.BaseAddress,
                AllocationInfos = new[] { allocationInfo }
            };

            return(newPager);
        }
예제 #4
0
        public PosixPageFileBackedMemoryMapPager(string file, long?initialFileSize = null)
        {
            var instanceId = Interlocked.Increment(ref _counter);

            _file = "/" + Syscall.getpid() + "-" + instanceId + "-" + file;
            _fd   = Rt.shm_open(_file, OpenFlags.O_RDWR | OpenFlags.O_CREAT, (int)FilePermissions.ALLPERMS);
            if (_fd == -1)
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }

            SysPageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE);

            if (initialFileSize.HasValue)
            {
                _totalAllocationSize = NearestSizeToPageSize(initialFileSize.Value);
            }

            _totalAllocationSize = NearestSizeToPageSize(_totalAllocationSize);
            var result = Syscall.ftruncate(_fd, _totalAllocationSize);

            if (result != 0)
            {
                PosixHelper.ThrowLastError(result);
            }

            NumberOfAllocatedPages = _totalAllocationSize / PageSize;
            PagerState.Release();
            PagerState = CreatePagerState();
        }
        public PosixTempMemoryMapPager(int pageSize, string file, long?initialFileSize = null)
            : base(pageSize)
        {
            _file = file;
            PosixHelper.EnsurePathExists(file);

            _fd = Syscall.open(_file, OpenFlags.O_RDWR | OpenFlags.O_CREAT | OpenFlags.O_EXCL,
                               FilePermissions.S_IWUSR | FilePermissions.S_IRUSR);

            if (_fd == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err);
            }
            DeleteOnClose = true;

            SysPageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE);

            _totalAllocationSize = NearestSizeToPageSize(initialFileSize ?? _totalAllocationSize);
            PosixHelper.AllocateFileSpace(_fd, (ulong)_totalAllocationSize);

            NumberOfAllocatedPages = _totalAllocationSize / _pageSize;
            PagerState.Release();
            PagerState = CreatePagerState();
        }
        private PagerState CreatePagerState()
        {
            var fileSize = GetFileSize();
            var startingBaseAddressPtr = Syscall.mmap(IntPtr.Zero, (ulong)fileSize,
                                                      MmapProts.PROT_READ | MmapProts.PROT_WRITE,
                                                      MmapFlags.MAP_SHARED, _fd, 0);

            if (startingBaseAddressPtr.ToInt64() == -1) //system didn't succeed in mapping the address where we wanted
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }

            var allocationInfo = new PagerState.AllocationInfo
            {
                BaseAddress = (byte *)startingBaseAddressPtr.ToPointer(),
                Size        = fileSize,
                MappedFile  = null
            };

            var newPager = new PagerState(this)
            {
                Files           = null, // unused
                MapBase         = allocationInfo.BaseAddress,
                AllocationInfos = new[] { allocationInfo }
            };

            newPager.AddRef(); // one for the pager
            return(newPager);
        }
        public PosixJournalWriter(StorageEnvironmentOptions options, string filename, long journalSize)
        {
            _options  = options;
            _filename = filename;


            _fd = Syscall.open(filename, OpenFlags.O_WRONLY | OpenFlags.O_DSYNC | OpenFlags.O_DIRECT | OpenFlags.O_CREAT,
                               FilePermissions.S_IWUSR | FilePermissions.S_IRUSR);

            if (_fd == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err);
            }

            var result = Syscall.posix_fallocate(_fd, 0, (ulong)journalSize);

            if (result != 0)
            {
                PosixHelper.ThrowLastError(result);
            }

            if (PosixHelper.CheckSyncDirectoryAllowed(_filename) && PosixHelper.SyncDirectory(filename) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err);
            }

            NumberOfAllocatedPages = (int)(journalSize / _options.PageSize);
        }
        public PosixMemoryMapPager(string file, long?initialFileSize = null)
        {
            _file = file;
            _fd   = Syscall.open(file, OpenFlags.O_RDWR | OpenFlags.O_CREAT | OpenFlags.O_SYNC,
                                 FilePermissions.S_IWUSR | FilePermissions.S_IRUSR);
            if (_fd == -1)
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }

            SysPageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE);

            _totalAllocationSize = GetFileSize();
            if (_totalAllocationSize == 0 && initialFileSize.HasValue)
            {
                _totalAllocationSize = NearestSizeToPageSize(initialFileSize.Value);
            }
            if (_totalAllocationSize == 0 || _totalAllocationSize % SysPageSize != 0 ||
                _totalAllocationSize != GetFileSize())
            {
                _totalAllocationSize = NearestSizeToPageSize(_totalAllocationSize);
                PosixHelper.AllocateFileSpace(_fd, (ulong)_totalAllocationSize);
            }

            NumberOfAllocatedPages = _totalAllocationSize / PageSize;
            PagerState.Release();
            PagerState = CreatePagerState();
        }
예제 #9
0
        public unsafe bool Read(long pageNumber, byte *buffer, int count)
        {
            if (_fdReads == -1)
            {
                _fdReads = Syscall.open(_filename, OpenFlags.O_RDONLY);
                if (_fdReads == -1)
                {
                    PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
                }
            }
            long position = pageNumber * AbstractPager.PageSize;

            while (count > 0)
            {
                var result = Syscall.pread(_fdReads, buffer, (ulong)count, position);
                if (result == 0)                 //eof
                {
                    return(false);
                }
                count    -= (int)result;
                buffer   += result;
                position += result;
            }
            return(true);
        }
예제 #10
0
        public override void Sync()
        {
            //TODO: Is it worth it to change to just one call for msync for the entire file?
            var currentState = GetPagerStateAndAddRefAtomically();

            try
            {
                using (var metric = Options.IoMetrics.MeterIoRate(FileName, IoMetrics.MeterType.DataSync, 0))
                {
                    foreach (var alloc in currentState.AllocationInfos)
                    {
                        metric.IncrementSize(alloc.Size);
                        var result = Syscall.msync(new IntPtr(alloc.BaseAddress), (UIntPtr)alloc.Size, MsyncFlags.MS_SYNC);
                        if (result == -1)
                        {
                            var err = Marshal.GetLastWin32Error();
                            PosixHelper.ThrowLastError(err, "msync on " + FileName);
                        }
                    }
                }
            }
            finally
            {
                currentState.Release();
            }
        }
        public override void ReleaseAllocationInfo(byte *baseAddress, long size)
        {
            var result = Syscall.munmap(new IntPtr(baseAddress), (ulong)size);

            if (result == -1)
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }
        }
예제 #12
0
        public override void ReleaseAllocationInfo(byte *baseAddress, long size)
        {
            var ptr    = new IntPtr(baseAddress);
            var result = Syscall.munmap(ptr, (UIntPtr)size);

            if (result == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err);
            }
            NativeMemory.UnregisterFileMapping(FileName, ptr, size);
        }
 public override void Sync()
 {
     //TODO: Is it worth it to change to just one call for msync for the entire file?
     foreach (var alloc in PagerState.AllocationInfos)
     {
         var result = Syscall.msync(new IntPtr(alloc.BaseAddress), (ulong)alloc.Size, MsyncFlags.MS_SYNC);
         if (result == -1)
         {
             PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
         }
     }
 }
예제 #14
0
        public unsafe void WriteBuffer(long position, byte *srcPosition, int sizeToWrite)
        {
            var offset = Convert.ToUInt64(sizeToWrite);

            var result = Syscall.pwrite(_fd, srcPosition, (ulong)sizeToWrite, (long)offset);

            if (result == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err);
            }
        }
        private long GetFileSize()
        {
            Stat buf;
            var  result = Syscall.fstat(_fd, out buf);

            if (result == -1)
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }
            var fileSize = buf.st_size;

            return(fileSize);
        }
예제 #16
0
        public unsafe void WriteGather(long position, IntPtr[] pages)
        {
            if (pages.Length == 0)
            {
                return; // nothing to do
            }
            var       start   = 0;
            const int IOV_MAX = 1024;

            while (start < pages.Length)
            {
                var byteLen = 0L;
                var locs    = new List <Iovec>
                {
                    new Iovec
                    {
                        iov_base = pages[start],
                        iov_len  = (ulong)_options.PageSize
                    }
                };
                start++;
                byteLen += _options.PageSize;
                for (int i = 1; i < pages.Length && locs.Count < IOV_MAX; i++, start++)
                {
                    byteLen += _options.PageSize;
                    var cur = locs[locs.Count - 1];
                    if (((byte *)cur.iov_base.ToPointer() + cur.iov_len) == (byte *)pages[i].ToPointer())
                    {
                        cur.iov_len          = cur.iov_len + (ulong)_options.PageSize;
                        locs[locs.Count - 1] = cur;
                    }
                    else
                    {
                        locs.Add(new Iovec
                        {
                            iov_base = pages[i],
                            iov_len  = (ulong)_options.PageSize
                        });
                    }
                }

                var result = Syscall.pwritev(_fd, locs.ToArray(), position);
                position += byteLen;
                if (result == -1)
                {
                    var err = Marshal.GetLastWin32Error();
                    PosixHelper.ThrowLastError(err);
                }
            }
        }
예제 #17
0
        public unsafe void WriteGather(long position, byte *[] pages)
        {
            var locs = new Iovec[pages.Length];

            for (int i = 0; i < locs.Length; i++)
            {
                locs[i].iov_base = new IntPtr(pages[i]);
                locs[i].iov_len  = AbstractPager.PageSize;
            }
            var result = Syscall.pwritev(_fd, locs, position);

            if (result == -1)
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }
        }
예제 #18
0
        protected override PagerState AllocateMorePages(long newLength)
        {
            if (Disposed)
            {
                ThrowAlreadyDisposedException();
            }
            var newLengthAfterAdjustment = NearestSizeToPageSize(newLength);

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

            var allocationSize = newLengthAfterAdjustment - _totalAllocationSize;

            PosixHelper.AllocateFileSpace(_fd, (ulong)(_totalAllocationSize + allocationSize));

            if (_isSyncDirAllowed && PosixHelper.SyncDirectory(_file) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.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);

            var tmp = PagerState;

            PagerState = newPagerState;
            tmp.Release(); //replacing the pager state --> so one less reference for it

            _totalAllocationSize  += allocationSize;
            NumberOfAllocatedPages = _totalAllocationSize / _pageSize;

            return(newPagerState);
        }
예제 #19
0
        public PosixJournalWriter(string filename, long journalSize)
        {
            _filename = filename;

            _fd = Syscall.open(filename, OpenFlags.O_WRONLY | OpenFlags.O_SYNC | OpenFlags.O_CREAT,
                               FilePermissions.ALLPERMS);
            if (_fd == -1)
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }

            var result = Syscall.posix_fallocate(_fd, 0, (ulong)journalSize);

            if (result != 0)
            {
                PosixHelper.ThrowLastError(result);
            }

            NumberOfAllocatedPages = journalSize / AbstractPager.PageSize;
        }
예제 #20
0
        public PosixMemoryMapPager(StorageEnvironmentOptions options, string file, long?initialFileSize = null,
                                   bool usePageProtection = false) : base(options, usePageProtection)
        {
            FileName          = file;
            _copyOnWriteMode  = options.CopyOnWriteMode && file.EndsWith(Constants.DatabaseFilename);
            _isSyncDirAllowed = PosixHelper.CheckSyncDirectoryAllowed(FileName);

            PosixHelper.EnsurePathExists(FileName);

            _fd = Syscall.open(file, OpenFlags.O_RDWR | OpenFlags.O_CREAT,
                               FilePermissions.S_IWUSR | FilePermissions.S_IRUSR);
            if (_fd == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err, "when opening " + file);
            }

            SysPageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE);

            _totalAllocationSize = GetFileSize();

            if (_totalAllocationSize == 0 && initialFileSize.HasValue)
            {
                _totalAllocationSize = NearestSizeToPageSize(initialFileSize.Value);
            }
            if (_totalAllocationSize == 0 || _totalAllocationSize % SysPageSize != 0 ||
                _totalAllocationSize != GetFileSize())
            {
                _totalAllocationSize = NearestSizeToPageSize(_totalAllocationSize);
                PosixHelper.AllocateFileSpace(_fd, (ulong)_totalAllocationSize, file);
            }

            if (_isSyncDirAllowed && PosixHelper.SyncDirectory(file) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err, "sync dir for " + file);
            }

            NumberOfAllocatedPages = _totalAllocationSize / PageSize;
            SetPagerState(CreatePagerState());
        }
예제 #21
0
        public PosixMemoryMapPager(int pageSize, string file, long?initialFileSize = null) : base(pageSize)
        {
            _file             = file;
            _isSyncDirAllowed = PosixHelper.CheckSyncDirectoryAllowed(_file);

            PosixHelper.EnsurePathExists(_file);

            _fd = Syscall.open(file, OpenFlags.O_RDWR | OpenFlags.O_CREAT,
                               FilePermissions.S_IWUSR | FilePermissions.S_IRUSR);
            if (_fd == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err);
            }

            SysPageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE);

            _totalAllocationSize = GetFileSize();

            if (_totalAllocationSize == 0 && initialFileSize.HasValue)
            {
                _totalAllocationSize = NearestSizeToPageSize(initialFileSize.Value);
            }
            if (_totalAllocationSize == 0 || _totalAllocationSize % SysPageSize != 0 ||
                _totalAllocationSize != GetFileSize())
            {
                _totalAllocationSize = NearestSizeToPageSize(_totalAllocationSize);
                PosixHelper.AllocateFileSpace(_fd, (ulong)_totalAllocationSize);
            }

            if (_isSyncDirAllowed && PosixHelper.SyncDirectory(file) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err);
            }

            NumberOfAllocatedPages = _totalAllocationSize / _pageSize;
            PagerState.Release();
            PagerState = CreatePagerState();
        }
예제 #22
0
        private unsafe void WriteFile(long position, byte *p, int numberOfPages)
        {
            if (numberOfPages == 0)
            {
                return; // nothing to do
            }
            var  nNumberOfBytesToWrite = (ulong)numberOfPages * (ulong)_options.PageSize;
            long actuallyWritten       = 0;
            long result;

            using (_options.IoMetrics.MeterIoRate(_filename, IoMetrics.MeterType.JournalWrite, (long)nNumberOfBytesToWrite))
            {
                do
                {
                    result = Syscall.pwrite(_fd, p, nNumberOfBytesToWrite - (ulong)actuallyWritten, position);
                    if (result < 1)
                    {
                        break;
                    }
                    actuallyWritten += result;
                    p += actuallyWritten;
                } while ((ulong)actuallyWritten < nNumberOfBytesToWrite);
            }
            if (result == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.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}");
            }
        }
예제 #23
0
        public void Truncate(long size)
        {
            var result = Syscall.ftruncate(_fd, (IntPtr)size);

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

            if (PosixHelper.CheckSyncDirectoryAllowed(_filename) && PosixHelper.SyncDirectory(_filename) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err, "when syncing dir for " + _filename);
            }
        }
예제 #24
0
        public PosixJournalWriter(StorageEnvironmentOptions options, string filename, long journalSize)
        {
            _options  = options;
            _filename = filename;
            _maxNumberOfPagesPerSingleWrite = int.MaxValue / _options.PageSize;

            _fd = Syscall.open(filename, OpenFlags.O_WRONLY | options.PosixOpenFlags | OpenFlags.O_CREAT,
                               FilePermissions.S_IWUSR | FilePermissions.S_IRUSR);

            if (_fd == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err, "when opening " + filename);
            }

            int result;

            if ((options.SafePosixOpenFlags & PerPlatformValues.OpenFlags.O_DIRECT) == 0)
            {
                // fallocate doesn't supported, we'll use lseek instead
                result = Syscall.AllocateUsingLseek(_fd, journalSize);
            }
            else
            {
                result = Syscall.posix_fallocate(_fd, IntPtr.Zero, (UIntPtr)journalSize);
            }
            if (result != 0)
            {
                PosixHelper.ThrowLastError(result, "when allocating " + filename);
            }

            if (PosixHelper.CheckSyncDirectoryAllowed(_filename) && PosixHelper.SyncDirectory(filename) == -1)
            {
                var err = Marshal.GetLastWin32Error();
                PosixHelper.ThrowLastError(err, "when syncing dir for on " + filename);
            }

            NumberOfAllocatedPages = (int)(journalSize / _options.PageSize);
        }
예제 #25
0
        public PosixTempMemoryMapPager(string file, long?initialFileSize = null)
        {
            var instanceId = Interlocked.Increment(ref _counter);

            _file = "/var/tmp/ravendb-" + Syscall.getpid() + "-" + instanceId + "-" + file;
            _fd   = Syscall.open(_file, OpenFlags.O_RDWR | OpenFlags.O_CREAT | OpenFlags.O_EXCL,
                                 FilePermissions.S_IWUSR | FilePermissions.S_IRUSR);
            if (_fd == -1)
            {
                PosixHelper.ThrowLastError(Marshal.GetLastWin32Error());
            }
            DeleteOnClose = true;

            SysPageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE);

            _totalAllocationSize = NearestSizeToPageSize(initialFileSize ?? _totalAllocationSize);
            PosixHelper.AllocateFileSpace(_fd, (ulong)_totalAllocationSize);

            NumberOfAllocatedPages = _totalAllocationSize / PageSize;
            PagerState.Release();
            PagerState = CreatePagerState();
        }