Skip to content

Commit 5901cf7

Browse files
committed
clusterlin: abstract out DepGraph::GetReduced{Parents,Children}
A fuzz test already relies on these operations, and a future commit will need the same logic too. Therefore, abstract them out into proper member functions, with proper testing.
1 parent 62e4516 commit 5901cf7

File tree

3 files changed

+90
-15
lines changed

3 files changed

+90
-15
lines changed

src/cluster_linearize.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,48 @@ class DepGraph
184184
}
185185
}
186186

187+
/** Compute the (reduced) set of parents of node i in this graph.
188+
*
189+
* This returns the minimal subset of the parents of i whose ancestors together equal all of
190+
* i's ancestors (unless i is part of a cycle of dependencies). Note that DepGraph does not
191+
* store the set of parents; this information is inferred from the ancestor sets.
192+
*
193+
* Complexity: O(N) where N=Ancestors(i).Count() (which is bounded by TxCount()).
194+
*/
195+
SetType GetReducedParents(ClusterIndex i) const noexcept
196+
{
197+
SetType parents = Ancestors(i);
198+
parents.Reset(i);
199+
for (auto parent : parents) {
200+
if (parents[parent]) {
201+
parents -= Ancestors(parent);
202+
parents.Set(parent);
203+
}
204+
}
205+
return parents;
206+
}
207+
208+
/** Compute the (reduced) set of children of node i in this graph.
209+
*
210+
* This returns the minimal subset of the children of i whose descendants together equal all of
211+
* i's descendants (unless i is part of a cycle of dependencies). Note that DepGraph does not
212+
* store the set of children; this information is inferred from the descendant sets.
213+
*
214+
* Complexity: O(N) where N=Descendants(i).Count() (which is bounded by TxCount()).
215+
*/
216+
SetType GetReducedChildren(ClusterIndex i) const noexcept
217+
{
218+
SetType children = Descendants(i);
219+
children.Reset(i);
220+
for (auto child : children) {
221+
if (children[child]) {
222+
children -= Descendants(child);
223+
children.Set(child);
224+
}
225+
}
226+
return children;
227+
}
228+
187229
/** Compute the aggregate feerate of a set of nodes in this graph.
188230
*
189231
* Complexity: O(N) where N=elems.Count().

src/test/fuzz/cluster_linearize.cpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -896,24 +896,12 @@ FUZZ_TARGET(clusterlin_postlinearize_tree)
896896
}
897897
if (direction & 1) {
898898
for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) {
899-
auto children = depgraph_gen.Descendants(i) - TestBitSet::Singleton(i);
900-
// Remove descendants that are children of other descendants.
901-
for (auto j : children) {
902-
if (!children[j]) continue;
903-
children -= depgraph_gen.Descendants(j);
904-
children.Set(j);
905-
}
899+
auto children = depgraph_gen.GetReducedChildren(i);
906900
if (children.Any()) depgraph_tree.AddDependency(i, children.First());
907901
}
908902
} else {
909903
for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) {
910-
auto parents = depgraph_gen.Ancestors(i) - TestBitSet::Singleton(i);
911-
// Remove ancestors that are parents of other ancestors.
912-
for (auto j : parents) {
913-
if (!parents[j]) continue;
914-
parents -= depgraph_gen.Ancestors(j);
915-
parents.Set(j);
916-
}
904+
auto parents = depgraph_gen.GetReducedParents(i);
917905
if (parents.Any()) depgraph_tree.AddDependency(parents.First(), i);
918906
}
919907
}

src/test/util/cluster_linearize.h

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,23 @@ void SanityCheck(const DepGraph<SetType>& depgraph)
264264
for (ClusterIndex j = 0; j < depgraph.TxCount(); ++j) {
265265
assert(depgraph.Ancestors(i)[j] == depgraph.Descendants(j)[i]);
266266
}
267+
// No transaction is a parent or child of itself.
268+
auto parents = depgraph.GetReducedParents(i);
269+
auto children = depgraph.GetReducedChildren(i);
270+
assert(!parents[i]);
271+
assert(!children[i]);
272+
// Parents of a transaction do not have ancestors inside those parents (except itself).
273+
// Note that even the transaction itself may be missing (if it is part of a cycle).
274+
for (auto parent : parents) {
275+
assert((depgraph.Ancestors(parent) & parents).IsSubsetOf(SetType::Singleton(parent)));
276+
}
277+
// Similar for children and descendants.
278+
for (auto child : children) {
279+
assert((depgraph.Descendants(child) & children).IsSubsetOf(SetType::Singleton(child)));
280+
}
267281
}
268-
// If DepGraph is acyclic, serialize + deserialize must roundtrip.
269282
if (IsAcyclic(depgraph)) {
283+
// If DepGraph is acyclic, serialize + deserialize must roundtrip.
270284
std::vector<unsigned char> ser;
271285
VectorWriter writer(ser, 0);
272286
writer << Using<DepGraphFormatter>(depgraph);
@@ -284,6 +298,37 @@ void SanityCheck(const DepGraph<SetType>& depgraph)
284298
reader >> Using<DepGraphFormatter>(decoded_depgraph);
285299
assert(depgraph == decoded_depgraph);
286300
assert(reader.empty());
301+
302+
// In acyclic graphs, the union of parents with parents of parents etc. yields the
303+
// full ancestor set (and similar for children and descendants).
304+
std::vector<SetType> parents, children;
305+
for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) {
306+
parents.push_back(depgraph.GetReducedParents(i));
307+
children.push_back(depgraph.GetReducedChildren(i));
308+
}
309+
for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) {
310+
// Initialize the set of ancestors with just the current transaction itself.
311+
SetType ancestors = SetType::Singleton(i);
312+
// Iteratively add parents of all transactions in the ancestor set to itself.
313+
while (true) {
314+
const auto old_ancestors = ancestors;
315+
for (auto j : ancestors) ancestors |= parents[j];
316+
// Stop when no more changes are being made.
317+
if (old_ancestors == ancestors) break;
318+
}
319+
assert(ancestors == depgraph.Ancestors(i));
320+
321+
// Initialize the set of descendants with just the current transaction itself.
322+
SetType descendants = SetType::Singleton(i);
323+
// Iteratively add children of all transactions in the descendant set to itself.
324+
while (true) {
325+
const auto old_descendants = descendants;
326+
for (auto j : descendants) descendants |= children[j];
327+
// Stop when no more changes are being made.
328+
if (old_descendants == descendants) break;
329+
}
330+
assert(descendants == depgraph.Descendants(i));
331+
}
287332
}
288333
}
289334

0 commit comments

Comments
 (0)