From c2fcf250697325636218225d578c3844ab9ca633 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 26 Dec 2025 13:58:45 -0500 Subject: [PATCH] clusterlin: inline GetReachable into Deactivate (optimization) Avoid two full iterations over all of a chunks' transactions to recompute the reachable sets, by inlining them into the dependency-updating loops. Note that there is no need to do the same for Activate, because the reachable sets after merging can be computed directly from the input chunks' reachable sets. Deactivate needs to recompute them, however. --- src/cluster_linearize.h | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/cluster_linearize.h b/src/cluster_linearize.h index a53edf77282..1fe737a7e97 100644 --- a/src/cluster_linearize.h +++ b/src/cluster_linearize.h @@ -724,7 +724,8 @@ private: } /** Find the set of out-of-chunk transactions reachable from tx_idxs, both in upwards and - * downwards direction. */ + * downwards direction. Only used by SanityCheck to verify the precomputed reachable sets in + * m_reachable that are maintained by Activate/Deactivate. */ std::pair GetReachable(const SetType& tx_idxs) const noexcept { SetType parents, children; @@ -794,9 +795,8 @@ private: // Merge top_info into bottom_info, which becomes the merged chunk. bottom_info |= top_info; m_cost += bottom_info.transactions.Count(); - // Compute merged sets of reachable transactions from the new chunk. There is no need to - // call GetReachable here, because they can be computed directly from the input chunks' - // reachable sets. + // Compute merged sets of reachable transactions from the new chunk, based on the input + // chunks' reachable sets. m_reachable[child_chunk_idx].first |= m_reachable[parent_chunk_idx].first; m_reachable[child_chunk_idx].second |= m_reachable[parent_chunk_idx].second; m_reachable[child_chunk_idx].first -= bottom_info.transactions; @@ -834,25 +834,34 @@ private: // Subtract the top_info from the bottom_info, as it will become the child chunk. bottom_info -= top_info; // See the comment above in Activate(). We perform the opposite operations here, removing - // instead of adding. + // instead of adding. Simultaneously, aggregate the top/bottom's union of parents/children. + SetType top_parents, top_children; for (auto tx_idx : top_info.transactions) { auto& tx_data = m_tx_data[tx_idx]; tx_data.chunk_idx = parent_chunk_idx; + top_parents |= tx_data.parents; + top_children |= tx_data.children; for (auto dep_child_idx : tx_data.active_children) { auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]]; if (dep_top_info.transactions[parent_idx]) dep_top_info -= bottom_info; } } + SetType bottom_parents, bottom_children; for (auto tx_idx : bottom_info.transactions) { auto& tx_data = m_tx_data[tx_idx]; + bottom_parents |= tx_data.parents; + bottom_children |= tx_data.children; for (auto dep_child_idx : tx_data.active_children) { auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]]; if (dep_top_info.transactions[child_idx]) dep_top_info -= top_info; } } - // Compute the new sets of reachable transactions for each new chunk. - m_reachable[child_chunk_idx] = GetReachable(bottom_info.transactions); - m_reachable[parent_chunk_idx] = GetReachable(top_info.transactions); + // Compute the new sets of reachable transactions for each new chunk, based on the + // top/bottom parents and children computed above. + m_reachable[parent_chunk_idx].first = top_parents - top_info.transactions; + m_reachable[parent_chunk_idx].second = top_children - top_info.transactions; + m_reachable[child_chunk_idx].first = bottom_parents - bottom_info.transactions; + m_reachable[child_chunk_idx].second = bottom_children - bottom_info.transactions; // Return the two new set idxs. return {parent_chunk_idx, child_chunk_idx}; }