mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-02-28 18:19:31 +01:00
clusterlin: inline UpdateChunk into (De)Activate (optimization)
The two calls to UpdateChunk, in Activate and Deactive each, are subtly different: the top one needs to update the chunk_idx of iterated transactions, while the bottom one leaves it unchanged. To exploit this difference, inline the four function calls, getting rid of UpdateChunks. This is also a preparation for a future improvement that inlines the recomputation of reachable sets in the same loop in Deactivate.
This commit is contained in:
committed by
Pieter Wuille
parent
b684f954bb
commit
d90f98ab4a
@@ -723,36 +723,6 @@ private:
|
||||
return TxIdx(-1);
|
||||
}
|
||||
|
||||
/** Update a chunk:
|
||||
* - All transactions have their chunk index set to `chunk_idx`.
|
||||
* - All dependencies which have `query` in their top set get `dep_change` added to it
|
||||
* (if `!Subtract`) or removed from it (if `Subtract`).
|
||||
*/
|
||||
template<bool Subtract>
|
||||
void UpdateChunk(const SetType& tx_idxs, TxIdx query, SetIdx chunk_idx, const SetInfo<SetType>& dep_change) noexcept
|
||||
{
|
||||
// Iterate over all the chunk's transactions.
|
||||
for (auto tx_idx : tx_idxs) {
|
||||
auto& tx_data = m_tx_data[tx_idx];
|
||||
// Update the chunk index for this transaction.
|
||||
tx_data.chunk_idx = chunk_idx;
|
||||
// Iterate over all active dependencies with tx_idx as parent. Combined with the outer
|
||||
// loop this iterates over all internal active dependencies of the chunk.
|
||||
for (auto child_idx : tx_data.active_children) {
|
||||
auto& top_set_info = m_set_info[tx_data.dep_top_idx[child_idx]];
|
||||
// If this dependency's top set contains query, update it to add/remove
|
||||
// dep_change.
|
||||
if (top_set_info.transactions[query]) {
|
||||
if constexpr (Subtract) {
|
||||
top_set_info -= dep_change;
|
||||
} else {
|
||||
top_set_info |= dep_change;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Find the set of out-of-chunk transactions reachable from tx_idxs, both in upwards and
|
||||
* downwards direction. */
|
||||
std::pair<SetType, SetType> GetReachable(const SetType& tx_idxs) const noexcept
|
||||
@@ -801,17 +771,26 @@ private:
|
||||
// dependency being activated (E->C here) in its top set, will have the opposite part added
|
||||
// to it. This is true for B->A and F->E, but not for C->A and F->D.
|
||||
//
|
||||
// Let UpdateChunk traverse the old parent chunk top_info (ABC in example), and add
|
||||
// bottom_info (DEF) to every dependency's top set which has the parent (C) in it. At the
|
||||
// same time, change the chunk_idx for each to be child_chunk_idx, which becomes the set for
|
||||
// the merged chunk.
|
||||
UpdateChunk<false>(/*tx_idxs=*/top_info.transactions, /*query=*/parent_idx,
|
||||
/*chunk_idx=*/child_chunk_idx, /*dep_change=*/bottom_info);
|
||||
// Let UpdateChunk traverse the old child chunk bottom_info (DEF in example), and add
|
||||
// top_info (ABC) to every dependency's top set which has the child (E) in it. The chunk
|
||||
// these are part of isn't being changed here (already child_chunk_idx for each).
|
||||
UpdateChunk<false>(/*tx_idxs=*/bottom_info.transactions, /*query=*/child_idx,
|
||||
/*chunk_idx=*/child_chunk_idx, /*dep_change=*/top_info);
|
||||
// Traverse the old parent chunk top_info (ABC in example), and add bottom_info (DEF) to
|
||||
// every dependency's top set which has the parent (C) in it. At the same time, change the
|
||||
// chunk_idx for each to be child_chunk_idx, which becomes the set for the merged chunk.
|
||||
for (auto tx_idx : top_info.transactions) {
|
||||
auto& tx_data = m_tx_data[tx_idx];
|
||||
tx_data.chunk_idx = child_chunk_idx;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// Traverse the old child chunk bottom_info (DEF in example), and add top_info (ABC) to
|
||||
// every dependency's top set which has the child (E) in it.
|
||||
for (auto tx_idx : bottom_info.transactions) {
|
||||
auto& tx_data = m_tx_data[tx_idx];
|
||||
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;
|
||||
}
|
||||
}
|
||||
// Merge top_info into bottom_info, which becomes the merged chunk.
|
||||
bottom_info |= top_info;
|
||||
m_cost += bottom_info.transactions.Count();
|
||||
@@ -856,10 +835,21 @@ private:
|
||||
bottom_info -= top_info;
|
||||
// See the comment above in Activate(). We perform the opposite operations here, removing
|
||||
// instead of adding.
|
||||
UpdateChunk<true>(/*tx_idxs=*/top_info.transactions, /*query=*/parent_idx,
|
||||
/*chunk_idx=*/parent_chunk_idx, /*dep_change=*/bottom_info);
|
||||
UpdateChunk<true>(/*tx_idxs=*/bottom_info.transactions, /*query=*/child_idx,
|
||||
/*chunk_idx=*/child_chunk_idx, /*dep_change=*/top_info);
|
||||
for (auto tx_idx : top_info.transactions) {
|
||||
auto& tx_data = m_tx_data[tx_idx];
|
||||
tx_data.chunk_idx = parent_chunk_idx;
|
||||
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;
|
||||
}
|
||||
}
|
||||
for (auto tx_idx : bottom_info.transactions) {
|
||||
auto& tx_data = m_tx_data[tx_idx];
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user