EV-Memcached
view release on metacpan or search on metacpan
replay across reconnects, configurable connect / command / waiting
timeouts.
* Predictable lifecycle: pending callbacks always fire (with the
disconnect reason on teardown), DESTROY is reentrancy-safe across
callback contexts.
AnyEvent applications can use this module unchanged, since AnyEvent runs
on top of EV when EV is loaded.
ENCODING
This module treats all keys and values as byte strings. Encode UTF-8
strings before passing them in:
use Encode;
$mc->set(foo => encode_utf8($val), sub { ... });
$mc->get('foo', sub {
my $val = decode_utf8($_[0]);
});
CALLBACK CONVENTIONS
Every command callback receives "($result, $err)". On success $err is
"undef"; on protocol error $err holds a string like "NOT_STORED" or
"NOT_FOUND". On a cache miss for "get"/"gat", both arguments are "undef"
(a miss is not an error).
Callback exceptions are caught with "G_EVAL" and reported via "warn" so
a stray "die" never unwinds the libev event loop. To abort on errors,
set a flag and break the loop; do not rely on "die" propagating out of a
callback.
CONSTRUCTOR
new(%options)
Construct an instance. All options are optional; with none, the client
is unconfigured and you must call "connect" / "connect_unix" later.
Specifying "host" (or "path") at construction time triggers an immediate
non-blocking connect. "on_connect" is always delivered from the event
loop, never synchronously from the constructor, so installing handlers
right after "new" is safe.
my $mc = EV::Memcached->new(
host => '127.0.0.1',
port => 11211,
on_error => sub { warn "@_" },
);
Connection
host => $str
port => $int (default 11211)
TCP host and port. Mutually exclusive with "path".
path => $str
Unix socket path. Mutually exclusive with "host".
loop => $ev_loop
EV loop to attach to. Default: "EV::default_loop".
priority => $num (-2 to +2)
EV watcher priority. Higher = serviced before other EV watchers.
keepalive => $seconds
TCP keepalive idle time. Set to 0 to disable. Ignored on Unix
sockets.
Timeouts and flow control
connect_timeout => $ms
Abort an in-progress non-blocking connect after this many
milliseconds. 0 = no timeout (default). Applies to any connect that
does not complete immediately (including unix sockets under rare
kernel backlog conditions); immediately-completing connects finish
on the next event loop iteration without arming this timer.
command_timeout => $ms
Disconnect with "command timeout" error if no response arrives
within this interval. The timer resets on every response from the
server. 0 = no timeout (default).
max_pending => $num
Cap on concurrent in-flight commands. Excess commands are held in a
local waiting queue. 0 = unlimited (default).
waiting_timeout => $ms
Maximum time a command may sit in the waiting queue before its
callback fires with "waiting timeout". 0 = unlimited (default).
resume_waiting_on_reconnect => $bool
If true, the waiting queue survives a disconnect and is replayed on
reconnect. Default: false.
Reconnect
reconnect => $bool
Enable automatic reconnection on transport errors.
reconnect_delay => $ms (default 1000)
Delay before each reconnect attempt. The delay is always honored via
a timer; setting it to 0 still defers through the event loop (no
synchronous retry recursion).
max_reconnect_attempts => $num
Give up after this many consecutive failures and emit "max reconnect
attempts reached". 0 = unlimited (default).
Authentication
username => $str
password => $str
SASL PLAIN credentials. When both are set, the client authenticates
after every successful connect (and reconnect). Pre-connect commands
sit in the waiting queue until SASL completes. Requires a memcached
build with SASL support and the "-S" flag.
Event handlers
on_error => $cb->($errstr)
Connection-level error callback. Default: write the message to
"STDERR" via "warn". Callbacks are run under "G_EVAL", so any "die"
in a custom handler is demoted to a warning -- use an explicit flag
if you need to terminate.
on_connect => $cb->()
Fires once the connection is fully established (after SASL, when
applicable; on SASL auth failure it never fires). Always delivered
from the event loop -- never synchronously from "new" / "connect" /
"connect_unix" -- so a handler installed right after the constructor
touch($key, $expiry, [$cb])
Update an existing key's expiration without fetching the value. Errors
with "NOT_FOUND" if absent.
gat($key, $expiry, [$cb->($value, $err)])
Get-and-touch: retrieve and update expiration in one round-trip. Same
miss semantics as "get".
gats($key, $expiry, [$cb->($info, $err)])
Get-and-touch with metadata. Same shape as "gets".
SERVER COMMANDS
flush([$expiry,] [$cb])
Invalidate every item. Optional delay in seconds before the flush takes
effect. Without $cb, sent as fire-and-forget (FLUSHQ).
noop([$cb])
No-operation round-trip. Useful as a pipeline fence to wait until all
previously-sent commands have been processed.
version([$cb->($version, $err)])
Server version string.
stats([$name,] [$cb->(\%stats, $err)])
Server statistics. Without $name, returns the default stats group.
Common groups: "settings", "items", "sizes", "slabs", "conns".
AUTHENTICATION
sasl_auth($username, $password, [$cb])
Authenticate via SASL PLAIN. Auto-invoked on connect when both
"username" and "password" were passed to the constructor; call manually
only when authenticating after a no-auth construction.
sasl_list_mechs([$cb->($mechs, $err)])
Query the server's supported mechanisms; returns a space-separated
string such as "PLAIN".
LOCAL CONTROL
skip_pending
Drain the in-flight queue, firing every callback with "(undef,
"skipped")". Responses for skipped commands are consumed and discarded
when they later arrive (strict FIFO opaque matching is preserved); the
connection genuinely stays usable for new commands.
skip_waiting
Same, but for the local waiting queue (commands not yet sent).
pending_count
Number of commands sent and awaiting a response.
waiting_count
Number of commands held in the local waiting queue (because the
connection is not ready, SASL is in progress, or "max_pending" is
saturated).
ACCESSORS
The following options have a getter/setter of the same name (there are
no accessors for "host", "port", "path", "username", "password",
"reconnect_delay", "max_reconnect_attempts", or "loop"). Calling without
arguments reads the current value; with one argument it writes and
(where meaningful, e.g. "keepalive") takes effect immediately.
connect_timeout([$ms])
command_timeout([$ms])
max_pending([$num])
waiting_timeout([$ms])
resume_waiting_on_reconnect([$bool])
priority([$num])
keepalive([$seconds])
"reconnect_enabled"
Read-only; configure via "reconnect".
"reconnect($enable, [$delay_ms], [$max_attempts])"
Reconfigure auto-reconnect at runtime.
on_error([$cb])
on_connect([$cb])
on_disconnect([$cb])
Get/set the corresponding handler. Pass "undef" to clear.
DESTRUCTION
If $mc goes out of scope while commands are in flight or queued, every
pending and waiting callback fires once with "(undef, "disconnected")".
This holds whether you call "disconnect" first or simply drop the
reference -- including dropping the last reference from inside one of
the object's own callbacks (deferred DESTROY fires the remaining
callbacks before tearing down).
The one exception is global destruction (interpreter shutdown): no Perl
callbacks are invoked then; queues are freed silently.
The clean shutdown idiom is:
$mc->disconnect; # drains queues, fires on_disconnect
undef $mc;
If a callback closes over $mc (a common mistake -- every reference
inside a callback closure keeps the object alive), break the cycle
before dropping the outer reference:
$mc->on_error(undef);
$mc->on_connect(undef);
$mc->on_disconnect(undef);
undef $mc;
DESTROY is reentrant-safe: if a callback fired during teardown drops the
last external reference to a separate "EV::Memcached", that object's
DESTROY is correctly deferred and run once unwound.
BINARY PROTOCOL NOTES
The wire format is the memcached binary protocol -- a 24-byte header
plus body, with each request tagged by an opaque field used for
in-flight matching and pipelining. Multi-get is sent as a run of GETKQ
packets ending in a NOOP fence: the server emits a response only on hit,
and the NOOP reply terminates the batch. Fire-and-forget "set"/"flush"
use the quiet SETQ / FLUSHQ opcodes so the server sends no response at
all.
Commands that can legitimately fail ("add", "replace", "append",
"prepend", "delete", "incr", ...) always use the non-quiet opcode so
error responses are consumed by the client even when the user passed no
callback. Response matching is strict FIFO per connection: responses
must arrive in request order, so only in-order servers are supported
(reordering proxies are unsupported). Keys are validated against the
250-byte protocol limit before any bytes go on the wire.
BENCHMARKS
Numbers from "bench/benchmark.pl" on Linux, TCP loopback, 100-byte
values, Perl 5.40, memcached 1.6.41:
50K cmds 200K cmds
Pipeline SET 213K 68K ops/sec
Pipeline GET 216K 67K ops/sec
Mixed workload 226K 69K ops/sec
Fire-and-forget SET 1.13M 1.29M ops/sec (SETQ)
Multi-get (GETKQ) 1.30M 1.17M ops/sec (per key)
Sequential round-trip 41K 38K ops/sec
Fire-and-forget is roughly 5x faster than callback mode because there is
no per-command Perl SV allocation. Multi-get is the fastest read path
since misses generate no traffic. Callback-mode throughput drops as
batch size grows because SV allocation for closures dominates; realistic
workloads (interleaved sends and receives) stay close to the 50K-command
column.
"max_pending" overhead (200K commands):
unlimited ~131K ops/sec
max_pending=500 ~126K ops/sec
max_pending=100 ~120K ops/sec
max_pending=50 ~117K ops/sec
Override "BENCH_COMMANDS", "BENCH_VALUE_SIZE", "BENCH_HOST", and
"BENCH_PORT" to retune.
SEE ALSO
EV, AnyEvent, Cache::Memcached::Fast, Memcached::Client,
<https://github.com/memcached/memcached/wiki/BinaryProtocolRevamped>.
( run in 0.768 second using v1.01-cache-2.11-cpan-14f38c9f855 )