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
|
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use FindBin qw($Bin);
use lib "$Bin/lib";
use MemcachedTest;
use Data::Dumper qw/Dumper/;
my $ext_path;
if (!supports_extstore()) {
plan skip_all => 'extstore not enabled';
exit 0;
}
$ext_path = "/tmp/extstore.$$";
my $server = new_memcached("-m 64 -U 0 -o ext_page_size=8,ext_wbuf_size=2,ext_threads=1,ext_item_size=512,ext_item_age=0,ext_recache_rate=0,ext_max_frag=0.9,ext_path=$ext_path:64m,slab_automove=0,ext_compact_under=1,ext_max_sleep=10000");
my $sock = $server->sock;
# Wait until all items have flushed
sub wait_for_ext {
my $target = shift || 0;
my $sum = $target + 1;
while ($sum > $target) {
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};
}
}
select undef, undef, undef, 0.05 if $sum > $target;
}
}
sub rand_value {
my $v = '';
my $s = shift;
my @chars = ("C".."Z");
for (1 .. $s) {
$v .= $chars[rand @chars];
}
return $v;
}
my $value = rand_value(20000);
note "fill page with same key over and over";
{
my $rval;
for (1 .. 100) {
$rval = rand_value(20000);
print $sock "set overwrite 0 0 20000 noreply\r\n$rval\r\n";
wait_for_ext(0);
}
# poke the final overwrite key a few times so it will get rescued later
print $sock "mg overwrite\r\n";
is(scalar <$sock>, "HD\r\n");
print $sock "mg overwrite\r\n";
is(scalar <$sock>, "HD\r\n");
print $sock "extstore compact_under 6\r\n";
my $res = <$sock>;
print $sock "extstore drop_under 3\r\n";
$res = <$sock>;
# fill with junk to allow compaction to run.
my $keycount = 1800;
for (1 .. $keycount) {
print $sock "set mfoo$_ 0 0 20000 noreply\r\n$value\r\n";
# wait to avoid evictions
wait_for_ext(100);
# Keep poking the overwrite key.
print $sock "mg overwrite\r\n";
my $res = <$sock>;
}
wait_for_ext();
my $stats = mem_stats($sock);
is($stats->{evictions}, 0, 'no evictions');
is($stats->{miss_from_extstore}, 0, 'no misses');
for (1 .. $keycount) {
next unless $_ % 2 == 0;
# print $sock "delete mfoo$_ noreply\r\n";
}
# With the bug we rescue the first seen item from the page, and since we
# were randomizing values we could end up returning an old value (or more
# likely none at all).
# This should find the final randomized value has been rescued.
mem_get_is($sock, "overwrite", $rval);
$stats = mem_stats($sock);
is($stats->{badcrc_from_extstore}, 0, 'CRC checks successful');
is($stats->{miss_from_extstore}, 0, 'no misses');
cmp_ok($stats->{extstore_pages_free}, '>', 0, 'some pages now free');
cmp_ok($stats->{extstore_compact_rescues}, '>', 0, 'some compaction rescues happened');
print $sock "extstore drop_unread 0\r\n";
$res = <$sock>;
}
done_testing();
END {
unlink $ext_path if $ext_path;
}
|