diff --git a/src/memory/map.cpp b/src/memory/map.cpp index 151e15b8e..b1e8b646e 100644 --- a/src/memory/map.cpp +++ b/src/memory/map.cpp @@ -554,15 +554,55 @@ bool map::remap_(size_t size) NOEXCEPT return finalize_(size); } +#if defined(HAVE_APPLE) +// ::fallocate is not defined on macOS, so implement. Ignores mode (linux). +int fallocate(int fd, int, size_t offset, size_t len) NOEXCEPT +{ + fstore_t store + { + // Prefer contiguous allocation + .fst_flags = F_ALLOCATECONTIG, + + // Allocate from EOF + .fst_posmode = F_PEOFPOSMODE, + + // Start from current capacity + .fst_offset = offset, + + // Delta size + .fst_length = len, + + // Output: actual bytes allocated + .fst_bytesalloc = 0 + }; + + // Try contiguous allocation. + auto result = ::fcntl(fd, F_PREALLOCATE, &store); + + // Fallback to non-contiguous. + if ((result == fail) && (errno != ENOSPC)) + { + store.fst_flags = F_ALLOCATEALL; + result = ::fcntl(fd, F_PREALLOCATE, &store); + } + + if (result == fail) + return fail; + + // Extend file to new size (required for mmap). This is not required on + // Linux because fallocate(2) automatically extends file's logical size. + return ::ftruncate(fd, offset + len); +} +#endif // HAVE_APPLE + // disk_full: space is set but no code is set with false return. bool map::resize_(size_t size) NOEXCEPT { // Disk full detection, any other failure is an abort. -#if defined(HAVE_APPLE) - // TODO: implement fallocate for macOS (open and write a byte per block). - if (::ftruncate(opened_, size) == fail) -#else +#if !defined (WITHOUT_FALLOCATE) if (::fallocate(opened_, 0, capacity_, size - capacity_) == fail) +#else + if (::ftruncate(opened_, size) == fail) #endif { // Disk full is the only restartable store failure (leave mapped). @@ -594,6 +634,7 @@ bool map::finalize_(size_t size) NOEXCEPT return false; } +#if !defined (WITHOUT_MADVISE) #if !defined(HAVE_MSC) // Get page size (usually 4KB). const int page_size = ::sysconf(_SC_PAGESIZE); @@ -629,6 +670,7 @@ bool map::finalize_(size_t size) NOEXCEPT } } #endif +#endif // WITHOUT_MADVISE loaded_ = true; capacity_ = size;