#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
use FindBin qw($Bin);
use lib "$Bin/lib";
use MemcachedTest;
# NOTE: Do not use this feature on top of a filesystem, please use a ram disk!
# These tests use /tmp/ as some systems do not have or have a weirdly small
# /dev/shm.
my $mem_path = "/tmp/mc_restart.$$";
# read a invalid metadata file
{
my $meta_path = "$mem_path.meta";
open(my $f, "> $meta_path") || die("Can't open a metadata file.");
eval { new_memcached("-e $mem_path"); };
unlink($meta_path);
ok($@, "Died with an empty metadata file");
}
my $server = new_memcached("-m 128 -e $mem_path -I 2m");
my $sock = $server->sock;
diag "Set some values, various sizes.";
{
my $cur = 2;
my $cnt = 0;
my $end = 2**20;
while ($cur <= $end) {
my $val = 'x' x $cur;
print $sock "set foo${cnt} 0 0 $cur\r\n$val\r\n";
like(scalar <$sock>, qr/STORED/, "stored $cur size item");
$cur *= 2;
$cnt++;
}
}
diag "load enough items to change hash power level";
{
my $stats = mem_stats($sock);
is($stats->{hash_power_level}, 16, "starting hash level is 16");
my $todo = 2**17;
my $good = 1;
while ($todo--) {
print $sock "set z${todo} 0 0 0\r\n\r\n";
my $res = <$sock>;
$good = 0 if ($res !~ m/STORED/);
}
is($good, 1, "set responses were all STORED");
sleep 3; # sigh.
$stats = mem_stats($sock);
is($stats->{hash_power_level}, 17, "new hash power level is 17");
# Now delete all these items, so the auto-restore won't cause the hash
# table to re-inflate, but the restart code should restore the hash table
# to where it was regardless.
$todo = 2**17;
$good = 1;
while ($todo--) {
print $sock "delete z${todo}\r\n";
my $res = <$sock>;
$good = 0 if ($res !~ m/DELETED/);
}
is($good, 1, "delete responses were all DELETED");
}
diag "Load a couple chunked items";
{
my $cur = 768000;
my $cnt = 0;
my $end = $cur + 1024;
while ($cur <= $end) {
my $val = 'x' x $cur;
print $sock "set chunk${cnt} 0 0 $cur\r\n$val\r\n";
like(scalar <$sock>, qr/STORED/, "stored $cur size item");
$cur += 50;
$cnt++;
}
}
diag "Data that should expire while stopped.";
{
print $sock "set low1 0 8 2\r\nbo\r\n";
like(scalar <$sock>, qr/STORED/, "stored low ttl item");
# This one should stay.
print $sock "set low2 0 20 2\r\nmo\r\n";
like(scalar <$sock>, qr/STORED/, "stored low ttl item");
}
# make sure it's okay to stop with a logger watcher enabled.
{
my $wsock = $server->new_sock;
print $wsock "watch fetchers mutations\n";
my $res = <$wsock>;
is($res, "OK\r\n", "watcher enabled");
}
$server->graceful_stop();
diag "killed, waiting";
# TODO: add way to wait for server to fully exit..
sleep 10;
{
$server = new_memcached("-m 128 -e $mem_path -I 2m");
$sock = $server->sock;
diag "reconnected";
my $stats = mem_stats($sock);
is($stats->{hash_power_level}, 17, "restarted hash power level is 17");
}
diag "low TTL item should be gone";
{
mem_get_is($sock, 'low1', undef);
# but this one should exist.
mem_get_is($sock, 'low2', 'mo');
}
# initially inserted items.
{
my $cur = 2;
my $cnt = 0;
my $end = 1000000;
while ($cur < $end) {
my $val = 'x' x $cur;
mem_get_is($sock, 'foo' . $cnt, $val);
$cur *= 2;
$cnt++;
}
}
# chunked items.
{
my $cur = 768000;
my $cnt = 0;
my $end = $cur + 1024;
while ($cur <= $end) {
my $val = 'x' x $cur;
mem_get_is($sock, 'chunk' . $cnt, $val);
$cur += 50;
$cnt++;
}
}
done_testing();
END {
unlink $mem_path if $mem_path;
}