Skip to content

Commit 076f189

Browse files
authored
Merge pull request #672 from evoskuil/master
Define ::fallocate for macos (fix disk full handling).
2 parents 98acba1 + 855142b commit 076f189

File tree

1 file changed

+46
-4
lines changed

1 file changed

+46
-4
lines changed

src/memory/map.cpp

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
558599
bool 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

Comments
 (0)