@@ -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
15141518uint64_t UpdateAuxImpl::version_history_max_possible () const noexcept
0 commit comments