@@ -189,8 +189,9 @@ class Cluster
189189 void Merge (TxGraphImpl& graph, Cluster& cluster) noexcept ;
190190 /* * Given a span of (parent, child) pairs that all belong to this Cluster, apply them. */
191191 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 ;
194195 /* * For every chunk in the cluster, append its FeeFrac to ret. */
195196 void AppendChunkFeerates (std::vector<FeeFrac>& ret) const noexcept ;
196197 /* * Add a TrimTxData entry (filling m_chunk_feerate, m_index, m_tx_size) for every
@@ -592,7 +593,7 @@ class TxGraphImpl final : public TxGraph
592593 void AddDependency (const Ref& parent, const Ref& child) noexcept final ;
593594 void SetTransactionFee (const Ref&, int64_t fee) noexcept final ;
594595
595- void DoWork () noexcept final ;
596+ bool DoWork (uint64_t iters ) noexcept final ;
596597
597598 void StartStaging () noexcept final ;
598599 void CommitStaging () noexcept final ;
@@ -1655,12 +1656,12 @@ void TxGraphImpl::ApplyDependencies(int level) noexcept
16551656 clusterset.m_group_data = GroupData{};
16561657}
16571658
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
16591660{
16601661 // We can only relinearize Clusters that do not need splitting.
16611662 Assume (!NeedsSplitting ());
16621663 // No work is required for Clusters which are already optimally linearized.
1663- if (IsOptimal ()) return 0 ;
1664+ if (IsOptimal ()) return { 0 , false } ;
16641665 // Invoke the actual linearization algorithm (passing in the existing one).
16651666 uint64_t rng_seed = graph.m_rng .rand64 ();
16661667 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
16701671 // Update the linearization.
16711672 m_linearization = std::move (linearization);
16721673 // 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+ }
16751682 // Update the Entry objects.
16761683 Updated (graph);
1677- return cost;
1684+ return { cost, improved} ;
16781685}
16791686
16801687void TxGraphImpl::MakeAcceptable (Cluster& cluster) noexcept
@@ -2478,13 +2485,50 @@ void TxGraphImpl::SanityCheck() const
24782485 assert (actual_chunkindex == expected_chunkindex);
24792486}
24802487
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+ }
24862526 }
24872527 }
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 ;
24882532}
24892533
24902534void BlockBuilderImpl::Next () noexcept
0 commit comments