summaryrefslogtreecommitdiff
path: root/t/lru-crawler.t
blob: 8bfa885c3942f8fb658de4039b67851fbf42d8d6 (plain)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/env perl

use strict;
use warnings;
use Test::More tests => 70257;
use FindBin qw($Bin);
use lib "$Bin/lib";
use MemcachedTest;

my $server = new_memcached('-m 32 -o no_modern');
{
    my $stats = mem_stats($server->sock, ' settings');
    is($stats->{lru_crawler}, "no");
}

my $sock = $server->sock;

# Fill a slab a bit.
# Some immortal items, some long expiring items, some short expiring items.
# Done so the immortals end up at the tail.
for (1 .. 30) {
    print $sock "set ifoo$_ 0 0 2\r\nok\r\n";
    is(scalar <$sock>, "STORED\r\n", "stored key");
}
for (1 .. 30) {
    print $sock "set lfoo$_ 0 3600 2\r\nok\r\n";
    is(scalar <$sock>, "STORED\r\n", "stored key");
}
for (1 .. 30) {
    print $sock "set sfoo$_ 0 1 2\r\nok\r\n";
    is(scalar <$sock>, "STORED\r\n", "stored key");
}

{
    my $slabs = mem_stats($sock, "slabs");
    is($slabs->{"1:used_chunks"}, 90, "slab1 has 90 used chunks");
}

sleep 3;

print $sock "lru_crawler enable\r\n";
is(scalar <$sock>, "OK\r\n", "enabled lru crawler");
{
    my $stats = mem_stats($server->sock, ' settings');
    is($stats->{lru_crawler}, "yes");
}

print $sock "lru_crawler crawl 1\r\n";
is(scalar <$sock>, "OK\r\n", "kicked lru crawler");
while (1) {
    my $stats = mem_stats($sock);
    last unless $stats->{lru_crawler_running};
    sleep 1;
}

{
    my $slabs = mem_stats($sock, "slabs");
    is($slabs->{"1:used_chunks"}, 60, "slab1 now has 60 used chunks");
    my $items = mem_stats($sock, "items");
    is($items->{"items:1:crawler_reclaimed"}, 30, "slab1 has 30 reclaims");
}

# Ensure pipelined commands fail with metadump.
# using metaget because get forces pipeline flush.
{
    print $sock "mg foo v\r\nlru_crawler metadump all\r\n";
    is(scalar <$sock>, "EN\r\n");
    is(scalar <$sock>, "ERROR cannot pipeline other commands before metadump\r\n");
}

# Check that crawler metadump works correctly.
{
    print $sock "lru_crawler metadump all\r\n";
    my $count = 0;
    while (<$sock>) {
        last if /^(\.|END)/;
        /^(key=) (\S+).*([^\r\n]+)/;
        $count++;
    }
    is ($count, 60, "metadump all returns all items");
}

for (1 .. 30) {
    mem_get_is($sock, "ifoo$_", "ok");
    mem_get_is($sock, "lfoo$_", "ok");
    mem_get_is($sock, "sfoo$_", undef);
}

# add a few more items into a different slab class
my $mfdata = 'x' x 512;
for (1 .. 30) {
    print $sock "set mfoo$_ 0 0 512\r\n$mfdata\r\n";
    is(scalar <$sock>, "STORED\r\n", "stored key");
}

# set enough small values to ensure bucket chaining happens
# ... but not enough that hash table expansion happens.
# TODO: check hash power level?
my %bfoo = ();
for (1 .. 70000) {
    print $sock "set bfoo$_ 0 0 1 noreply\r\nz\r\n";
    $bfoo{$_} = 1;
}
{
    print $sock "version\r\n";
    my $res = <$sock>;
    like($res, qr/^VERSION/, "bulk sets completed");
}

# Check metadump hash table walk returns correct number of items.
{
    print $sock "lru_crawler metadump hash\r\n";
    my $count = 0;
    while (<$sock>) {
        last if /^(\.|END)/;
        if (/^key=bfoo(\S+)/) {
            ok(exists $bfoo{$1}, "found bfoo key $1 is still in test hash");
            delete $bfoo{$1};
        }
        $count++;
    }
    is ($count, 70090, "metadump hash returns all items");
    is ((keys %bfoo), 0, "metadump found all bfoo keys");
}

print $sock "lru_crawler disable\r\n";
is(scalar <$sock>, "OK\r\n", "disabled lru crawler");
my $settings_match = 0;
# TODO: we retry a few times since the settings value is changed
# outside of a memory barrier, but the thread is stopped before the OK is
# returned.
# At some point better handling of the setings synchronization should happen.
for (1 .. 10) {
    my $stats = mem_stats($server->sock, ' settings');
    if ($stats->{lru_crawler} eq "no") {
        $settings_match = 1;
        last;
    }
    sleep 1;
}
is($settings_match, 1, "settings output matches crawler state");

$server->stop;

# Test initializing crawler from starttime.
$server = new_memcached('-m 32 -o no_modern,lru_crawler');
$sock = $server->sock;

for (1 .. 30) {
    print $sock "set sfoo$_ 0 1 2\r\nok\r\n";
    is(scalar <$sock>, "STORED\r\n", "stored key");
}

sleep 3;

print $sock "lru_crawler crawl 1\r\n";
is(scalar <$sock>, "OK\r\n", "kicked lru crawler");
while (1) {
    my $stats = mem_stats($sock);
    last unless $stats->{lru_crawler_running};
    sleep 1;
}

{
    my $slabs = mem_stats($sock, "slabs");
    is($slabs->{"1:used_chunks"}, 0, "slab1 now has 0 used chunks");
}