@@ -189,8 +189,9 @@ class Cluster
189
189
void Merge (TxGraphImpl& graph, Cluster& cluster) noexcept ;
190
190
/* * Given a span of (parent, child) pairs that all belong to this Cluster, apply them. */
191
191
void ApplyDependencies (TxGraphImpl& graph, std::span<std::pair<GraphIndex, GraphIndex>> to_apply) noexcept ;
192
- /* * Improve the linearization of this Cluster. Returns how much work was performed. */
193
- uint64_t Relinearize (TxGraphImpl& graph, uint64_t max_iters) noexcept ;
192
+ /* * Improve the linearization of this Cluster. Returns how much work was performed and whether
193
+ * the Cluster's QualityLevel improved as a result. */
194
+ std::pair<uint64_t , bool > Relinearize (TxGraphImpl& graph, uint64_t max_iters) noexcept ;
194
195
/* * For every chunk in the cluster, append its FeeFrac to ret. */
195
196
void AppendChunkFeerates (std::vector<FeeFrac>& ret) const noexcept ;
196
197
/* * Add a TrimTxData entry (filling m_chunk_feerate, m_index, m_tx_size) for every
@@ -592,7 +593,7 @@ class TxGraphImpl final : public TxGraph
592
593
void AddDependency (const Ref& parent, const Ref& child) noexcept final ;
593
594
void SetTransactionFee (const Ref&, int64_t fee) noexcept final ;
594
595
595
- void DoWork () noexcept final ;
596
+ bool DoWork (uint64_t iters ) noexcept final ;
596
597
597
598
void StartStaging () noexcept final ;
598
599
void CommitStaging () noexcept final ;
@@ -1655,12 +1656,12 @@ void TxGraphImpl::ApplyDependencies(int level) noexcept
1655
1656
clusterset.m_group_data = GroupData{};
1656
1657
}
1657
1658
1658
- uint64_t Cluster::Relinearize (TxGraphImpl& graph, uint64_t max_iters) noexcept
1659
+ std::pair< uint64_t , bool > Cluster::Relinearize (TxGraphImpl& graph, uint64_t max_iters) noexcept
1659
1660
{
1660
1661
// We can only relinearize Clusters that do not need splitting.
1661
1662
Assume (!NeedsSplitting ());
1662
1663
// No work is required for Clusters which are already optimally linearized.
1663
- if (IsOptimal ()) return 0 ;
1664
+ if (IsOptimal ()) return { 0 , false } ;
1664
1665
// Invoke the actual linearization algorithm (passing in the existing one).
1665
1666
uint64_t rng_seed = graph.m_rng .rand64 ();
1666
1667
auto [linearization, optimal, cost] = Linearize (m_depgraph, max_iters, rng_seed, m_linearization);
@@ -1670,11 +1671,17 @@ uint64_t Cluster::Relinearize(TxGraphImpl& graph, uint64_t max_iters) noexcept
1670
1671
// Update the linearization.
1671
1672
m_linearization = std::move (linearization);
1672
1673
// Update the Cluster's quality.
1673
- auto new_quality = optimal ? QualityLevel::OPTIMAL : QualityLevel::ACCEPTABLE;
1674
- graph.SetClusterQuality (m_level, m_quality, m_setindex, new_quality);
1674
+ bool improved = false ;
1675
+ if (optimal) {
1676
+ graph.SetClusterQuality (m_level, m_quality, m_setindex, QualityLevel::OPTIMAL);
1677
+ improved = true ;
1678
+ } else if (max_iters >= graph.m_acceptable_iters && !IsAcceptable ()) {
1679
+ graph.SetClusterQuality (m_level, m_quality, m_setindex, QualityLevel::ACCEPTABLE);
1680
+ improved = true ;
1681
+ }
1675
1682
// Update the Entry objects.
1676
1683
Updated (graph);
1677
- return cost;
1684
+ return { cost, improved} ;
1678
1685
}
1679
1686
1680
1687
void TxGraphImpl::MakeAcceptable (Cluster& cluster) noexcept
@@ -2478,13 +2485,50 @@ void TxGraphImpl::SanityCheck() const
2478
2485
assert (actual_chunkindex == expected_chunkindex);
2479
2486
}
2480
2487
2481
- void TxGraphImpl::DoWork () noexcept
2482
- {
2483
- for (int level = 0 ; level <= GetTopLevel (); ++level) {
2484
- if (level > 0 || m_main_chunkindex_observers == 0 ) {
2485
- MakeAllAcceptable (level);
2488
+ bool TxGraphImpl::DoWork (uint64_t iters) noexcept
2489
+ {
2490
+ uint64_t iters_done{0 };
2491
+ // First linearize everything in NEEDS_RELINEARIZE to an acceptable level. If more budget
2492
+ // remains after that, try to make everything optimal.
2493
+ for (QualityLevel quality : {QualityLevel::NEEDS_RELINEARIZE, QualityLevel::ACCEPTABLE}) {
2494
+ // First linearize staging, if it exists, then main.
2495
+ for (int level = GetTopLevel (); level >= 0 ; --level) {
2496
+ // Do not modify main if it has any observers.
2497
+ if (level == 0 && m_main_chunkindex_observers != 0 ) continue ;
2498
+ ApplyDependencies (level);
2499
+ auto & clusterset = GetClusterSet (level);
2500
+ // Do not modify oversized levels.
2501
+ if (clusterset.m_oversized == true ) continue ;
2502
+ auto & queue = clusterset.m_clusters [int (quality)];
2503
+ while (!queue.empty ()) {
2504
+ if (iters_done >= iters) return false ;
2505
+ // Randomize the order in which we process, so that if the first cluster somehow
2506
+ // needs more work than what iters allows, we don't keep spending it on the same
2507
+ // one.
2508
+ auto pos = m_rng.randrange <size_t >(queue.size ());
2509
+ auto iters_now = iters - iters_done;
2510
+ if (quality == QualityLevel::NEEDS_RELINEARIZE) {
2511
+ // If we're working with clusters that need relinearization still, only perform
2512
+ // up to m_acceptable_iters iterations. If they become ACCEPTABLE, and we still
2513
+ // have budget after all other clusters are ACCEPTABLE too, we'll spend the
2514
+ // remaining budget on trying to make them OPTIMAL.
2515
+ iters_now = std::min (iters_now, m_acceptable_iters);
2516
+ }
2517
+ auto [cost, improved] = queue[pos].get ()->Relinearize (*this , iters_now);
2518
+ iters_done += cost;
2519
+ // If no improvement was made to the Cluster, it means we've essentially run out of
2520
+ // budget. Even though it may be the case that iters_done < iters still, the
2521
+ // linearizer decided there wasn't enough budget left to attempt anything with.
2522
+ // To avoid an infinite loop that keeps trying clusters with minuscule budgets,
2523
+ // stop here too.
2524
+ if (!improved) return false ;
2525
+ }
2486
2526
}
2487
2527
}
2528
+ // All possible work has been performed, so we can return true. Note that this does *not* mean
2529
+ // that all clusters are optimally linearized now. It may be that there is nothing to do left
2530
+ // because all non-optimal clusters are in oversized and/or observer-bearing levels.
2531
+ return true ;
2488
2532
}
2489
2533
2490
2534
void BlockBuilderImpl::Next () noexcept
0 commit comments