@@ -554,15 +554,55 @@ bool map::remap_(size_t size) NOEXCEPT
554554 return finalize_ (size);
555555}
556556
557+ #if defined(HAVE_APPLE)
558+ // ::fallocate is not defined on macOS, so implement. Ignores mode (linux).
559+ int fallocate (int fd, int , size_t offset, size_t len) NOEXCEPT
560+ {
561+ fstore_t store
562+ {
563+ // Prefer contiguous allocation
564+ .fst_flags = F_ALLOCATECONTIG,
565+
566+ // Allocate from EOF
567+ .fst_posmode = F_PEOFPOSMODE,
568+
569+ // Start from current capacity
570+ .fst_offset = offset,
571+
572+ // Delta size
573+ .fst_length = len,
574+
575+ // Output: actual bytes allocated
576+ .fst_bytesalloc = 0
577+ };
578+
579+ // Try contiguous allocation.
580+ auto result = ::fcntl (fd, F_PREALLOCATE, &store);
581+
582+ // Fallback to non-contiguous.
583+ if ((result == fail) && (errno != ENOSPC))
584+ {
585+ store.fst_flags = F_ALLOCATEALL;
586+ result = ::fcntl (fd, F_PREALLOCATE, &store);
587+ }
588+
589+ if (result == fail)
590+ return fail;
591+
592+ // Extend file to new size (required for mmap). This is not required on
593+ // Linux because fallocate(2) automatically extends file's logical size.
594+ return ::ftruncate (fd, offset + len);
595+ }
596+ #endif // HAVE_APPLE
597+
557598// disk_full: space is set but no code is set with false return.
558599bool map::resize_ (size_t size) NOEXCEPT
559600{
560601 // Disk full detection, any other failure is an abort.
561- #if defined(HAVE_APPLE)
562- // TODO: implement fallocate for macOS (open and write a byte per block).
563- if (::ftruncate (opened_, size) == fail)
564- #else
602+ #if !defined (WITHOUT_FALLOCATE)
565603 if (::fallocate (opened_, 0 , capacity_, size - capacity_) == fail)
604+ #else
605+ if (::ftruncate (opened_, size) == fail)
566606#endif
567607 {
568608 // Disk full is the only restartable store failure (leave mapped).
@@ -594,6 +634,7 @@ bool map::finalize_(size_t size) NOEXCEPT
594634 return false ;
595635 }
596636
637+ #if !defined (WITHOUT_MADVISE)
597638#if !defined(HAVE_MSC)
598639 // Get page size (usually 4KB).
599640 const int page_size = ::sysconf (_SC_PAGESIZE);
@@ -629,6 +670,7 @@ bool map::finalize_(size_t size) NOEXCEPT
629670 }
630671 }
631672#endif
673+ #endif // WITHOUT_MADVISE
632674
633675 loaded_ = true ;
634676 capacity_ = size;
0 commit comments