Blame t/hugeids.t

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
}