NAME
    EV::Memcached - asynchronous memcached client on libev

SYNOPSIS
        use EV;
        use EV::Memcached;

        my $mc = EV::Memcached->new(
            host     => '127.0.0.1',
            port     => 11211,
            on_error => sub { warn "memcached: @_" },
        );

        $mc->set('foo', 'bar', sub {
            my ($ok, $err) = @_;
            warn "set failed: $err" if $err;

            $mc->get('foo', sub {
                my ($value, $err) = @_;
                print "foo = $value\n";   # bar
                $mc->disconnect;
            });
        });

        EV::run;

DESCRIPTION
    A pure-XS memcached client built on the EV event loop. Implements the
    memcached binary protocol directly -- no external C client library is
    needed. All commands are non-blocking; results are delivered through
    callbacks dispatched by the EV loop.

    Highlights:

    *   Binary protocol with pipelining, multi-get via GETKQ + NOOP fence, and
        fire-and-forget quiet variants (SETQ, FLUSHQ).

    *   TCP and Unix socket transports, optional SASL PLAIN authentication
        (automatic re-auth on reconnect).

    *   Flow control via "max_pending", local "waiting_queue" with optional
        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.

        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). Does not apply to Unix sockets or to
        immediately-completing localhost connects.

    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_disconnect => $cb->()
        Fires after a disconnect, after pending callbacks have been cancelled.
        For server-initiated close, this fires before "on_error".

LIFECYCLE
  connect($host, [$port])
    Connect to a TCP host. Port defaults to 11211. Stops any pending
    auto-reconnect timer and clears any prior "path" setting.

  connect_unix($path)
    Connect via Unix domain socket. Stops any pending auto-reconnect timer and
    clears any prior "host" setting.

  disconnect
    Disconnect cleanly. Cancels any pending reconnect, drains pending command
    callbacks with "(undef, "disconnected")", then fires "on_disconnect". For an
    intentional disconnect, "on_error" does not fire -- that distinction lets
    you tell user-initiated teardown from server-side close.

  is_connected
    Returns true while a session is established or in progress (TCP handshake /
    SASL exchange). Commands issued in the connecting phase are queued and sent
    on completion.

  quit([$cb])
    Send a memcached "QUIT" and let the server close the connection.

STORAGE COMMANDS
    Each command's callback receives "($result, $err)". $result is 1 on success.

  set($key, $value, [$expiry, [$flags,]] [$cb])
    Store unconditionally. Without $cb this becomes fire-and-forget (SETQ): no
    response is received and any server-side failure is silently dropped.

  add($key, $value, [$expiry, [$flags,]] [$cb])
    Store only if the key does not exist. Errors with "NOT_STORED" if present.

  replace($key, $value, [$expiry, [$flags,]] [$cb])
    Store only if the key already exists. Errors with "NOT_STORED" if absent.

  cas($key, $value, $cas, [$expiry, [$flags,]] [$cb])
    Compare-and-swap. The $cas token comes from a prior "gets" / "gats" /
    "mgets". Errors with "EXISTS" on token mismatch or "NOT_FOUND" if the key
    disappeared.

  append($key, $data, [$cb])
    Append bytes to an existing value. Errors with "NOT_STORED" if the key does
    not exist. Without $cb, errors are silently dropped.

  prepend($key, $data, [$cb])
    Prepend bytes to an existing value. Same error and fire-and-forget semantics
    as "append".

  delete($key, [$cb])
    Delete a key. Errors with "NOT_FOUND" if absent.

RETRIEVAL COMMANDS
  get($key, [$cb->($value, $err)])
    Retrieve a value. On a cache miss, both $value and $err are "undef" -- a
    miss is not an error.

  gets($key, [$cb->($info, $err)])
    Like "get" but returns "{ value => ..., flags => ..., cas => ... }".

  mget(\@keys, [$cb->(\%values, $err)])
    Multi-get, internally pipelined as a sequence of GETKQ packets terminated by
    a NOOP fence. Returns a hash containing only the keys that were hits:

        $mc->mget([qw(k1 k2 k3)], sub {
            my ($values, $err) = @_;
            # $values = { k1 => 'v1', k3 => 'v3' }   # k2 was a miss
        });

  mgets(\@keys, [$cb->(\%info, $err)])
    Like "mget" but each value carries metadata:

        $mc->mgets([qw(k1 k2)], sub {
            my ($info, $err) = @_;
            # $info = { k1 => { value => 'v', flags => 0, cas => 123 } }
        });

ATOMIC COUNTERS
  incr($key, [$delta, [$initial, [$expiry,]]] [$cb->($new_value, $err)])
    Atomic increment. $delta defaults to 1. $expiry defaults to 0xFFFFFFFF,
    which means "do not auto-create" (the call then errors with "NOT_FOUND").
    Pass any other expiry to auto-create with $initial:

        $mc->incr('counter', 1, sub { ... });          # require existing
        $mc->incr('counter', 1, 100, 300, sub { ... }); # auto-create at 100, 5min TTL

    $new_value is the post-increment counter value.

  decr($key, [$delta, [$initial, [$expiry,]]] [$cb->($new_value, $err)])
    Atomic decrement. Memcached clamps the result at 0 (never negative). Same
    auto-create semantics as "incr".

EXPIRATION
  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")".
    The connection itself is left intact.

  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
    Every option from "new" has a getter/setter of the same name. 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.

    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", "delete", "incr",
    ...) always use the non-quiet opcode so error responses are consumed by the
    client even when the user passed no callback. 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>.

AUTHOR
    vividsnow

LICENSE
    This library is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

