@@ -165,6 +165,23 @@ std::pair<std::vector<ClusterIndex>, bool> SimpleLinearize(const DepGraph<SetTyp
165
165
return {std::move (linearization), optimal};
166
166
}
167
167
168
+ /* * Stitch connected components together in a DepGraph, guaranteeing its corresponding cluster is connected. */
169
+ template <typename BS>
170
+ void MakeConnected (DepGraph<BS>& depgraph)
171
+ {
172
+ auto todo = BS::Fill (depgraph.TxCount ());
173
+ auto comp = depgraph.FindConnectedComponent (todo);
174
+ Assume (depgraph.IsConnected (comp));
175
+ todo -= comp;
176
+ while (todo.Any ()) {
177
+ auto nextcomp = depgraph.FindConnectedComponent (todo);
178
+ Assume (depgraph.IsConnected (nextcomp));
179
+ depgraph.AddDependency (comp.Last (), nextcomp.First ());
180
+ todo -= nextcomp;
181
+ comp = nextcomp;
182
+ }
183
+ }
184
+
168
185
/* * Given a dependency graph, and a todo set, read a topological subset of todo from reader. */
169
186
template <typename SetType>
170
187
SetType ReadTopologicalSet (const DepGraph<SetType>& depgraph, const SetType& todo, SpanReader& reader)
@@ -369,6 +386,20 @@ FUZZ_TARGET(clusterlin_components)
369
386
assert (depgraph.FindConnectedComponent (todo).None ());
370
387
}
371
388
389
+ FUZZ_TARGET (clusterlin_make_connected)
390
+ {
391
+ // Verify that MakeConnected makes graphs connected.
392
+
393
+ SpanReader reader (buffer);
394
+ DepGraph<TestBitSet> depgraph;
395
+ try {
396
+ reader >> Using<DepGraphFormatter>(depgraph);
397
+ } catch (const std::ios_base::failure&) {}
398
+ MakeConnected (depgraph);
399
+ SanityCheck (depgraph);
400
+ assert (depgraph.IsConnected ());
401
+ }
402
+
372
403
FUZZ_TARGET (clusterlin_chunking)
373
404
{
374
405
// Verify the correctness of the ChunkLinearization function.
@@ -468,13 +499,17 @@ FUZZ_TARGET(clusterlin_search_finder)
468
499
// and comparing with the results from SimpleCandidateFinder, ExhaustiveCandidateFinder, and
469
500
// AncestorCandidateFinder.
470
501
471
- // Retrieve an RNG seed and a depgraph from the fuzz input.
502
+ // Retrieve an RNG seed, a depgraph, and whether to make it connected, from the fuzz input.
472
503
SpanReader reader (buffer);
473
504
DepGraph<TestBitSet> depgraph;
474
505
uint64_t rng_seed{0 };
506
+ uint8_t make_connected{1 };
475
507
try {
476
- reader >> Using<DepGraphFormatter>(depgraph) >> rng_seed;
508
+ reader >> Using<DepGraphFormatter>(depgraph) >> rng_seed >> make_connected ;
477
509
} catch (const std::ios_base::failure&) {}
510
+ // The most complicated graphs are connected ones (other ones just split up). Optionally force
511
+ // the graph to be connected.
512
+ if (make_connected) MakeConnected (depgraph);
478
513
479
514
// Instantiate ALL the candidate finders.
480
515
SearchCandidateFinder src_finder (depgraph, rng_seed);
@@ -513,9 +548,11 @@ FUZZ_TARGET(clusterlin_search_finder)
513
548
assert (found.transactions .IsSupersetOf (depgraph.Ancestors (i) & todo));
514
549
}
515
550
516
- // At most 2^N-1 iterations can be required: the number of non-empty subsets a graph with N
517
- // transactions has.
518
- assert (iterations_done <= ((uint64_t {1 } << todo.Count ()) - 1 ));
551
+ // At most 2^(N-1) iterations can be required: the maximum number of non-empty topological
552
+ // subsets a (connected) cluster with N transactions can have. Even when the cluster is no
553
+ // longer connected after removing certain transactions, this holds, because the connected
554
+ // components are searched separately.
555
+ assert (iterations_done <= (uint64_t {1 } << (todo.Count () - 1 )));
519
556
520
557
// Perform quality checks only if SearchCandidateFinder claims an optimal result.
521
558
if (iterations_done < max_iterations) {
@@ -685,14 +722,19 @@ FUZZ_TARGET(clusterlin_linearize)
685
722
{
686
723
// Verify the behavior of Linearize().
687
724
688
- // Retrieve an RNG seed, an iteration count, and a depgraph from the fuzz input.
725
+ // Retrieve an RNG seed, an iteration count, a depgraph, and whether to make it connected from
726
+ // the fuzz input.
689
727
SpanReader reader (buffer);
690
728
DepGraph<TestBitSet> depgraph;
691
729
uint64_t rng_seed{0 };
692
730
uint64_t iter_count{0 };
731
+ uint8_t make_connected{1 };
693
732
try {
694
- reader >> VARINT (iter_count) >> Using<DepGraphFormatter>(depgraph) >> rng_seed;
733
+ reader >> VARINT (iter_count) >> Using<DepGraphFormatter>(depgraph) >> rng_seed >> make_connected ;
695
734
} catch (const std::ios_base::failure&) {}
735
+ // The most complicated graphs are connected ones (other ones just split up). Optionally force
736
+ // the graph to be connected.
737
+ if (make_connected) MakeConnected (depgraph);
696
738
697
739
// Optionally construct an old linearization for it.
698
740
std::vector<ClusterIndex> old_linearization;
@@ -721,10 +763,10 @@ FUZZ_TARGET(clusterlin_linearize)
721
763
}
722
764
723
765
// If the iteration count is sufficiently high, an optimal linearization must be found.
724
- // Each linearization step can use up to 2^k iterations, with steps k=1..n. That sum is
725
- // 2 * (2 ^n - 1)
766
+ // Each linearization step can use up to 2^(k-1) iterations, with steps k=1..n. That sum is
767
+ // 2^n - 1.
726
768
const uint64_t n = depgraph.TxCount ();
727
- if (n <= 18 && iter_count > 2U * (( uint64_t {1 } << n) - 1U )) {
769
+ if (n <= 19 && iter_count > ( uint64_t {1 } << n)) {
728
770
assert (optimal);
729
771
}
730
772
0 commit comments