Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix problem with posix_fallocate on AWS Lambda #3195

Merged
merged 2 commits into from
Dec 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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