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/group_writer.cpp b/src/realm/group_writer.cpp index 0e1e9b4a2d7..055372a040a 100644 --- a/src/realm/group_writer.cpp +++ b/src/realm/group_writer.cpp @@ -207,6 +207,8 @@ GroupWriter::GroupWriter(Group& group) if (ref_type ref = m_free_lengths.get_ref_from_parent()) { m_free_lengths.init_from_ref(ref); + REALM_ASSERT_RELEASE_EX(m_free_positions.size() == m_free_lengths.size(), top.get_ref(), + m_free_positions.size(), m_free_lengths.size()); } else { m_free_lengths.create(Array::type_Normal); // Throws @@ -230,6 +232,8 @@ GroupWriter::GroupWriter(Group& group) if (ref_type ref = m_free_versions.get_ref_from_parent()) { m_free_versions.init_from_ref(ref); + REALM_ASSERT_RELEASE_EX(m_free_versions.size() == m_free_lengths.size(), top.get_ref(), + m_free_versions.size(), m_free_lengths.size()); } else { int_fast64_t value = int_fast64_t(initial_version); // FIXME: Problematic unsigned -> signed conversion @@ -515,10 +519,10 @@ ref_type GroupWriter::write_group() void GroupWriter::read_in_freelist() { bool is_shared = m_group.m_is_shared; - REALM_ASSERT_3(m_free_positions.size(), ==, m_free_lengths.size()); - REALM_ASSERT(!is_shared || m_free_versions.size() == m_free_lengths.size()); - size_t limit = m_free_lengths.size(); + REALM_ASSERT_RELEASE_EX(m_free_positions.size() == limit, limit, m_free_positions.size()); + REALM_ASSERT_RELEASE_EX(!is_shared || m_free_versions.size() == limit, limit, m_free_versions.size()); + if (limit) { auto limit_version = is_shared ? m_readlock_version : 0; for (size_t idx = 0; idx < limit; ++idx) { diff --git a/src/realm/util/file.cpp b/src/realm/util/file.cpp index fccaa188cef..162f7de5eab 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 @@ -837,6 +833,7 @@ void File::prealloc_if_supported(SizeType offset, size_t size) REALM_ASSERT_RELEASE(!is_prealloc_supported()); #endif + return false; } 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();