Skip to content

Commit 74189bf

Browse files
committed
[mpt] Separate fast and slow list compaction conditions in advance_compact_offsets(),
and scale slow-list compaction by gc_efficiency relative to disk growth Replace the fixed cap (min of growth+1 and gc_efficiency) with a formula that scales growth by gc_efficiency / breakeven. Above the breakeven (4), compaction outruns growth to reduce backlog; below it, compaction backs off when recirculation is heavy.
1 parent f89f504 commit 74189bf

File tree

1 file changed

+70
-66
lines changed

1 file changed

+70
-66
lines changed

category/mpt/update_aux.cpp

Lines changed: 70 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,7 @@ void UpdateAuxImpl::advance_compact_offsets(Node::SharedPtr const prev_root)
13991399
MONAD_ASSERT(is_on_disk());
14001400

14011401
constexpr double fast_usage_limit_start_compaction = 0.1;
1402-
constexpr unsigned fast_chunk_count_limit_start_compaction = 800;
1402+
constexpr size_t fast_chunk_count_limit_start_compaction = 800;
14031403
constexpr uint32_t max_compact_offset_range =
14041404
512; // 32MB, each unit of compact_virtual_chunk_offset_t represents
14051405
// 64KB
@@ -1423,16 +1423,6 @@ void UpdateAuxImpl::advance_compact_offsets(Node::SharedPtr const prev_root)
14231423
}
14241424
}
14251425

1426-
auto const fast_disk_usage =
1427-
num_chunks(chunk_list::fast) / (double)io->chunk_count();
1428-
uint64_t const max_version = db_history_max_version();
1429-
if ((fast_disk_usage < fast_usage_limit_start_compaction &&
1430-
num_chunks(chunk_list::fast) <
1431-
fast_chunk_count_limit_start_compaction) ||
1432-
max_version == INVALID_BLOCK_NUM) {
1433-
return;
1434-
}
1435-
14361426
MONAD_ASSERT(
14371427
compact_offsets.fast != INVALID_COMPACT_VIRTUAL_OFFSET &&
14381428
compact_offsets.slow != INVALID_COMPACT_VIRTUAL_OFFSET);
@@ -1441,74 +1431,88 @@ void UpdateAuxImpl::advance_compact_offsets(Node::SharedPtr const prev_root)
14411431
range of the latest version, so that fast-list usage adapts appropriately to
14421432
changes in history length. */
14431433
compact_offset_range_fast_ = MIN_COMPACT_VIRTUAL_OFFSET;
1434+
compact_offset_range_slow_ = MIN_COMPACT_VIRTUAL_OFFSET;
14441435

1445-
uint64_t const min_version = db_history_min_valid_version();
1446-
MONAD_ASSERT(min_version != INVALID_BLOCK_NUM);
1447-
compact_virtual_chunk_offset_t const curr_fast_writer_offset{
1448-
physical_to_virtual(node_writer_fast->sender().offset())};
1449-
// Estimate average fast-list disk growth per version. If the oldest root
1450-
// is on the fast list, compute from the full history range. Otherwise fall
1451-
// back to the last block's growth (e.g. roots from statesync may be on the
1452-
// slow list).
1453-
uint32_t avg_disk_growth_fast = last_block_disk_growth_fast_;
1454-
auto const min_version_root_virtual_offset =
1455-
physical_to_virtual(get_root_offset_at_version(min_version));
1456-
if (min_version_root_virtual_offset.in_fast_list() &&
1457-
max_version > min_version) {
1458-
avg_disk_growth_fast = divide_and_round(
1459-
curr_fast_writer_offset -
1460-
compact_virtual_chunk_offset_t{min_version_root_virtual_offset},
1461-
max_version - min_version);
1462-
}
1463-
// Only advance the fast-list compaction offset if the uncompacted range
1464-
// exceeds min_versions_of_growth_before_compact_fast_list (5000) versions'
1465-
// worth of growth, to prevent over-compaction when the history window
1466-
// shrinks.
1467-
uint32_t const latest_block_fast_uncompacted_range =
1468-
curr_fast_writer_offset - compact_offsets.fast;
1469-
if (latest_block_fast_uncompacted_range >
1470-
static_cast<uint64_t>(avg_disk_growth_fast) *
1471-
min_versions_of_growth_before_compact_fast_list) {
1472-
// Stride that would evenly spread the uncompacted range across the
1473-
// history window, keeping fast-list disk usage steady over time.
1474-
uint32_t const target_fast_compaction_stride = divide_and_round(
1475-
latest_block_fast_uncompacted_range, max_version - min_version + 1);
1476-
uint32_t to_advance = std::min(
1477-
target_fast_compaction_stride,
1478-
avg_disk_growth_fast + min_compaction_progress_buffer);
1479-
to_advance =
1480-
std::min(to_advance, max_compact_offset_range); // Cap at 32MB
1481-
compact_offset_range_fast_.set_value(to_advance);
1482-
compact_offsets.fast += compact_offset_range_fast_;
1436+
uint64_t const max_version = db_history_max_version();
1437+
if (max_version == INVALID_BLOCK_NUM) {
1438+
return;
14831439
}
1440+
1441+
// <-- Fast list compaction -->
1442+
auto const min_fast_chunks_to_start_compaction = std::min(
1443+
fast_chunk_count_limit_start_compaction,
1444+
static_cast<size_t>(
1445+
(double)io->chunk_count() * fast_usage_limit_start_compaction));
1446+
if (compact_offsets.fast < last_block_end_offset_fast_ &&
1447+
num_chunks(chunk_list::fast) >= min_fast_chunks_to_start_compaction) {
1448+
uint64_t const min_version = db_history_min_valid_version();
1449+
MONAD_ASSERT(min_version != INVALID_BLOCK_NUM);
1450+
compact_virtual_chunk_offset_t const curr_fast_writer_offset{
1451+
physical_to_virtual(node_writer_fast->sender().offset())};
1452+
// Estimate average fast-list disk growth per version. If the oldest
1453+
// root is on the fast list, compute from the full history range.
1454+
// Otherwise fall back to the last block's growth (e.g. roots from
1455+
// statesync may be on the slow list).
1456+
uint32_t avg_disk_growth_fast = last_block_disk_growth_fast_;
1457+
auto const min_version_root_virtual_offset =
1458+
physical_to_virtual(get_root_offset_at_version(min_version));
1459+
if (min_version_root_virtual_offset.in_fast_list() &&
1460+
max_version > min_version) {
1461+
avg_disk_growth_fast = divide_and_round(
1462+
curr_fast_writer_offset -
1463+
compact_virtual_chunk_offset_t{
1464+
min_version_root_virtual_offset},
1465+
max_version - min_version);
1466+
}
1467+
// Only advance the fast-list compaction offset if the uncompacted range
1468+
// exceeds min_versions_of_growth_before_compact_fast_list (5000)
1469+
// versions' worth of growth, to prevent over-compaction when the
1470+
// history window shrinks.
1471+
uint32_t const latest_block_fast_uncompacted_range =
1472+
curr_fast_writer_offset - compact_offsets.fast;
1473+
if (latest_block_fast_uncompacted_range >
1474+
static_cast<uint64_t>(avg_disk_growth_fast) *
1475+
min_versions_of_growth_before_compact_fast_list) {
1476+
// Stride that would evenly spread the uncompacted range across the
1477+
// history window, keeping fast-list disk usage steady over time.
1478+
uint32_t const target_fast_compaction_stride = divide_and_round(
1479+
latest_block_fast_uncompacted_range,
1480+
max_version - min_version + 1);
1481+
uint32_t to_advance = std::min(
1482+
target_fast_compaction_stride,
1483+
avg_disk_growth_fast + min_compaction_progress_buffer);
1484+
to_advance =
1485+
std::min(to_advance, max_compact_offset_range); // Cap at 32MB
1486+
compact_offset_range_fast_.set_value(to_advance);
1487+
compact_offsets.fast += compact_offset_range_fast_;
1488+
}
1489+
}
1490+
// <-- Slow list compaction -->
14841491
constexpr double usage_limit_start_compact_slow = 0.6;
14851492
constexpr double slow_usage_limit_start_compact_slow = 0.2;
1493+
constexpr uint32_t gc_efficiency_breakeven = 4;
1494+
14861495
double const slow_disk_usage =
14871496
num_chunks(chunk_list::slow) / (double)io->chunk_count();
1488-
double const total_disk_usage = fast_disk_usage + slow_disk_usage;
14891497
// Do not compact slow list until slow list usage and total usage are both
14901498
// above the thresholds
1491-
if (total_disk_usage > usage_limit_start_compact_slow &&
1499+
if (disk_usage() > usage_limit_start_compact_slow &&
14921500
slow_disk_usage > slow_usage_limit_start_compact_slow) {
1493-
// Compact slow ring: the offset is based on slow list garbage
1494-
// collection ratio of the last block. We use the ratio of compacted
1495-
// bytes to determine how aggressively to advance the compaction head.
1501+
// Compact slow ring at growth rate scaled by gc_efficiency.
1502+
// The breakeven point is 4, above which we compact faster than
1503+
// growth (reduce backlog), below 4 we compact slower (back off
1504+
// when recirculation is heavy).
1505+
uint32_t to_advance =
1506+
3; // No active data in last compaction, use minimum progress
14961507
if (last_block_slow_list_gc_efficiency_ > 0) {
1497-
// Cap at last block's growth + 1 to avoid advancing too fast
1498-
uint32_t const new_range = std::min(
1499-
static_cast<uint32_t>(last_block_disk_growth_slow_ + 1),
1500-
last_block_slow_list_gc_efficiency_);
1501-
compact_offset_range_slow_.set_value(new_range);
1502-
}
1503-
else {
1504-
// No valid data, use minimum progress
1505-
compact_offset_range_slow_.set_value(1);
1508+
to_advance = static_cast<uint32_t>(
1509+
static_cast<uint64_t>(last_block_disk_growth_slow_) *
1510+
last_block_slow_list_gc_efficiency_ / gc_efficiency_breakeven);
1511+
to_advance = std::min(to_advance, max_compact_offset_range);
15061512
}
1513+
compact_offset_range_slow_.set_value(to_advance);
15071514
compact_offsets.slow += compact_offset_range_slow_;
15081515
}
1509-
else {
1510-
compact_offset_range_slow_ = MIN_COMPACT_VIRTUAL_OFFSET;
1511-
}
15121516
}
15131517

15141518
uint64_t UpdateAuxImpl::version_history_max_possible() const noexcept

0 commit comments

Comments
 (0)