1212#include < util/vector.h>
1313
1414#include < compare>
15+ #include < functional>
1516#include < memory>
1617#include < set>
1718#include < span>
@@ -120,9 +121,7 @@ class Cluster
120121public:
121122 Cluster () noexcept = delete ;
122123 /* * Construct an empty Cluster. */
123- explicit Cluster (uint64_t sequence) noexcept ;
124- /* * Construct a singleton Cluster. */
125- explicit Cluster (uint64_t sequence, TxGraphImpl& graph, const FeePerWeight& feerate, GraphIndex graph_index) noexcept ;
124+ explicit Cluster (uint64_t sequence) noexcept : m_sequence(sequence) {}
126125
127126 // Cannot move or copy (would invalidate Cluster* in Locator and ClusterSet). */
128127 Cluster (const Cluster&) = delete ;
@@ -153,15 +152,25 @@ class Cluster
153152 return m_quality == QualityLevel::NEEDS_SPLIT ||
154153 m_quality == QualityLevel::NEEDS_SPLIT_ACCEPTABLE;
155154 }
155+
156156 /* * Total memory usage currently for this Cluster, including all its dynamic memory, plus Cluster
157157 * structure itself, and ClusterSet::m_clusters entry. */
158158 size_t TotalMemoryUsage () const noexcept ;
159+ /* * Determine the range of DepGraphIndexes used by this Cluster. */
160+ DepGraphIndex GetDepGraphIndexRange () const noexcept { return m_depgraph.PositionRange (); }
159161 /* * Get the number of transactions in this Cluster. */
160162 LinearizationIndex GetTxCount () const noexcept { return m_linearization.size (); }
161163 /* * Get the total size of the transactions in this Cluster. */
162164 uint64_t GetTotalTxSize () const noexcept ;
163165 /* * Given a DepGraphIndex into this Cluster, find the corresponding GraphIndex. */
164166 GraphIndex GetClusterEntry (DepGraphIndex index) const noexcept { return m_mapping[index]; }
167+ /* * Append a transaction with given GraphIndex at the end of this Cluster and its
168+ * linearization. Return the DepGraphIndex it was placed at. */
169+ DepGraphIndex AppendTransaction (GraphIndex graph_idx, FeePerWeight feerate) noexcept ;
170+ /* * Add dependencies to a given child in this cluster. */
171+ void AddDependencies (SetType parents, DepGraphIndex child) noexcept ;
172+ /* * Invoke visitor_fn for each transaction in the cluster, in linearization order, then wipe this Cluster. */
173+ void ExtractTransactions (const std::function<void (DepGraphIndex, GraphIndex, FeePerWeight, SetType)>& visit_fn) noexcept ;
165174 /* * Figure out what level this Cluster exists at in the graph. In most cases this is known by
166175 * the caller already (see all "int level" arguments below), but not always. */
167176 int GetLevel (const TxGraphImpl& graph) const noexcept ;
@@ -186,7 +195,7 @@ class Cluster
186195 // Functions that implement the Cluster-specific side of internal TxGraphImpl mutations.
187196
188197 /* * Apply all removals from the front of to_remove that apply to this Cluster, popping them
189- * off. These must be at least one such entry. */
198+ * off. There must be at least one such entry. */
190199 void ApplyRemovals (TxGraphImpl& graph, int level, std::span<GraphIndex>& to_remove) noexcept ;
191200 /* * Split this cluster (must have a NEEDS_SPLIT* quality). Returns whether to delete this
192201 * Cluster afterwards. */
@@ -732,6 +741,31 @@ uint64_t Cluster::GetTotalTxSize() const noexcept
732741 return ret;
733742}
734743
744+ DepGraphIndex Cluster::AppendTransaction (GraphIndex graph_idx, FeePerWeight feerate) noexcept
745+ {
746+ Assume (graph_idx != GraphIndex (-1 ));
747+ auto ret = m_depgraph.AddTransaction (feerate);
748+ m_mapping.push_back (graph_idx);
749+ m_linearization.push_back (ret);
750+ return ret;
751+ }
752+
753+ void Cluster::AddDependencies (SetType parent, DepGraphIndex child) noexcept
754+ {
755+ m_depgraph.AddDependencies (parent, child);
756+ }
757+
758+ void Cluster::ExtractTransactions (const std::function<void (DepGraphIndex, GraphIndex, FeePerWeight, SetType)>& visit_fn) noexcept
759+ {
760+ for (auto pos : m_linearization) {
761+ visit_fn (pos, m_mapping[pos], FeePerWeight::FromFeeFrac (m_depgraph.FeeRate (pos)), m_depgraph.GetReducedParents (pos));
762+ }
763+ // Purge this Cluster, now that everything has been moved.
764+ m_depgraph = DepGraph<SetType>{};
765+ m_linearization.clear ();
766+ m_mapping.clear ();
767+ }
768+
735769int Cluster::GetLevel (const TxGraphImpl& graph) const noexcept
736770{
737771 // GetLevel() does not work for empty Clusters.
@@ -1072,12 +1106,7 @@ bool Cluster::Split(TxGraphImpl& graph, int level) noexcept
10721106 /* * The cluster which transaction originally in position i is moved to. */
10731107 Cluster* new_cluster = remap[i].first ;
10741108 // Copy the transaction to the new cluster's depgraph, and remember the position.
1075- remap[i].second = new_cluster->m_depgraph .AddTransaction (m_depgraph.FeeRate (i));
1076- // Create new mapping entry.
1077- new_cluster->m_mapping .push_back (m_mapping[i]);
1078- // Create a new linearization entry. As we're only appending transactions, they equal the
1079- // DepGraphIndex.
1080- new_cluster->m_linearization .push_back (remap[i].second );
1109+ remap[i].second = new_cluster->AppendTransaction (m_mapping[i], FeePerWeight::FromFeeFrac (m_depgraph.FeeRate (i)));
10811110 }
10821111 // Redistribute the dependencies.
10831112 for (auto i : m_linearization) {
@@ -1086,7 +1115,7 @@ bool Cluster::Split(TxGraphImpl& graph, int level) noexcept
10861115 // Copy its parents, translating positions.
10871116 SetType new_parents;
10881117 for (auto par : m_depgraph.GetReducedParents (i)) new_parents.Set (remap[par].second );
1089- new_cluster->m_depgraph . AddDependencies (new_parents, remap[i].second );
1118+ new_cluster->AddDependencies (new_parents, remap[i].second );
10901119 }
10911120 // Update all the Locators of moved transactions, and memory usage.
10921121 for (Cluster* new_cluster : new_clusters) {
@@ -1104,39 +1133,34 @@ bool Cluster::Split(TxGraphImpl& graph, int level) noexcept
11041133void Cluster::Merge (TxGraphImpl& graph, int level, Cluster& other) noexcept
11051134{
11061135 /* * Vector to store the positions in this Cluster for each position in other. */
1107- std::vector<DepGraphIndex> remap (other.m_depgraph . PositionRange ());
1136+ std::vector<DepGraphIndex> remap (other.GetDepGraphIndexRange ());
11081137 // Iterate over all transactions in the other Cluster (the one being absorbed).
1109- for (auto pos : other.m_linearization ) {
1110- auto idx = other.m_mapping [pos];
1138+ other.ExtractTransactions ([&](DepGraphIndex pos, GraphIndex idx, FeePerWeight feerate, SetType other_parents) noexcept {
11111139 // Copy the transaction into this Cluster, and remember its position.
1112- auto new_pos = m_depgraph.AddTransaction (other. m_depgraph . FeeRate (pos) );
1140+ auto new_pos = m_depgraph.AddTransaction (feerate );
11131141 // Since this cluster must have been made hole-free before being merged into, all added
11141142 // transactions should appear at the end.
11151143 Assume (new_pos == m_mapping.size ());
11161144 remap[pos] = new_pos;
11171145 m_mapping.push_back (idx);
11181146 m_linearization.push_back (new_pos);
11191147 // Copy the transaction's dependencies, translating them using remap. Note that since
1120- // pos iterates over other.m_linearization , which is in topological order , all parents
1121- // of pos should already be in remap.
1148+ // pos iterates in linearization order , which is topological, all parents of pos should
1149+ // already be in remap.
11221150 SetType parents;
1123- for (auto par : other. m_depgraph . GetReducedParents (pos) ) {
1151+ for (auto par : other_parents ) {
11241152 parents.Set (remap[par]);
11251153 }
11261154 m_depgraph.AddDependencies (parents, remap[pos]);
11271155 // Update the transaction's Locator. There is no need to call Updated() to update chunk
11281156 // feerates, as Updated() will be invoked by Cluster::ApplyDependencies on the resulting
1129- // merged Cluster later anyway) .
1157+ // merged Cluster later anyway.
11301158 auto & entry = graph.m_entries [idx];
11311159 // Discard any potential ChunkData prior to modifying the Cluster (as that could
11321160 // invalidate its ordering).
11331161 if (level == 0 ) graph.ClearChunkData (entry);
11341162 entry.m_locator [level].SetPresent (this , new_pos);
1135- }
1136- // Purge the other Cluster, now that everything has been moved.
1137- other.m_depgraph = DepGraph<SetType>{};
1138- other.m_linearization .clear ();
1139- other.m_mapping .clear ();
1163+ });
11401164}
11411165
11421166void Cluster::ApplyDependencies (TxGraphImpl& graph, int level, std::span<std::pair<GraphIndex, GraphIndex>> to_apply) noexcept
@@ -1766,17 +1790,6 @@ void TxGraphImpl::MakeAllAcceptable(int level) noexcept
17661790 }
17671791}
17681792
1769- Cluster::Cluster (uint64_t sequence) noexcept : m_sequence{sequence} {}
1770-
1771- Cluster::Cluster (uint64_t sequence, TxGraphImpl& graph, const FeePerWeight& feerate, GraphIndex graph_index) noexcept :
1772- m_sequence{sequence}
1773- {
1774- // Create a new transaction in the DepGraph, and remember its position in m_mapping.
1775- auto cluster_idx = m_depgraph.AddTransaction (feerate);
1776- m_mapping.push_back (graph_index);
1777- m_linearization.push_back (cluster_idx);
1778- }
1779-
17801793TxGraph::Ref TxGraphImpl::AddTransaction (const FeePerWeight& feerate) noexcept
17811794{
17821795 Assume (m_main_chunkindex_observers == 0 || GetTopLevel () != 0 );
@@ -1793,7 +1806,8 @@ TxGraph::Ref TxGraphImpl::AddTransaction(const FeePerWeight& feerate) noexcept
17931806 GetRefIndex (ret) = idx;
17941807 // Construct a new singleton Cluster (which is necessarily optimally linearized).
17951808 bool oversized = uint64_t (feerate.size ) > m_max_cluster_size;
1796- auto cluster = std::make_unique<Cluster>(m_next_sequence_counter++, *this , feerate, idx);
1809+ auto cluster = std::make_unique<Cluster>(m_next_sequence_counter++);
1810+ cluster->AppendTransaction (idx, feerate);
17971811 auto cluster_ptr = cluster.get ();
17981812 int level = GetTopLevel ();
17991813 auto & clusterset = GetClusterSet (level);
0 commit comments