"Fossies" - the Fresh Open Source Software Archive

Member "memcached-1.6.9/t/extstore.t" (21 Nov 2020, 6055 Bytes) of package /linux/www/memcached-1.6.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "extstore.t": 1.6.8_vs_1.6.9.

    1 #!/usr/bin/perl
    2 
    3 use strict;
    4 use warnings;
    5 use Test::More;
    6 use FindBin qw($Bin);
    7 use lib "$Bin/lib";
    8 use MemcachedTest;
    9 use Data::Dumper qw/Dumper/;
   10 
   11 my $ext_path;
   12 
   13 if (!supports_extstore()) {
   14     plan skip_all => 'extstore not enabled';
   15     exit 0;
   16 }
   17 
   18 $ext_path = "/tmp/extstore.$$";
   19 
   20 my $server = new_memcached("-m 64 -U 0 -o ext_page_size=8,ext_wbuf_size=2,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");
   21 my $sock = $server->sock;
   22 
   23 eval {
   24     my $server = new_memcached("-o ext_path=$ext_path:64m");
   25 };
   26 ok($@, "failed to start a second server with the same file path");
   27 
   28 # Wait until all items have flushed
   29 sub wait_for_ext {
   30     my $target = shift || 0;
   31     my $sum = $target + 1;
   32     while ($sum > $target) {
   33         my $s = mem_stats($sock, "items");
   34         $sum = 0;
   35         for my $key (keys %$s) {
   36             if ($key =~ m/items:(\d+):number/) {
   37                 # Ignore classes which can contain extstore items
   38                 next if $1 < 3;
   39                 $sum += $s->{$key};
   40             }
   41         }
   42         sleep 1 if $sum > $target;
   43     }
   44 }
   45 
   46 my $value;
   47 {
   48     my @chars = ("C".."Z");
   49     for (1 .. 20000) {
   50         $value .= $chars[rand @chars];
   51     }
   52 }
   53 
   54 # fill a small object
   55 print $sock "set foo 0 0 2\r\nhi\r\n";
   56 is(scalar <$sock>, "STORED\r\n", "stored small value");
   57 # fetch
   58 mem_get_is($sock, "foo", "hi");
   59 # check extstore counters
   60 {
   61     my $stats = mem_stats($sock);
   62     is($stats->{extstore_objects_written}, 0);
   63 }
   64 # fill some larger objects
   65 {
   66     # set one canary value for later
   67     print $sock "set canary 0 0 20000 noreply\r\n$value\r\n";
   68     my $keycount = 1000;
   69     for (1 .. $keycount) {
   70         print $sock "set nfoo$_ 0 0 20000 noreply\r\n$value\r\n";
   71     }
   72     # wait for a flush
   73     wait_for_ext();
   74     # fetch
   75     # TODO: Fetch back all values
   76     mem_get_is($sock, "nfoo1", $value);
   77     # check extstore counters
   78     my $stats = mem_stats($sock);
   79     cmp_ok($stats->{extstore_page_allocs}, '>', 0, 'at least one page allocated');
   80     cmp_ok($stats->{extstore_objects_written}, '>', $keycount / 2, 'some objects written');
   81     cmp_ok($stats->{extstore_bytes_written}, '>', length($value) * 2, 'some bytes written');
   82     cmp_ok($stats->{get_extstore}, '>', 0, 'one object was fetched');
   83     cmp_ok($stats->{extstore_objects_read}, '>', 0, 'one object read');
   84     cmp_ok($stats->{extstore_bytes_read}, '>', length($value), 'some bytes read');
   85 
   86     # Remove half of the keys for the next test.
   87     for (1 .. $keycount) {
   88         next unless $_ % 2 == 0;
   89         print $sock "delete nfoo$_ noreply\r\n";
   90     }
   91 
   92     my $stats2 = mem_stats($sock);
   93     cmp_ok($stats->{extstore_bytes_used}, '>', $stats2->{extstore_bytes_used},
   94         'bytes used dropped after deletions');
   95     cmp_ok($stats->{extstore_objects_used}, '>', $stats2->{extstore_objects_used},
   96         'objects used dropped after deletions');
   97     is($stats2->{badcrc_from_extstore}, 0, 'CRC checks successful');
   98     is($stats2->{miss_from_extstore}, 0, 'no misses');
   99 
  100     # delete the rest
  101     for (1 .. $keycount) {
  102         next unless $_ % 2 == 1;
  103         print $sock "delete nfoo$_ noreply\r\n";
  104     }
  105 }
  106 
  107 # fill to eviction
  108 {
  109     my $keycount = 4000;
  110     for (1 .. $keycount) {
  111         print $sock "set mfoo$_ 0 0 20000 noreply\r\n$value\r\n";
  112         # wait to avoid evictions
  113         wait_for_ext(500) if ($_ % 2000 == 0);
  114     }
  115     # because item_age is set to 2s
  116     wait_for_ext();
  117     my $stats = mem_stats($sock);
  118     is($stats->{evictions}, 0, 'no evictions');
  119     is($stats->{miss_from_extstore}, 0, 'no misses');
  120     # FIXME: test is flaky; something can rescue the canary because of a race
  121     # condition. might need to roundtrip twice or disable compaction?
  122     #mem_get_is($sock, "canary", undef);
  123 
  124     # check counters
  125     $stats = mem_stats($sock);
  126     cmp_ok($stats->{extstore_page_evictions}, '>', 0, 'at least one page evicted');
  127     cmp_ok($stats->{extstore_objects_evicted}, '>', 0, 'at least one object evicted');
  128     cmp_ok($stats->{extstore_bytes_evicted}, '>', 0, 'some bytes evicted');
  129     cmp_ok($stats->{extstore_pages_free}, '<', 2, 'few pages are free');
  130     #is($stats->{miss_from_extstore}, 1, 'exactly one miss');
  131 
  132     # refresh some keys so rescues happen while drop_unread == 1.
  133     for (1 .. $keycount / 2) {
  134         next unless $_ % 2 == 1;
  135         # Need to be fetched twice in order to bump
  136         print $sock "touch mfoo$_ 0 noreply\r\n";
  137         print $sock "touch mfoo$_ 0 noreply\r\n";
  138     }
  139     print $sock "extstore drop_unread 1\r\n";
  140     my $res = <$sock>;
  141     print $sock "extstore max_frag 0\r\n";
  142     $res = <$sock>;
  143     print $sock "extstore compact_under 4\r\n";
  144     $res = <$sock>;
  145     print $sock "extstore drop_under 3\r\n";
  146     $res = <$sock>;
  147     for (1 .. $keycount) {
  148         next unless $_ % 2 == 0;
  149         print $sock "delete mfoo$_ noreply\r\n";
  150     }
  151 
  152     sleep 4;
  153     $stats = mem_stats($sock);
  154     cmp_ok($stats->{extstore_pages_free}, '>', 0, 'some pages now free');
  155     cmp_ok($stats->{extstore_compact_rescues}, '>', 0, 'some compaction rescues happened');
  156     cmp_ok($stats->{extstore_compact_skipped}, '>', 0, 'some compaction skips happened');
  157     print $sock "extstore drop_unread 0\r\n";
  158     $res = <$sock>;
  159 }
  160 
  161 # attempt to incr/decr/append/prepend or chunk objects that were sent to disk.
  162 {
  163     my $keycount = 100;
  164     for (1 .. $keycount) {
  165         print $sock "set bfoo$_ 0 0 20000 noreply\r\n$value\r\n";
  166     }
  167     wait_for_ext();
  168 
  169     # incr should be blocked.
  170     print $sock "incr bfoo1 1\r\n";
  171     is(scalar <$sock>, "CLIENT_ERROR cannot increment or decrement non-numeric value\r\n", 'incr fails');
  172 
  173     # append/prepend *could* work, but it would require pulling the item back in.
  174     print $sock "append bfoo1 0 0 2\r\nhi\r\n";
  175     is(scalar <$sock>, "NOT_STORED\r\n", 'append fails');
  176     print $sock "prepend bfoo1 0 0 2\r\nhi\r\n";
  177     is(scalar <$sock>, "NOT_STORED\r\n", 'prepend fails');
  178 }
  179 
  180 done_testing();
  181 
  182 END {
  183     unlink $ext_path if $ext_path;
  184 }