txgraph: Delay chunking while sub-acceptable (optimization)

Chunk-based information (primarily, chunk feerates) are never accessed without
first bringing the relevant Clusters to an "acceptable" quality level. Thus,
while operations are ongoing and Clusters are not acceptable, we can omit
computing the chunkings and chunk feerates for Clusters.
This commit is contained in:
Pieter Wuille 2024-11-15 13:31:23 -05:00
parent 57f5499882
commit 5801e0fb2b

View file

@ -331,23 +331,27 @@ void Cluster::Updated(TxGraphImpl& graph) noexcept
auto& entry = graph.m_entries[m_mapping[idx]]; auto& entry = graph.m_entries[m_mapping[idx]];
entry.m_locator.SetPresent(this, idx); entry.m_locator.SetPresent(this, idx);
} }
// If the Cluster's quality is ACCEPTABLE or OPTIMAL, compute its chunking and store its
// Compute its chunking and store its information in the Entry's m_chunk_feerate. // information in the Entry's m_chunk_feerate. These fields are only accessed after making
LinearizationChunking chunking(m_depgraph, m_linearization); // the entire graph ACCEPTABLE, so it is pointless to compute these if we haven't reached that
LinearizationIndex lin_idx{0}; // quality level yet.
// Iterate over the chunks. if (IsAcceptable()) {
for (unsigned chunk_idx = 0; chunk_idx < chunking.NumChunksLeft(); ++chunk_idx) { LinearizationChunking chunking(m_depgraph, m_linearization);
auto chunk = chunking.GetChunk(chunk_idx); LinearizationIndex lin_idx{0};
Assume(chunk.transactions.Any()); // Iterate over the chunks.
// Iterate over the transactions in the linearization, which must match those in chunk. for (unsigned chunk_idx = 0; chunk_idx < chunking.NumChunksLeft(); ++chunk_idx) {
do { auto chunk = chunking.GetChunk(chunk_idx);
DepGraphIndex idx = m_linearization[lin_idx++]; Assume(chunk.transactions.Any());
GraphIndex graph_idx = m_mapping[idx]; // Iterate over the transactions in the linearization, which must match those in chunk.
auto& entry = graph.m_entries[graph_idx]; do {
entry.m_chunk_feerate = FeePerWeight::FromFeeFrac(chunk.feerate); DepGraphIndex idx = m_linearization[lin_idx++];
Assume(chunk.transactions[idx]); GraphIndex graph_idx = m_mapping[idx];
chunk.transactions.Reset(idx); auto& entry = graph.m_entries[graph_idx];
} while(chunk.transactions.Any()); entry.m_chunk_feerate = FeePerWeight::FromFeeFrac(chunk.feerate);
Assume(chunk.transactions[idx]);
chunk.transactions.Reset(idx);
} while(chunk.transactions.Any());
}
} }
} }
@ -409,8 +413,6 @@ bool Cluster::Split(TxGraphImpl& graph) noexcept
// The existing Cluster is an entire component. Leave it be, but update its quality. // The existing Cluster is an entire component. Leave it be, but update its quality.
Assume(todo == m_depgraph.Positions()); Assume(todo == m_depgraph.Positions());
graph.SetClusterQuality(m_quality, m_setindex, QualityLevel::NEEDS_RELINEARIZE); graph.SetClusterQuality(m_quality, m_setindex, QualityLevel::NEEDS_RELINEARIZE);
// We need to recompute and cache its chunking.
Updated(graph);
return false; return false;
} }
first = false; first = false;
@ -1262,12 +1264,12 @@ void Cluster::SanityCheck(const TxGraphImpl& graph) const
assert(entry.m_locator.cluster == this); assert(entry.m_locator.cluster == this);
assert(entry.m_locator.index == lin_pos); assert(entry.m_locator.index == lin_pos);
// Check linearization position and chunk feerate. // Check linearization position and chunk feerate.
if (!linchunking.GetChunk(0).transactions[lin_pos]) {
linchunking.MarkDone(linchunking.GetChunk(0).transactions);
}
assert(entry.m_chunk_feerate == linchunking.GetChunk(0).feerate);
// If this Cluster has an acceptable quality level, its chunks must be connected.
if (IsAcceptable()) { if (IsAcceptable()) {
if (!linchunking.GetChunk(0).transactions[lin_pos]) {
linchunking.MarkDone(linchunking.GetChunk(0).transactions);
}
assert(entry.m_chunk_feerate == linchunking.GetChunk(0).feerate);
// If this Cluster has an acceptable quality level, its chunks must be connected.
assert(m_depgraph.IsConnected(linchunking.GetChunk(0).transactions)); assert(m_depgraph.IsConnected(linchunking.GetChunk(0).transactions));
} }
} }