1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
#!/usr/bin/perl
# Test the "Error on get" path for extstore.
# the entire error handling code for process_get_command() never worked, and
# would infinite loop. get_extstore() can hit it sometimes.
use strict;
use warnings;
use Test::More;
use FindBin qw($Bin);
use lib "$Bin/lib";
use MemcachedTest;
my $ext_path;
if (!supports_extstore()) {
plan skip_all => 'extstore not enabled';
exit 0;
}
$ext_path = "/tmp/extstore.$$";
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");
my $sock = $server->sock;
# Wait until all items have flushed
sub wait_for_ext {
my $sum = 1;
while ($sum != 0) {
my $s = mem_stats($sock, "items");
$sum = 0;
for my $key (keys %$s) {
if ($key =~ m/items:(\d+):number/) {
# Ignore classes which can contain extstore items
next if $1 < 3;
$sum += $s->{$key};
}
}
sleep 1 if $sum != 0;
}
}
# We're testing to ensure item chaining doesn't corrupt or poorly overlap
# data, so create a non-repeating pattern.
my @parts = ();
for (1 .. 8000) {
push(@parts, $_);
}
my $pattern = join(':', @parts);
my $plen = length($pattern);
# Set some large items and let them flush to extstore.
for (1..5) {
my $size = 3000 * 1024;
my $data = "x" x $size;
print $sock "set foo$_ 0 0 $size\r\n$data\r\n";
my $res = <$sock>;
is($res, "STORED\r\n", "stored some big items");
}
wait_for_ext();
{
my $long_key = "f" x 512;
print $sock "get foo1 foo2 foo3 $long_key\r\n";
ok(scalar <$sock> =~ /CLIENT_ERROR bad command line format/, 'long key fails');
my $stats = mem_stats($sock);
cmp_ok($stats->{get_aborted_extstore}, '>', 1, 'some extstore queries aborted');
}
# Disable automatic page balancing, then move enough pages that the large
# items can no longer be loaded from extstore
{
print $sock "slabs automove 0\r\n";
my $res = <$sock>;
my $source = 0;
while (1) {
print $sock "slabs reassign $source 1\r\n";
$res = <$sock>;
if ($res =~ m/NOSPARE/) {
$source = -1;
my $stats = mem_stats($sock, 'slabs');
for my $key (grep { /total_pages/ } keys %$stats) {
if ($key =~ m/(\d+):total_pages/) {
next if $1 < 3;
$source = $1 if $stats->{$key} > 1;
}
}
last if $source == -1;
}
select undef, undef, undef, 0.10;
}
}
# fetching the large keys should now fail.
{
print $sock "get foo1\r\n";
my $res = <$sock>;
$res =~ s/[\r\n]//g;
is($res, 'SERVER_ERROR out of memory writing get response', 'can no longer read back item');
my $stats = mem_stats($sock);
is($stats->{get_oom_extstore}, 1, 'check extstore oom counter');
}
# Leaving this for future generations.
# The process_get_command() function had several memory leaks.
my $LEAK_TEST = 0;
if ($LEAK_TEST) {
my $tries = 0;
while ($tries) {
print $sock "slabs reassign 1 39\r\n";
my $res = <$sock>;
if ($res =~ m/BUSY/) {
select undef, undef, undef, 0.10;
} else {
$tries--;
}
}
my $long_key = "f" x 512;
while (1) {
print $sock "get foo1 foo2 foo3 $long_key\r\n";
my $res = <$sock>;
}
}
done_testing();
END {
unlink $ext_path if $ext_path;
}
|