|
Packit |
4e8bc4 |
#!/usr/bin/perl
|
|
Packit |
4e8bc4 |
# Test the "Error on get" path for extstore.
|
|
Packit |
4e8bc4 |
# the entire error handling code for process_get_command() never worked, and
|
|
Packit |
4e8bc4 |
# would infinite loop. get_extstore() can hit it sometimes.
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
use strict;
|
|
Packit |
4e8bc4 |
use warnings;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
use Test::More;
|
|
Packit |
4e8bc4 |
use FindBin qw($Bin);
|
|
Packit |
4e8bc4 |
use lib "$Bin/lib";
|
|
Packit |
4e8bc4 |
use MemcachedTest;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
my $ext_path;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (!supports_extstore()) {
|
|
Packit |
4e8bc4 |
plan skip_all => 'extstore not enabled';
|
|
Packit |
4e8bc4 |
exit 0;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
$ext_path = "/tmp/extstore.$$";
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
my $server = new_memcached("-m 64 -I 4m -U 0 -o ext_page_size=8,ext_wbuf_size=8,ext_threads=1,ext_io_depth=2,ext_item_size=512,ext_item_age=2,ext_recache_rate=10000,ext_max_frag=0.9,ext_path=$ext_path:64m,slab_automove=0,ext_compact_under=1");
|
|
Packit |
4e8bc4 |
my $sock = $server->sock;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
# Wait until all items have flushed
|
|
Packit |
4e8bc4 |
sub wait_for_ext {
|
|
Packit |
4e8bc4 |
my $sum = 1;
|
|
Packit |
4e8bc4 |
while ($sum != 0) {
|
|
Packit |
4e8bc4 |
my $s = mem_stats($sock, "items");
|
|
Packit |
4e8bc4 |
$sum = 0;
|
|
Packit |
4e8bc4 |
for my $key (keys %$s) {
|
|
Packit |
4e8bc4 |
if ($key =~ m/items:(\d+):number/) {
|
|
Packit |
4e8bc4 |
# Ignore classes which can contain extstore items
|
|
Packit |
4e8bc4 |
next if $1 < 3;
|
|
Packit |
4e8bc4 |
$sum += $s->{$key};
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
sleep 1 if $sum != 0;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
# We're testing to ensure item chaining doesn't corrupt or poorly overlap
|
|
Packit |
4e8bc4 |
# data, so create a non-repeating pattern.
|
|
Packit |
4e8bc4 |
my @parts = ();
|
|
Packit |
4e8bc4 |
for (1 .. 8000) {
|
|
Packit |
4e8bc4 |
push(@parts, $_);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
my $pattern = join(':', @parts);
|
|
Packit |
4e8bc4 |
my $plen = length($pattern);
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
# Set some large items and let them flush to extstore.
|
|
Packit |
4e8bc4 |
for (1..5) {
|
|
Packit |
4e8bc4 |
my $size = 3000 * 1024;
|
|
Packit |
4e8bc4 |
my $data = "x" x $size;
|
|
Packit |
4e8bc4 |
print $sock "set foo$_ 0 0 $size\r\n$data\r\n";
|
|
Packit |
4e8bc4 |
my $res = <$sock>;
|
|
Packit |
4e8bc4 |
is($res, "STORED\r\n", "stored some big items");
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
wait_for_ext();
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
my $long_key = "f" x 512;
|
|
Packit |
4e8bc4 |
print $sock "get foo1 foo2 foo3 $long_key\r\n";
|
|
Packit |
4e8bc4 |
ok(scalar <$sock> =~ /CLIENT_ERROR bad command line format/, 'long key fails');
|
|
Packit |
4e8bc4 |
my $stats = mem_stats($sock);
|
|
Packit |
4e8bc4 |
cmp_ok($stats->{get_aborted_extstore}, '>', 1, 'some extstore queries aborted');
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
# Disable automatic page balancing, then move enough pages that the large
|
|
Packit |
4e8bc4 |
# items can no longer be loaded from extstore
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
print $sock "slabs automove 0\r\n";
|
|
Packit |
4e8bc4 |
my $res = <$sock>;
|
|
Packit |
4e8bc4 |
my $source = 0;
|
|
Packit |
4e8bc4 |
while (1) {
|
|
Packit |
4e8bc4 |
print $sock "slabs reassign $source 1\r\n";
|
|
Packit |
4e8bc4 |
$res = <$sock>;
|
|
Packit |
4e8bc4 |
if ($res =~ m/NOSPARE/) {
|
|
Packit |
4e8bc4 |
$source = -1;
|
|
Packit |
4e8bc4 |
my $stats = mem_stats($sock, 'slabs');
|
|
Packit |
4e8bc4 |
for my $key (grep { /total_pages/ } keys %$stats) {
|
|
Packit |
4e8bc4 |
if ($key =~ m/(\d+):total_pages/) {
|
|
Packit |
4e8bc4 |
next if $1 < 3;
|
|
Packit |
4e8bc4 |
$source = $1 if $stats->{$key} > 1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
last if $source == -1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
select undef, undef, undef, 0.10;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
# fetching the large keys should now fail.
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
print $sock "get foo1\r\n";
|
|
Packit |
4e8bc4 |
my $res = <$sock>;
|
|
Packit |
4e8bc4 |
$res =~ s/[\r\n]//g;
|
|
Packit |
4e8bc4 |
is($res, 'SERVER_ERROR out of memory writing get response', 'can no longer read back item');
|
|
Packit |
4e8bc4 |
my $stats = mem_stats($sock);
|
|
Packit |
4e8bc4 |
is($stats->{get_oom_extstore}, 1, 'check extstore oom counter');
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
# Leaving this for future generations.
|
|
Packit |
4e8bc4 |
# The process_get_command() function had several memory leaks.
|
|
Packit |
4e8bc4 |
my $LEAK_TEST = 0;
|
|
Packit |
4e8bc4 |
if ($LEAK_TEST) {
|
|
Packit |
4e8bc4 |
my $tries = 0;
|
|
Packit |
4e8bc4 |
while ($tries) {
|
|
Packit |
4e8bc4 |
print $sock "slabs reassign 1 39\r\n";
|
|
Packit |
4e8bc4 |
my $res = <$sock>;
|
|
Packit |
4e8bc4 |
if ($res =~ m/BUSY/) {
|
|
Packit |
4e8bc4 |
select undef, undef, undef, 0.10;
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
$tries--;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
my $long_key = "f" x 512;
|
|
Packit |
4e8bc4 |
while (1) {
|
|
Packit |
4e8bc4 |
print $sock "get foo1 foo2 foo3 $long_key\r\n";
|
|
Packit |
4e8bc4 |
my $res = <$sock>;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
done_testing();
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
END {
|
|
Packit |
4e8bc4 |
unlink $ext_path if $ext_path;
|
|
Packit |
4e8bc4 |
}
|