"Fossies" - the Fresh Open Source Software Archive

Member "memcached-1.6.15/t/extstore.t" (30 Mar 2022, 6076 Bytes) of package /linux/www/memcached-1.6.15.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.14_vs_1.6.15.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    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,ext_max_sleep=100000");
   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 }