| #!/usr/bin/perl |
| |
| # (C) Maxim Dounin |
| |
| # Test for stale events handling in upstream keepalive. |
| |
| ############################################################################### |
| |
| use warnings; |
| use strict; |
| |
| use Test::More; |
| |
| BEGIN { use FindBin; chdir($FindBin::Bin); } |
| |
| use lib 'lib'; |
| use Test::Nginx; |
| |
| ############################################################################### |
| |
| select STDERR; $| = 1; |
| select STDOUT; $| = 1; |
| |
| eval { require Cache::Memcached; }; |
| plan(skip_all => 'Cache::Memcached not installed') if $@; |
| |
| my $t = Test::Nginx->new()->has(qw/http memcached upstream_keepalive rewrite/) |
| ->has_daemon('memcached')->plan(1) |
| ->write_file_expand('nginx.conf', <<'EOF'); |
| |
| %%TEST_GLOBALS%% |
| |
| daemon off; |
| |
| worker_processes 2; |
| |
| events { |
| } |
| |
| http { |
| %%TEST_GLOBALS_HTTP%% |
| |
| upstream memd { |
| server 127.0.0.1:8081; |
| keepalive 1; |
| } |
| |
| server { |
| listen 127.0.0.1:8080 sndbuf=32k; |
| server_name localhost; |
| |
| location / { |
| set $memcached_key $uri; |
| memcached_pass memd; |
| } |
| } |
| } |
| |
| EOF |
| |
| my $memhelp = `memcached -h`; |
| my @memopts1 = (); |
| |
| if ($memhelp =~ /repcached/) { |
| # repcached patches adds additional listen socket memcached |
| # that should be different too |
| |
| push @memopts1, '-X', port(8082); |
| } |
| if ($memhelp =~ /-U/) { |
| # UDP ports no longer off by default in memcached 1.2.7+ |
| |
| push @memopts1, '-U', '0'; |
| } |
| if ($memhelp =~ /-t/) { |
| # for connection stats consistency in threaded memcached 1.3+ |
| |
| push @memopts1, '-t', '1'; |
| } |
| |
| $t->run_daemon('memcached', '-l', '127.0.0.1', '-p', port(8081), @memopts1); |
| |
| $t->run(); |
| |
| $t->waitforsocket('127.0.0.1:' . port(8081)) |
| or die "Unable to start memcached"; |
| |
| ############################################################################### |
| |
| my $memd1 = Cache::Memcached->new(servers => [ '127.0.0.1:' . port(8081) ], |
| connect_timeout => 1.0); |
| |
| # It's possible that stale events occur, i.e. read event handler called |
| # for just saved upstream connection without any data available for |
| # read. We shouldn't close upstream connection in such situation. |
| # |
| # This happens due to reading from upstream connection on downstream write |
| # events. More likely to happen with multiple workers due to use of posted |
| # events. |
| # |
| # Stale event may only happen if reading response from upstream requires |
| # entering event loop, i.e. response should be big enough. On the other |
| # hand, it is less likely to occur with full client's connection output |
| # buffer. |
| # |
| # We use here 2 workers, 20k response and set output buffer on clients |
| # connection to 32k. This allows more or less reliably reproduce stale |
| # events at least on FreeBSD testbed here. |
| |
| $memd1->set('/big', 'X' x 20480); |
| |
| my $total = $memd1->stats()->{total}->{total_connections}; |
| |
| for (1 .. 100) { |
| http_get('/big'); |
| } |
| |
| cmp_ok($memd1->stats()->{total}->{total_connections}, '<=', $total + 2, |
| 'only one connection per worker used'); |
| |
| ############################################################################### |