Skip to content

Commit aded047

Browse files
committed
txgraph: Add CountDistinctClusters function (feature)
1 parent b685d32 commit aded047

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

src/test/fuzz/txgraph.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,50 @@ FUZZ_TARGET(txgraph)
526526
// these here without making more calls to real, which could affect its internal
527527
// state. A full comparison is done at the end.
528528
break;
529+
} else if (!sel_sim.IsOversized() && command-- == 0) {
530+
// CountDistinctClusters.
531+
std::vector<TxGraph::Ref*> refs;
532+
// Gather a list of up to 15 (or up to 255) Ref pointers.
533+
auto count = provider.ConsumeIntegralInRange<size_t>(0, alt ? 255 : 15);
534+
refs.resize(count);
535+
for (size_t i = 0; i < count; ++i) {
536+
refs[i] = pick_fn();
537+
}
538+
// Their order should not matter, shuffle them.
539+
std::shuffle(refs.begin(), refs.end(), rng);
540+
// Invoke the real function.
541+
auto result = real->CountDistinctClusters(refs, use_main);
542+
// Build a vector with representatives of the clusters the Refs occur in in the
543+
// simulated graph. For each, remember the lowest-index transaction SimPos in the
544+
// cluster.
545+
std::vector<DepGraphIndex> sim_reps;
546+
for (auto ref : refs) {
547+
// Skip Refs that do not occur in the simulated graph.
548+
auto simpos = sel_sim.Find(ref);
549+
if (simpos == SimTxGraph::MISSING) continue;
550+
// Start with component equal to just the Ref's SimPos.
551+
auto component = SimTxGraph::SetType::Singleton(simpos);
552+
// Keep adding ancestors/descendants of all elements in component until it no
553+
// longer changes.
554+
while (true) {
555+
auto old_component = component;
556+
for (auto i : component) {
557+
component |= sel_sim.graph.Ancestors(i);
558+
component |= sel_sim.graph.Descendants(i);
559+
}
560+
if (component == old_component) break;
561+
}
562+
// Remember the lowest-index SimPos in component, as a representative for it.
563+
assert(component.Any());
564+
sim_reps.push_back(component.First());
565+
}
566+
// Remove duplicates from sim_reps.
567+
std::sort(sim_reps.begin(), sim_reps.end());
568+
sim_reps.erase(std::unique(sim_reps.begin(), sim_reps.end()), sim_reps.end());
569+
// Compare the number of deduplicated representatives with the value returned by
570+
// the real function.
571+
assert(result == sim_reps.size());
572+
break;
529573
} else if (command-- == 0) {
530574
// DoWork.
531575
real->DoWork();

src/txgraph.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ class TxGraphImpl final : public TxGraph
454454
GraphIndex GetTransactionCount(bool main_only = false) noexcept final;
455455
bool IsOversized(bool main_only = false) noexcept final;
456456
std::strong_ordering CompareMainOrder(const Ref& a, const Ref& b) noexcept final;
457+
GraphIndex CountDistinctClusters(std::span<const Ref* const> refs, bool main_only = false) noexcept final;
457458

458459
void SanityCheck() const final;
459460
};
@@ -1781,6 +1782,33 @@ std::strong_ordering TxGraphImpl::CompareMainOrder(const Ref& a, const Ref& b) n
17811782
return entry_a.m_main_lin_index <=> entry_b.m_main_lin_index;
17821783
}
17831784

1785+
TxGraph::GraphIndex TxGraphImpl::CountDistinctClusters(std::span<const Ref* const> refs, bool main_only) noexcept
1786+
{
1787+
size_t level = GetSpecifiedLevel(main_only);
1788+
ApplyDependencies(level);
1789+
auto& clusterset = GetClusterSet(level);
1790+
Assume(clusterset.m_deps_to_add.empty());
1791+
// Build a vector of Clusters that the specified Refs occur in.
1792+
std::vector<Cluster*> clusters;
1793+
clusters.reserve(refs.size());
1794+
for (const Ref* ref : refs) {
1795+
if (ref == nullptr) continue;
1796+
if (GetRefGraph(*ref) == nullptr) continue;
1797+
Assume(GetRefGraph(*ref) == this);
1798+
auto cluster = FindCluster(GetRefIndex(*ref), level);
1799+
if (cluster != nullptr) clusters.push_back(cluster);
1800+
}
1801+
// Count the number of distinct elements in clusters.
1802+
std::sort(clusters.begin(), clusters.end());
1803+
Cluster* last{nullptr};
1804+
GraphIndex ret{0};
1805+
for (Cluster* cluster : clusters) {
1806+
ret += (cluster != last);
1807+
last = cluster;
1808+
}
1809+
return ret;
1810+
}
1811+
17841812
void Cluster::SanityCheck(const TxGraphImpl& graph, int level) const
17851813
{
17861814
// There must be an m_mapping for each m_depgraph position (including holes).

src/txgraph.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ class TxGraph
149149
/** Compare two transactions according to their order in the main graph. Both transactions must
150150
* be in the main graph. The main graph must not be oversized. */
151151
virtual std::strong_ordering CompareMainOrder(const Ref& a, const Ref& b) noexcept = 0;
152+
/** Count the number of distinct clusters that the specified transactions belong to. If
153+
* main_only is false and a staging graph exists, staging clusters are counted. Otherwise,
154+
* main clusters are counted. Refs that do not exist in the queried graph are ignored. The
155+
* queried graph must not be oversized. */
156+
virtual GraphIndex CountDistinctClusters(std::span<const Ref* const>, bool main_only = false) noexcept = 0;
152157

153158
/** Perform an internal consistency check on this object. */
154159
virtual void SanityCheck() const = 0;

0 commit comments

Comments
 (0)