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 handling of work limit in online compaction #6245

Merged
merged 1 commit into from
Jan 27, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* Properties and types not present in the requested schema would be missing from the reported schema in several scenarios, such as if the Realm was being opened with a different schema version than the persisted one, and if the new tables or columns were added while the Realm instance did not have an active read transaction ([PR #6211](https://github.com/realm/realm-core/pull/6211), since v13.2.0).
* If a client reset w/recovery or discard local is interrupted while the "fresh" realm is being downloaded, the sync client may crash with a MultpleSyncAgents exception ([#6217](https://github.com/realm/realm-core/issues/6217), since v11.13.0)
* Changesets from the server sent during FLX bootstrapping that are larger than 16MB can cause the sync client to crash with a LogicError (PR [#6218](https://github.com/realm/realm-core/pull/6218), since v12.0.0)
* Online compaction may cause a single commit to take a long time ([#6245](https://github.com/realm/realm-core/pull/6245), since v13.0.0)

### Breaking changes
* `SyncSession::log_out()` has been renamed to `SyncSession::force_close()` to reflect what it actually does ([#6183](https://github.com/realm/realm-core/pull/6183))
Expand Down
4 changes: 2 additions & 2 deletions src/realm/db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2225,8 +2225,8 @@ void DB::low_level_commit(uint_fast64_t new_version, Transaction& transaction, b

if (auto limit = out.get_evacuation_limit()) {
// Get a work limit based on the size of the transaction we're about to commit
// Assume at least 4K on top of that for the top arrays
size_t work_limit = 4 * 1024 + m_alloc.get_commit_size() / 2;
// Add 4k to ensure progress on small commits
size_t work_limit = m_alloc.get_commit_size() / 2 + out.get_free_list_size() + 0x1000;
transaction.cow_outliers(out.get_evacuation_progress(), limit, work_limit);
}

Expand Down
6 changes: 2 additions & 4 deletions src/realm/group_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,10 +679,8 @@ ref_type GroupWriter::write_group()
// bigger databases the space required for free lists will be relatively less.
max_free_list_size += 10;

// If current size is less than 128 MB, the database need not expand above 2 GB
// which means that the positions and sizes can still be in 32 bit.
int size_per_entry = (m_logical_size < 0x8000000 ? 8 : 16) + 8;
size_t max_free_space_needed = Array::get_max_byte_size(top.size()) + size_per_entry * max_free_list_size;
size_t max_free_space_needed =
Array::get_max_byte_size(top.size()) + size_per_free_list_entry() * max_free_list_size;

ALLOC_DBG_COUT(" Allocating file space for freelists:" << std::endl);
// Reserve space for remaining arrays. We ask for some extra bytes beyond the
Expand Down
12 changes: 12 additions & 0 deletions src/realm/group_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ class GroupWriter : public _impl::ArrayWriterBase {
return m_backoff ? 0 : m_evacuation_limit;
}

size_t get_free_list_size()
{
return m_free_positions.size() * size_per_free_list_entry();
}

std::vector<size_t>& get_evacuation_progress()
{
return m_evacuation_progress;
Expand Down Expand Up @@ -254,6 +259,13 @@ class GroupWriter : public _impl::ArrayWriterBase {

/// Debug helper - extends the TopRefMap with list of reachable blocks
void map_reachable();

size_t size_per_free_list_entry() const
{
// If current size is less than 128 MB, the database need not expand above 2 GB
// which means that the positions and sizes can still be in 32 bit.
return (m_logical_size < 0x8000000 ? 8 : 16) + 8;
}
};


Expand Down
21 changes: 9 additions & 12 deletions src/realm/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -933,9 +933,9 @@ void Transaction::set_transact_stage(DB::TransactStage stage) noexcept

class NodeTree {
public:
NodeTree(size_t evac_limit, size_t& work_limit)
NodeTree(size_t evac_limit, size_t work_limit)
: m_evac_limit(evac_limit)
, m_work_limit(work_limit)
, m_work_limit(int64_t(work_limit))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we want to allow for a negative work limit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because then we can just subtract the sizes and just theck if the work_limit is not negative

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find that less intuitive than the original approach, but feel free to pick your poison.

, m_moved(0)
{
}
Expand All @@ -955,18 +955,15 @@ class NodeTree {
/// to point to the node we have just processed
bool trv(Array& current_node, unsigned level, std::vector<size_t>& progress)
{
if (m_work_limit < 0) {
return false;
}
if (current_node.is_read_only()) {
auto byte_size = current_node.get_byte_size();
size_t byte_size = current_node.get_byte_size();
if ((current_node.get_ref() + byte_size) > m_evac_limit) {
current_node.copy_on_write();
m_moved++;
if (m_work_limit > byte_size) {
m_work_limit -= byte_size;
}
else {
m_work_limit = 0;
return false;
}
m_work_limit -= byte_size;
}
}

Expand Down Expand Up @@ -998,12 +995,12 @@ class NodeTree {

private:
size_t m_evac_limit;
size_t m_work_limit;
int64_t m_work_limit;
size_t m_moved;
};


void Transaction::cow_outliers(std::vector<size_t>& progress, size_t evac_limit, size_t& work_limit)
void Transaction::cow_outliers(std::vector<size_t>& progress, size_t evac_limit, size_t work_limit)
{
NodeTree node_tree(evac_limit, work_limit);
if (progress.empty()) {
Expand Down
2 changes: 1 addition & 1 deletion src/realm/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class Transaction : public Group {
void complete_async_commit();
void acquire_write_lock() REQUIRES(!m_async_mutex);

void cow_outliers(std::vector<size_t>& progress, size_t evac_limit, size_t& work_limit);
void cow_outliers(std::vector<size_t>& progress, size_t evac_limit, size_t work_limit);
void close_read_with_lock() REQUIRES(!m_async_mutex, db->m_mutex);

DBRef db;
Expand Down