clusterlin: split up OptimizeStep (refactor)
This commit is contained in:
1 parent
cbd684a471
commit
dcf458ffb9
1 file changed
+60
-42
+60
-42
@@ -974,6 +974,54 @@ private:
|
|||||||
MergeSequence<true>(child_idx);
|
MergeSequence<true>(child_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Determine the next chunk to optimize, or INVALID_SET_IDX if none. */
|
||||||
|
SetIdx PickChunkToOptimize() noexcept
|
||||||
|
{
|
||||||
|
while (!m_suboptimal_chunks.empty()) {
|
||||||
|
// Pop an entry from the potentially-suboptimal chunk queue.
|
||||||
|
SetIdx chunk_idx = m_suboptimal_chunks.front();
|
||||||
|
m_suboptimal_chunks.pop_front();
|
||||||
|
if (m_chunk_idxs[chunk_idx]) return chunk_idx;
|
||||||
|
// If what was popped is not currently a chunk, continue. This may
|
||||||
|
// happen when a split chunk merges in Improve() with one or more existing chunks that
|
||||||
|
// are themselves on the suboptimal queue already.
|
||||||
|
}
|
||||||
|
return INVALID_SET_IDX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Find a (parent, child) dependency to deactivate in chunk_idx, or (-1, -1) if none. */
|
||||||
|
std::pair<TxIdx, TxIdx> PickDependencyToSplit(SetIdx chunk_idx) noexcept
|
||||||
|
{
|
||||||
|
Assume(m_chunk_idxs[chunk_idx]);
|
||||||
|
auto& chunk_info = m_set_info[chunk_idx];
|
||||||
|
|
||||||
|
// Remember the best dependency {par, chl} seen so far.
|
||||||
|
std::pair<TxIdx, TxIdx> candidate_dep = {TxIdx(-1), TxIdx(-1)};
|
||||||
|
uint64_t candidate_tiebreak = 0;
|
||||||
|
// Iterate over all transactions.
|
||||||
|
for (auto tx_idx : chunk_info.transactions) {
|
||||||
|
const auto& tx_data = m_tx_data[tx_idx];
|
||||||
|
// Iterate over all active child dependencies of the transaction.
|
||||||
|
for (auto child_idx : tx_data.children) {
|
||||||
|
if (tx_data.dep_top_idx[child_idx] == INVALID_SET_IDX) continue;
|
||||||
|
auto& dep_top_info = m_set_info[tx_data.dep_top_idx[child_idx]];
|
||||||
|
// Skip if this dependency is ineligible (the top chunk that would be created
|
||||||
|
// does not have higher feerate than the chunk it is currently part of).
|
||||||
|
auto cmp = FeeRateCompare(dep_top_info.feerate, chunk_info.feerate);
|
||||||
|
if (cmp <= 0) continue;
|
||||||
|
// Generate a random tiebreak for this dependency, and reject it if its tiebreak
|
||||||
|
// is worse than the best so far. This means that among all eligible
|
||||||
|
// dependencies, a uniformly random one will be chosen.
|
||||||
|
uint64_t tiebreak = m_rng.rand64();
|
||||||
|
if (tiebreak < candidate_tiebreak) continue;
|
||||||
|
// Remember this as our (new) candidate dependency.
|
||||||
|
candidate_dep = {tx_idx, child_idx};
|
||||||
|
candidate_tiebreak = tiebreak;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidate_dep;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Construct a spanning forest for the given DepGraph, with every transaction in its own chunk
|
/** Construct a spanning forest for the given DepGraph, with every transaction in its own chunk
|
||||||
* (not topological). */
|
* (not topological). */
|
||||||
@@ -1077,50 +1125,20 @@ public:
|
|||||||
/** Try to improve the forest. Returns false if it is optimal, true otherwise. */
|
/** Try to improve the forest. Returns false if it is optimal, true otherwise. */
|
||||||
bool OptimizeStep() noexcept
|
bool OptimizeStep() noexcept
|
||||||
{
|
{
|
||||||
while (!m_suboptimal_chunks.empty()) {
|
auto chunk_idx = PickChunkToOptimize();
|
||||||
// Pop an entry from the potentially-suboptimal chunk queue.
|
if (chunk_idx == INVALID_SET_IDX) {
|
||||||
SetIdx chunk_idx = m_suboptimal_chunks.front();
|
// No improvable chunk was found, we are done.
|
||||||
m_suboptimal_chunks.pop_front();
|
return false;
|
||||||
auto& chunk_info = m_set_info[chunk_idx];
|
}
|
||||||
// If what was popped is not currently a chunk, continue. This may
|
auto [parent_idx, child_idx] = PickDependencyToSplit(chunk_idx);
|
||||||
// happen when a split chunk merges in Improve() with one or more existing chunks that
|
if (parent_idx == TxIdx(-1)) {
|
||||||
// are themselves on the suboptimal queue already.
|
// Nothing to improve in chunk_idx. Need to continue with other chunks, if any.
|
||||||
if (!m_chunk_idxs[chunk_idx]) continue;
|
|
||||||
// Remember the best dependency {par, chl} seen so far.
|
|
||||||
std::pair<TxIdx, TxIdx> candidate_dep = {TxIdx(-1), TxIdx(-1)};
|
|
||||||
uint64_t candidate_tiebreak = 0;
|
|
||||||
// Iterate over all transactions.
|
|
||||||
for (auto tx_idx : chunk_info.transactions) {
|
|
||||||
const auto& tx_data = m_tx_data[tx_idx];
|
|
||||||
// Iterate over all active child dependencies of the transaction.
|
|
||||||
for (auto child_idx : tx_data.children) {
|
|
||||||
if (tx_data.dep_top_idx[child_idx] == INVALID_SET_IDX) continue;
|
|
||||||
auto& dep_top_info = m_set_info[tx_data.dep_top_idx[child_idx]];
|
|
||||||
// Skip if this dependency is ineligible (the top chunk that would be created
|
|
||||||
// does not have higher feerate than the chunk it is currently part of).
|
|
||||||
auto cmp = FeeRateCompare(dep_top_info.feerate, chunk_info.feerate);
|
|
||||||
if (cmp <= 0) continue;
|
|
||||||
// Generate a random tiebreak for this dependency, and reject it if its tiebreak
|
|
||||||
// is worse than the best so far. This means that among all eligible
|
|
||||||
// dependencies, a uniformly random one will be chosen.
|
|
||||||
uint64_t tiebreak = m_rng.rand64();
|
|
||||||
if (tiebreak < candidate_tiebreak) continue;
|
|
||||||
// Remember this as our (new) candidate dependency.
|
|
||||||
candidate_dep = {tx_idx, child_idx};
|
|
||||||
candidate_tiebreak = tiebreak;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If a candidate with positive gain was found, deactivate it and then make the state
|
|
||||||
// topological again with a sequence of merges.
|
|
||||||
if (candidate_dep.first != TxIdx(-1)) {
|
|
||||||
Improve(candidate_dep.first, candidate_dep.second);
|
|
||||||
}
|
|
||||||
// Stop processing for now, even if nothing was activated, as the loop above may have
|
|
||||||
// had a nontrivial cost.
|
|
||||||
return !m_suboptimal_chunks.empty();
|
return !m_suboptimal_chunks.empty();
|
||||||
}
|
}
|
||||||
// No improvable chunk was found, we are done.
|
// Deactivate the found dependency and then make the state topological again with a
|
||||||
return false;
|
// sequence of merges.
|
||||||
|
Improve(parent_idx, child_idx);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initialize data structure for minimizing the chunks. Can only be called if state is known
|
/** Initialize data structure for minimizing the chunks. Can only be called if state is known
|
||||||
|
|||||||
Reference in new issue
Block a user