Skip to content

Commit

Permalink
Merge pull request #3195 from realm/je/fix-fallocate-problem
Browse files Browse the repository at this point in the history
Fix problem with posix_fallocate on AWS Lambda
  • Loading branch information
jedelbo authored Dec 14, 2018
2 parents 8ba4288 + 07ad6c1 commit fb3faa8
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 24 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
* None.

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](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.
Expand Down
10 changes: 7 additions & 3 deletions src/realm/group_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
33 changes: 15 additions & 18 deletions src/realm/util/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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().

Expand Down Expand Up @@ -783,42 +783,38 @@ 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());

#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L // POSIX.1-2001 version

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
Expand All @@ -837,6 +833,7 @@ void File::prealloc_if_supported(SizeType offset, size_t size)
REALM_ASSERT_RELEASE(!is_prealloc_supported());

#endif
return false;
}


Expand Down
2 changes: 1 addition & 1 deletion src/realm/util/file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit fb3faa8

Please sign in to comment.