Skip to content

Commit 8673e8f

Browse files
committed
txgraph: Special-case singletons in chunk index (optimization)
1 parent abdd9d3 commit 8673e8f

File tree

1 file changed

+40
-11
lines changed

1 file changed

+40
-11
lines changed

src/txgraph.cpp

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ class TxGraphImpl final : public TxGraph
263263
{
264264
/** The Entry which is the last transaction of the chunk. */
265265
mutable GraphIndex m_graph_index;
266-
/** How many transactions the chunk contains. */
266+
/** How many transactions the chunk contains (-1 = singleton tail of cluster). */
267267
LinearizationIndex m_chunk_count;
268268

269269
ChunkData(GraphIndex graph_index, LinearizationIndex chunk_count) noexcept :
@@ -681,7 +681,7 @@ void Cluster::Updated(TxGraphImpl& graph) noexcept
681681
// Iterate over the chunks.
682682
for (unsigned chunk_idx = 0; chunk_idx < chunking.NumChunksLeft(); ++chunk_idx) {
683683
auto chunk = chunking.GetChunk(chunk_idx);
684-
const auto chunk_count = chunk.transactions.Count();
684+
auto chunk_count = chunk.transactions.Count();
685685
Assume(chunk_count > 0);
686686
// Iterate over the transactions in the linearization, which must match those in chunk.
687687
while (true) {
@@ -694,6 +694,12 @@ void Cluster::Updated(TxGraphImpl& graph) noexcept
694694
chunk.transactions.Reset(idx);
695695
if (chunk.transactions.None()) {
696696
// Last transaction in the chunk.
697+
if (chunk_count == 1 && chunk_idx + 1 == chunking.NumChunksLeft()) {
698+
// If this is the final chunk of the cluster, and it contains just a single
699+
// transaction (which will always be true for the very common singleton
700+
// clusters), store the special value -1 as chunk count.
701+
chunk_count = LinearizationIndex(-1);
702+
}
697703
graph.CreateChunkData(graph_idx, chunk_count);
698704
break;
699705
}
@@ -2152,7 +2158,11 @@ void Cluster::SanityCheck(const TxGraphImpl& graph, int level) const
21522158
assert((entry.m_main_chunkindex_iterator != graph.m_main_chunkindex.end()) == is_chunk_end);
21532159
if (is_chunk_end) {
21542160
auto& chunk_data = *entry.m_main_chunkindex_iterator;
2155-
assert(chunk_data.m_chunk_count == chunk_pos);
2161+
if (m_done == m_depgraph.Positions() && chunk_pos == 1) {
2162+
assert(chunk_data.m_chunk_count == LinearizationIndex(-1));
2163+
} else {
2164+
assert(chunk_data.m_chunk_count == chunk_pos);
2165+
}
21562166
}
21572167
// If this Cluster has an acceptable quality level, its chunks must be connected.
21582168
assert(m_depgraph.IsConnected(linchunking.GetChunk(0).transactions));
@@ -2357,10 +2367,22 @@ std::optional<std::pair<std::vector<TxGraph::Ref*>, FeePerWeight>> BlockBuilderI
23572367
ret.emplace();
23582368
const auto& chunk_data = *m_cur_iter;
23592369
const auto& chunk_end_entry = m_graph->m_entries[chunk_data.m_graph_index];
2360-
ret->first.resize(chunk_data.m_chunk_count);
2361-
auto start_pos = chunk_end_entry.m_main_lin_index + 1 - chunk_data.m_chunk_count;
2362-
Assume(m_cur_cluster);
2363-
m_known_end_of_cluster = m_cur_cluster->GetClusterRefs(*m_graph, ret->first, start_pos);
2370+
if (chunk_data.m_chunk_count == LinearizationIndex(-1)) {
2371+
// Special case in case just a single transaction remains, avoiding the need to
2372+
// dispatch to and dereference Cluster.
2373+
ret->first.resize(1);
2374+
Assume(chunk_end_entry.m_ref != nullptr);
2375+
ret->first[0] = chunk_end_entry.m_ref;
2376+
m_known_end_of_cluster = true;
2377+
} else {
2378+
Assume(m_cur_cluster);
2379+
ret->first.resize(chunk_data.m_chunk_count);
2380+
auto start_pos = chunk_end_entry.m_main_lin_index + 1 - chunk_data.m_chunk_count;
2381+
m_known_end_of_cluster = m_cur_cluster->GetClusterRefs(*m_graph, ret->first, start_pos);
2382+
// If the chunk size was 1 and at end of cluster, then the special case above should
2383+
// have been used.
2384+
Assume(!m_known_end_of_cluster || chunk_data.m_chunk_count > 1);
2385+
}
23642386
ret->second = chunk_end_entry.m_main_chunk_feerate;
23652387
}
23662388
return ret;
@@ -2428,10 +2450,17 @@ std::pair<std::vector<TxGraph::Ref*>, FeePerWeight> TxGraphImpl::GetWorstMainChu
24282450
const auto& chunk_data = *m_main_chunkindex.rbegin();
24292451
const auto& chunk_end_entry = m_entries[chunk_data.m_graph_index];
24302452
Cluster* cluster = chunk_end_entry.m_locator[0].cluster;
2431-
ret.first.resize(chunk_data.m_chunk_count);
2432-
auto start_pos = chunk_end_entry.m_main_lin_index + 1 - chunk_data.m_chunk_count;
2433-
cluster->GetClusterRefs(*this, ret.first, start_pos);
2434-
std::reverse(ret.first.begin(), ret.first.end());
2453+
if (chunk_data.m_chunk_count == LinearizationIndex(-1) || chunk_data.m_chunk_count == 1) {
2454+
// Special case for singletons.
2455+
ret.first.resize(1);
2456+
Assume(chunk_end_entry.m_ref != nullptr);
2457+
ret.first[0] = chunk_end_entry.m_ref;
2458+
} else {
2459+
ret.first.resize(chunk_data.m_chunk_count);
2460+
auto start_pos = chunk_end_entry.m_main_lin_index + 1 - chunk_data.m_chunk_count;
2461+
cluster->GetClusterRefs(*this, ret.first, start_pos);
2462+
std::reverse(ret.first.begin(), ret.first.end());
2463+
}
24352464
ret.second = chunk_end_entry.m_main_chunk_feerate;
24362465
}
24372466
return ret;

0 commit comments

Comments
 (0)