Data-DisjointSet-Shared
view release on metacpan or search on metacpan
xt/fork_dsu.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use POSIX qw(_exit);
plan skip_all => 'author test' unless $ENV{AUTHOR_TESTING};
use Data::DisjointSet::Shared;
# An anonymous MAP_SHARED disjoint-set inherited across fork: each child chains
# its own disjoint band of elements into a single set, contending on the shared
# parent/size arrays under the rwlock. Because every union is performed while
# holding the write lock, the unions serialize and the final partition is
# DETERMINISTIC regardless of how the children interleave: each of the K bands
# collapses to exactly one set, so num_sets == K afterwards.
my $kids = 4;
my $N = 10_000;
my $band = $N / $kids; # 2500 elements per child (exact)
die "N must divide evenly by kids" if $N % $kids;
my $d = Data::DisjointSet::Shared->new(undef, $N);
my @pids;
for my $k (0 .. $kids - 1) {
my $pid = fork // die "fork: $!";
if (!$pid) {
my $base = $k * $band; # disjoint band [base, base+band)
# chain the whole band into one set: (base,base+1),(base+1,base+2),...
$d->union($base + $_, $base + $_ + 1) for 0 .. $band - 2;
_exit(0);
}
push @pids, $pid;
}
waitpid $_, 0 for @pids;
# K bands, each fully collapsed to one set -> exactly K disjoint sets remain.
is $d->num_sets, $kids,
sprintf('cross-process: num_sets == %d (each of %d bands collapsed to one set)', $kids, $kids);
# Within-band connectivity holds; across-band does not.
my $within_bad = 0;
for my $k (0 .. $kids - 1) {
my $base = $k * $band;
$within_bad++ unless $d->connected($base, $base + $band - 1); # band endpoints joined
$within_bad++ unless $d->set_size($base) == $band; # band set has 'band' members
}
is $within_bad, 0, 'cross-process: every band is fully connected with the expected size';
my $across_bad = 0;
for my $k (0 .. $kids - 2) {
my $a = $k * $band;
my $b = ($k + 1) * $band;
$across_bad++ if $d->connected($a, $b); # different bands stay disjoint
}
is $across_bad, 0, 'cross-process: distinct bands remain disjoint';
done_testing;
( run in 0.993 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )