txgraph: keep data structures compact (mem optimization)
What changed, and why it matters
This commit is a straightforward memory optimization for Bitcoin Core's internal transaction graph data structure. It adds a new Compact() method that trims excess capacity from vectors after clusters of transactions are modified, split, or merged. There is no security-relevant change here—only a reduction in memory usage.
No security action required. Treat as a normal performance/memory optimization patch.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces Cluster::Compact(), which calls shrink_to_fit() on m_linearization and m_mapping, plus DepGraph::Compact() on m_depgraph. It invokes Compact() after ApplyRemovals(), Split(), and TxGraphImpl::Merge(). These are all memory-footprint optimizations following structural mutations. No logic, validation, consensus, or authorization behavior is altered.
Changed components
src/txgraph.cppCluster::Compact()Cluster::ApplyRemovals()Cluster::Split()TxGraphImpl::Merge()Inspect captured patch +12 / −0
diff --git a/src/txgraph.cpp b/src/txgraph.cpp
index 4c4772ef..d730c397 100644
--- a/src/txgraph.cpp
+++ b/src/txgraph.cpp
@@ -177,6 +177,8 @@ public:
void Clear(TxGraphImpl& graph, int level) noexcept;
/** Change a Cluster's level from 1 (staging) to 0 (main). */
void MoveToMain(TxGraphImpl& graph) noexcept;
+ /** Minimize this Cluster's memory usage. */
+ void Compact() noexcept;
// Functions that implement the Cluster-specific side of internal TxGraphImpl mutations.
@@ -910,6 +912,7 @@ void Cluster::ApplyRemovals(TxGraphImpl& graph, int level, std::span<GraphIndex>
[&](auto pos) { return todo[pos]; }), m_linearization.end());
quality = QualityLevel::NEEDS_SPLIT;
}
+ Compact();
graph.SetClusterQuality(level, m_quality, m_setindex, quality);
Updated(graph, level);
}
@@ -937,6 +940,13 @@ void Cluster::MoveToMain(TxGraphImpl& graph) noexcept
Updated(graph, /*level=*/0);
}
+void Cluster::Compact() noexcept
+{
+ m_linearization.shrink_to_fit();
+ m_mapping.shrink_to_fit();
+ m_depgraph.Compact();
+}
+
void Cluster::AppendChunkFeerates(std::vector<FeeFrac>& ret) const noexcept
{
auto chunk_feerates = ChunkLinearization(m_depgraph, m_linearization);
@@ -1050,6 +1060,7 @@ bool Cluster::Split(TxGraphImpl& graph, int level) noexcept
// Update all the Locators of moved transactions.
for (Cluster* new_cluster : new_clusters) {
new_cluster->Updated(graph, level);
+ new_cluster->Compact();
}
// Wipe this Cluster, and return that it needs to be deleted.
m_depgraph = DepGraph<SetType>{};
@@ -1627,6 +1638,7 @@ void TxGraphImpl::Merge(std::span<Cluster*> to_merge, int level) noexcept
to_merge[0]->Merge(*this, level, *to_merge[i]);
DeleteCluster(*to_merge[i], level);
}
+ to_merge[0]->Compact();
}
void TxGraphImpl::ApplyDependencies(int level) noexcept
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.