|
Packit |
14c646 |
#!./perl
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# We do all of the work in child processes here to ensure that any
|
|
Packit |
14c646 |
# memory used is released immediately.
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# These tests use ridiculous amounts of memory and CPU.
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
use strict;
|
|
Packit |
14c646 |
use warnings;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
use Config;
|
|
Packit |
14c646 |
use Storable qw(store_fd retrieve_fd nstore_fd);
|
|
Packit |
14c646 |
use Test::More;
|
|
Packit |
14c646 |
use File::Temp qw(tempfile);
|
|
Packit |
14c646 |
use File::Spec;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
BEGIN {
|
|
Packit |
14c646 |
plan skip_all => 'Storable was not built'
|
|
Packit |
14c646 |
if $ENV{PERL_CORE} && $Config{'extensions'} !~ /\b Storable \b/x;
|
|
Packit |
14c646 |
plan skip_all => 'Need 64-bit pointers for this test'
|
|
Packit |
14c646 |
if $Config{ptrsize} < 8 and $] > 5.013;
|
|
Packit |
14c646 |
plan skip_all => 'Need 64-bit int for this test on older versions'
|
|
Packit |
14c646 |
if $Config{uvsize} < 8 and $] < 5.013;
|
|
Packit |
14c646 |
plan skip_all => 'Need ~8 GiB memory for this test, set PERL_TEST_MEMORY >= 8'
|
|
Packit |
14c646 |
if !$ENV{PERL_TEST_MEMORY} || $ENV{PERL_TEST_MEMORY} < 8;
|
|
Packit |
14c646 |
plan skip_all => 'These tests are slow, set PERL_RUN_SLOW_TESTS'
|
|
Packit |
14c646 |
unless $ENV{PERL_RUN_SLOW_TESTS};
|
|
Packit |
14c646 |
plan skip_all => "Need fork for this test",
|
|
Packit |
14c646 |
unless $Config{d_fork};
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
find_exe("gzip")
|
|
Packit |
14c646 |
or plan skip_all => "Need gzip for this test";
|
|
Packit |
14c646 |
find_exe("gunzip")
|
|
Packit |
14c646 |
or plan skip_all => "Need gunzip for this test";
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
plan tests => 12;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
my $skips = $ENV{PERL_STORABLE_SKIP_ID_TEST} || '';
|
|
Packit |
14c646 |
my $keeps = $ENV{PERL_STORABLE_KEEP_ID_TEST};
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
freeze_thaw_test
|
|
Packit |
14c646 |
(
|
|
Packit |
14c646 |
name => "object ids between 2G and 4G",
|
|
Packit |
14c646 |
freeze => \&make_2g_data,
|
|
Packit |
14c646 |
thaw => \&check_2g_data,
|
|
Packit |
14c646 |
id => "2g",
|
|
Packit |
14c646 |
memory => 34,
|
|
Packit |
14c646 |
);
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
freeze_thaw_test
|
|
Packit |
14c646 |
(
|
|
Packit |
14c646 |
name => "object ids over 4G",
|
|
Packit |
14c646 |
freeze => \&make_4g_data,
|
|
Packit |
14c646 |
thaw => \&check_4g_data,
|
|
Packit |
14c646 |
id => "4g",
|
|
Packit |
14c646 |
memory => 70,
|
|
Packit |
14c646 |
);
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
freeze_thaw_test
|
|
Packit |
14c646 |
(
|
|
Packit |
14c646 |
name => "hook object ids over 4G",
|
|
Packit |
14c646 |
freeze => \&make_hook_data,
|
|
Packit |
14c646 |
thaw => \&check_hook_data,
|
|
Packit |
14c646 |
id => "hook4g",
|
|
Packit |
14c646 |
memory => 70,
|
|
Packit |
14c646 |
);
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# not really an id test, but the infrastructure here makes tests
|
|
Packit |
14c646 |
# easier
|
|
Packit |
14c646 |
freeze_thaw_test
|
|
Packit |
14c646 |
(
|
|
Packit |
14c646 |
name => "network store large PV",
|
|
Packit |
14c646 |
freeze => \&make_net_large_pv,
|
|
Packit |
14c646 |
thaw => \&check_net_large_pv,
|
|
Packit |
14c646 |
id => "netlargepv",
|
|
Packit |
14c646 |
memory => 8,
|
|
Packit |
14c646 |
);
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
freeze_thaw_test
|
|
Packit |
14c646 |
(
|
|
Packit |
14c646 |
name => "hook store with 2g data",
|
|
Packit |
14c646 |
freeze => \&make_2g_hook_data,
|
|
Packit |
14c646 |
thaw => \&check_2g_hook_data,
|
|
Packit |
14c646 |
id => "hook2gdata",
|
|
Packit |
14c646 |
memory => 4,
|
|
Packit |
14c646 |
);
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
freeze_thaw_test
|
|
Packit |
14c646 |
(
|
|
Packit |
14c646 |
name => "hook store with 4g data",
|
|
Packit |
14c646 |
freeze => \&make_4g_hook_data,
|
|
Packit |
14c646 |
thaw => \&check_4g_hook_data,
|
|
Packit |
14c646 |
id => "hook4gdata",
|
|
Packit |
14c646 |
memory => 8,
|
|
Packit |
14c646 |
);
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub freeze_thaw_test {
|
|
Packit |
14c646 |
my %opts = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
my $freeze = $opts{freeze}
|
|
Packit |
14c646 |
or die "Missing freeze";
|
|
Packit |
14c646 |
my $thaw = $opts{thaw}
|
|
Packit |
14c646 |
or die "Missing thaw";
|
|
Packit |
14c646 |
my $id = $opts{id}
|
|
Packit |
14c646 |
or die "Missing id";
|
|
Packit |
14c646 |
my $name = $opts{name}
|
|
Packit |
14c646 |
or die "Missing name";
|
|
Packit |
14c646 |
my $memory = $opts{memory}
|
|
Packit |
14c646 |
or die "Missing memory";
|
|
Packit |
14c646 |
my $todo_thaw = $opts{todo_thaw} || "";
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
SKIP:
|
|
Packit |
14c646 |
{
|
|
Packit |
14c646 |
# IPC::Run would be handy here
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
$ENV{PERL_TEST_MEMORY} >= $memory
|
|
Packit |
14c646 |
or skip "Not enough memory to test $name", 2;
|
|
Packit |
14c646 |
$skips =~ /\b\Q$id\E\b/
|
|
Packit |
14c646 |
and skip "You requested test $name ($id) be skipped", 2;
|
|
Packit |
14c646 |
defined $keeps && $keeps !~ /\b\Q$id\E\b/
|
|
Packit |
14c646 |
and skip "You didn't request test $name ($id)", 2;
|
|
Packit |
14c646 |
my $stored;
|
|
Packit |
14c646 |
if (defined(my $pid = open(my $fh, "-|"))) {
|
|
Packit |
14c646 |
unless ($pid) {
|
|
Packit |
14c646 |
# child
|
|
Packit |
14c646 |
open my $cfh, "|-", "gzip"
|
|
Packit |
14c646 |
or die "Cannot pipe to gzip: $!";
|
|
Packit |
14c646 |
binmode $cfh;
|
|
Packit |
14c646 |
$freeze->($cfh);
|
|
Packit |
14c646 |
exit;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
# parent
|
|
Packit |
14c646 |
$stored = do { local $/; <$fh> };
|
|
Packit |
14c646 |
close $fh;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
else {
|
|
Packit |
14c646 |
skip "$name: Cannot fork for freeze", 2;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
ok($stored, "$name: we got output data")
|
|
Packit |
14c646 |
or skip "$name: skipping thaw test", 1;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
my ($tfh, $tname) = tempfile();
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
#my $tname = "$id.store.gz";
|
|
Packit |
14c646 |
#open my $tfh, ">", $tname or die;
|
|
Packit |
14c646 |
#binmode $tfh;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
print $tfh $stored;
|
|
Packit |
14c646 |
close $tfh;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
if (defined(my $pid = open(my $fh, "-|"))) {
|
|
Packit |
14c646 |
unless ($pid) {
|
|
Packit |
14c646 |
# child
|
|
Packit |
14c646 |
open my $bfh, "-|", "gunzip <$tname"
|
|
Packit |
14c646 |
or die "Cannot pipe from gunzip: $!";
|
|
Packit |
14c646 |
binmode $bfh;
|
|
Packit |
14c646 |
$thaw->($bfh);
|
|
Packit |
14c646 |
exit;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
my $out = do { local $/; <$fh> };
|
|
Packit |
14c646 |
chomp $out;
|
|
Packit |
14c646 |
local $TODO = $todo_thaw;
|
|
Packit |
14c646 |
is($out, "OK", "$name: check result");
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
else {
|
|
Packit |
14c646 |
skip "$name: Cannot fork for thaw", 1;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub make_2g_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my @x;
|
|
Packit |
14c646 |
my $y = 1;
|
|
Packit |
14c646 |
my $z = 2;
|
|
Packit |
14c646 |
my $g2 = 0x80000000;
|
|
Packit |
14c646 |
$x[0] = \$y;
|
|
Packit |
14c646 |
$x[$g2] = \$y;
|
|
Packit |
14c646 |
$x[$g2+1] = \$z;
|
|
Packit |
14c646 |
$x[$g2+2] = \$z;
|
|
Packit |
14c646 |
store_fd(\@x, $fh);
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub check_2g_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my $x = retrieve_fd($fh);
|
|
Packit |
14c646 |
my $g2 = 0x80000000;
|
|
Packit |
14c646 |
$x->[0] == $x->[$g2]
|
|
Packit |
14c646 |
or die "First entry mismatch";
|
|
Packit |
14c646 |
$x->[$g2+1] == $x->[$g2+2]
|
|
Packit |
14c646 |
or die "2G+ entry mismatch";
|
|
Packit |
14c646 |
print "OK";
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub make_4g_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my @x;
|
|
Packit |
14c646 |
my $y = 1;
|
|
Packit |
14c646 |
my $z = 2;
|
|
Packit |
14c646 |
my $g4 = 2*0x80000000;
|
|
Packit |
14c646 |
$x[0] = \$y;
|
|
Packit |
14c646 |
$x[$g4] = \$y;
|
|
Packit |
14c646 |
$x[$g4+1] = \$z;
|
|
Packit |
14c646 |
$x[$g4+2] = \$z;
|
|
Packit |
14c646 |
store_fd(\@x, $fh);
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub check_4g_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my $x = retrieve_fd($fh);
|
|
Packit |
14c646 |
my $g4 = 2*0x80000000;
|
|
Packit |
14c646 |
$x->[0] == $x->[$g4]
|
|
Packit |
14c646 |
or die "First entry mismatch";
|
|
Packit |
14c646 |
$x->[$g4+1] == $x->[$g4+2]
|
|
Packit |
14c646 |
or die "4G+ entry mismatch";
|
|
Packit |
14c646 |
${$x->[$g4+1]} == 2
|
|
Packit |
14c646 |
or die "Incorrect value in 4G+ entry";
|
|
Packit |
14c646 |
print "OK";
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub make_hook_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my @x;
|
|
Packit |
14c646 |
my $y = HookLargeIds->new(101, { name => "one" });
|
|
Packit |
14c646 |
my $z = HookLargeIds->new(201, { name => "two" });
|
|
Packit |
14c646 |
my $g4 = 2*0x8000_0000;
|
|
Packit |
14c646 |
$x[0] = $y;
|
|
Packit |
14c646 |
$x[$g4] = $y;
|
|
Packit |
14c646 |
$x[$g4+1] = $z;
|
|
Packit |
14c646 |
$x[$g4+2] = $z;
|
|
Packit |
14c646 |
store_fd(\@x, $fh);
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub check_hook_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my $x = retrieve_fd($fh);
|
|
Packit |
14c646 |
my $g4 = 2*0x8000_0000;
|
|
Packit |
14c646 |
my $y = $x->[$g4+1];
|
|
Packit |
14c646 |
$y = $x->[$g4+1];
|
|
Packit |
14c646 |
$y->id == 201
|
|
Packit |
14c646 |
or die "Incorrect id in 4G+ object";
|
|
Packit |
14c646 |
ref($y->data) eq 'HASH'
|
|
Packit |
14c646 |
or die "data isn't a ref";
|
|
Packit |
14c646 |
$y->data->{name} eq "two"
|
|
Packit |
14c646 |
or die "data name not 'one'";
|
|
Packit |
14c646 |
print "OK";
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub make_net_large_pv {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my $x = "x"; # avoid constant folding making a 4G scalar
|
|
Packit |
14c646 |
my $g4 = 2*0x80000000;
|
|
Packit |
14c646 |
my $y = $x x ($g4 + 5);
|
|
Packit |
14c646 |
nstore_fd(\$y, $fh);
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub check_net_large_pv {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my $x = retrieve_fd($fh);
|
|
Packit |
14c646 |
my $g4 = 2*0x80000000;
|
|
Packit |
14c646 |
ref $x && ref($x) eq "SCALAR"
|
|
Packit |
14c646 |
or die "Not a scalar ref ", ref $x;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
length($$x) == $g4+5
|
|
Packit |
14c646 |
or die "Incorect length";
|
|
Packit |
14c646 |
print "OK";
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub make_2g_hook_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
my $g2 = 0x80000000;
|
|
Packit |
14c646 |
my $x = HookLargeData->new($g2);
|
|
Packit |
14c646 |
store_fd($x, $fh);
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub check_2g_hook_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my $x = retrieve_fd($fh);
|
|
Packit |
14c646 |
my $g2 = 0x80000000;
|
|
Packit |
14c646 |
$x->size == $g2
|
|
Packit |
14c646 |
or die "Size incorrect ", $x->size;
|
|
Packit |
14c646 |
print "OK";
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub make_4g_hook_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
my $g2 = 0x80000000;
|
|
Packit |
14c646 |
my $g4 = 2 * $g2;
|
|
Packit |
14c646 |
my $x = HookLargeData->new($g4+1);
|
|
Packit |
14c646 |
store_fd($x, $fh);
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub check_4g_hook_data {
|
|
Packit |
14c646 |
my ($fh) = @_;
|
|
Packit |
14c646 |
my $x = retrieve_fd($fh);
|
|
Packit |
14c646 |
my $g2 = 0x80000000;
|
|
Packit |
14c646 |
my $g4 = 2 * $g2;
|
|
Packit |
14c646 |
$x->size == $g4+1
|
|
Packit |
14c646 |
or die "Size incorrect ", $x->size;
|
|
Packit |
14c646 |
print "OK";
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub find_exe {
|
|
Packit |
14c646 |
my ($exe) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
$exe .= $Config{_exe};
|
|
Packit |
14c646 |
my @path = split /\Q$Config{path_sep}/, $ENV{PATH};
|
|
Packit |
14c646 |
for my $dir (@path) {
|
|
Packit |
14c646 |
my $abs = File::Spec->catfile($dir, $exe);
|
|
Packit |
14c646 |
-x $abs
|
|
Packit |
14c646 |
and return $abs;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package HookLargeIds;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub new {
|
|
Packit |
14c646 |
my $class = shift;
|
|
Packit |
14c646 |
my ($id, $data) = @_;
|
|
Packit |
14c646 |
return bless { id => $id, data => $data }, $class;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
#print STDERR "freeze called\n";
|
|
Packit |
14c646 |
#Devel::Peek::Dump($_[0]);
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
return $_[0]->id, $_[0]->data;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_thaw {
|
|
Packit |
14c646 |
my ($self, $cloning, $ser, $data) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
#Devel::Peek::Dump(\@_);
|
|
Packit |
14c646 |
#print STDERR "thaw called\n";
|
|
Packit |
14c646 |
#Devel::Peek::Dump($self);
|
|
Packit |
14c646 |
$self->{id} = $ser+0;
|
|
Packit |
14c646 |
$self->{data} = $data;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub id {
|
|
Packit |
14c646 |
$_[0]{id};
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub data {
|
|
Packit |
14c646 |
$_[0]{data};
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package HookLargeData;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub new {
|
|
Packit |
14c646 |
my ($class, $size) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
return bless { size => $size }, $class;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
return "x" x $_[0]{size};
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_thaw {
|
|
Packit |
14c646 |
my ($self, $cloning, $ser) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
$self->{size} = length $ser;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub size {
|
|
Packit |
14c646 |
$_[0]{size};
|
|
Packit |
14c646 |
}
|