From 938f7520adea8bbc53d1644859170fb4b2e59d79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Edelbo?= Date: Thu, 13 Dec 2018 15:18:33 +0100 Subject: [PATCH] Fix problem with posix_fallocate on AWS Lambda --- CHANGELOG.md | 5 +++-- src/realm/util/file.cpp | 32 ++++++++++++++------------------ src/realm/util/file.hpp | 2 +- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ab27221134..d2ace4eb4e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,9 @@ * None. ### Fixed -* ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?) -* None. +* On AWS Lambda we may throw an "Operation not permitted" exception when calling posix_fallocate(). + A slower workaround has been supplied. + ([#3193](https://github.com/realm/realm-core/issues/3293)) ### Breaking changes * None. diff --git a/src/realm/util/file.cpp b/src/realm/util/file.cpp index fccaa188cef..7d024ad32ea 100644 --- a/src/realm/util/file.cpp +++ b/src/realm/util/file.cpp @@ -681,12 +681,6 @@ void File::prealloc(size_t size) { REALM_ASSERT_RELEASE(is_attached()); -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L // POSIX.1-2001 version - // Mostly Linux only - prealloc_if_supported(0, size); - -#else // Non-atomic fallback - if (size <= to_size_t(get_size())) { return; } @@ -713,6 +707,12 @@ void File::prealloc(size_t size) } }; +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L // POSIX.1-2001 version + // Mostly Linux only + if (!prealloc_if_supported(0, new_size)) { + manually_consume_space(); + } +#else // Non-atomic fallback #if REALM_PLATFORM_APPLE // posix_fallocate() is not supported on MacOS or iOS, so use a combination of fcntl(F_PREALLOCATE) and ftruncate(). @@ -783,7 +783,7 @@ void File::prealloc(size_t size) } -void File::prealloc_if_supported(SizeType offset, size_t size) +bool File::prealloc_if_supported(SizeType offset, size_t size) { REALM_ASSERT_RELEASE(is_attached()); @@ -791,34 +791,30 @@ void File::prealloc_if_supported(SizeType offset, size_t size) REALM_ASSERT_RELEASE(is_prealloc_supported()); - if (m_encryption_key) - size = data_size_to_encrypted_size(size); - - off_t size2; - if (int_cast_with_overflow_detect(size, size2)) - throw util::overflow_error("File size overflow"); - - if (size2 == 0) { + if (size == 0) { // calling posix_fallocate with a size of 0 will cause a return of EINVAL // since this is a meaningless operation anyway, we just return early here - return; + return true; } // posix_fallocate() does not set errno, it returns the error (if any) or zero. // It is also possible for it to be interrupted by EINTR according to some man pages (ex fedora 24) int status; do { - status = ::posix_fallocate(m_fd, offset, size2); + status = ::posix_fallocate(m_fd, offset, size); } while (status == EINTR); if (REALM_LIKELY(status == 0)) { - return; + return true; } if (status == ENOSPC || status == EDQUOT) { std::string msg = get_errno_msg("posix_fallocate() failed: ", status); throw OutOfDiskSpace(msg); } + if (status == EINVAL) { + return false; // Retry with non-atomic version + } throw std::system_error(status, std::system_category(), "posix_fallocate() failed"); // FIXME: OS X does not have any version of fallocate, but see diff --git a/src/realm/util/file.hpp b/src/realm/util/file.hpp index e23f57e1cd5..d1af65d58fd 100644 --- a/src/realm/util/file.hpp +++ b/src/realm/util/file.hpp @@ -300,7 +300,7 @@ class File { /// /// \sa prealloc() /// \sa is_prealloc_supported() - void prealloc_if_supported(SizeType offset, size_t size); + bool prealloc_if_supported(SizeType offset, size_t size); /// See prealloc_if_supported(). static bool is_prealloc_supported();