NAME
    EV::Memcached - High-performance asynchronous memcached client using EV

SYNOPSIS
        use EV::Memcached;

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

        $mc->set('foo', 'bar', sub {
            my ($result, $err) = @_;
            die $err if $err;

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

        EV::run;

DESCRIPTION
    EV::Memcached is a high-performance asynchronous memcached client that
    implements the memcached binary protocol in pure XS with EV event loop
    integration. No external C memcached client library is required.

    Features:

    *   Binary protocol for efficient encoding and pipelining

    *   Automatic pipelining (multiple commands in flight)

    *   Multi-get optimization via GETKQ + NOOP fence

    *   Flow control (max_pending, waiting queue)

    *   Automatic reconnection

    *   Fire-and-forget mode (no callback)

    *   TCP and Unix socket support

    *   SASL PLAIN authentication (auto-auth on connect)

    *   Connect and command timeouts

    *   Key length validation (250-byte protocol limit)

ANYEVENT INTEGRATION
    AnyEvent has EV as one of its backends, so EV::Memcached can be used in
    AnyEvent applications seamlessly.

NO UTF-8 SUPPORT
    This module handles all variables as bytes. Encode your UTF-8 strings
    before passing them:

        use Encode;

        $mc->set(foo => encode_utf8($val), sub { ... });

        $mc->get('foo', sub {
            my $val = decode_utf8($_[0]);
        });

METHODS
  new(%options)
    Create a new EV::Memcached instance. All options are optional.

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

    Options:

    host => 'Str'
    port => 'Int' (default 11211)
        Hostname and port. Mutually exclusive with "path".

    path => 'Str'
        Unix socket path. Mutually exclusive with "host".

    on_error => $cb->($errstr)
        Error callback for connection-level errors. Default: "die".

    on_connect => $cb->()
        Called when connection is established.

    on_disconnect => $cb->()
        Called when disconnected.

    connect_timeout => $ms
        Connection timeout in milliseconds. 0 = no timeout (default). Only
        applies to non-blocking TCP connects (not Unix sockets or immediate
        localhost connections).

    command_timeout => $ms
        Command timeout in milliseconds. When set, if no response is
        received within this interval, the connection is terminated with
        "command timeout" error. The timer resets on every response from the
        server. 0 = no timeout (default).

    max_pending => $num
        Maximum concurrent commands. 0 = unlimited (default).

    waiting_timeout => $ms
        Max time in local queue before cancellation. 0 = unlimited.

    resume_waiting_on_reconnect => $bool
        Keep waiting queue on disconnect for replay after reconnect.

    reconnect => $bool
        Enable automatic reconnection.

    reconnect_delay => $ms (default 1000)
    max_reconnect_attempts => $num (0 = unlimited)
    priority => $num (-2 to +2)
        EV watcher priority.

    keepalive => $seconds
        TCP keepalive interval.

    username => 'Str'
    password => 'Str'
        SASL PLAIN authentication credentials. When both are set, the client
        automatically authenticates after connecting (and after each
        reconnect). Requires memcached started with "-S" flag and SASL
        support compiled in.

    loop => EV::Loop
        EV loop to use. Default: "EV::default_loop".

  connect($host, [$port])
    Connect to memcached server. Port defaults to 11211.

  connect_unix($path)
    Connect via Unix socket.

  disconnect
    Disconnect from server. Stops reconnect timer. Pending command callbacks
    receive "(undef, "disconnected")" error. "on_disconnect" fires after
    pending callbacks have been cancelled.

    For intentional disconnect, only "on_disconnect" fires. For
    server-initiated close or errors, "on_disconnect" fires first, then
    "on_error" fires with the reason (e.g., "connection closed by server",
    "command timeout"). This lets you distinguish the two cases.

  is_connected
    Returns true if connected or connecting.

  get($key, [$cb->($value, $err)])
    Retrieve a value. On miss: "($value, $err)" are both "undef".

  gets($key, [$cb->($result, $err)])
    Retrieve with metadata. $result is "{ value, flags, cas }".

  set($key, $value, [$expiry, [$flags,]] [$cb])
    Store a value. Without callback: fire-and-forget.

  add($key, $value, [$expiry, [$flags,]] [$cb])
    Store only if key does not exist.

  replace($key, $value, [$expiry, [$flags,]] [$cb])
    Store only if key exists.

  cas($key, $value, $cas, [$expiry, [$flags,]] [$cb])
    Compare-and-swap: store only if CAS value matches.

  delete($key, [$cb])
    Delete a key.

  incr($key, [$delta, [$initial, [$expiry,]]] [$cb])
    Atomic increment. $delta defaults to 1. $expiry defaults to 0xFFFFFFFF
    (don't create if key doesn't exist).

        $mc->incr('counter', 1, sub {
            my ($new_value, $err) = @_;
        });

        # Auto-create with initial value 100, TTL 300s:
        $mc->incr('counter', 1, 100, 300, sub { ... });

  decr($key, [$delta, [$initial, [$expiry,]]] [$cb])
    Atomic decrement. Memcached clamps at 0 (never goes negative).

  append($key, $data, [$cb])
    Append data to existing value.

  prepend($key, $data, [$cb])
    Prepend data to existing value.

  touch($key, $expiry, [$cb])
    Update expiration time without fetching.

  gat($key, $expiry, [$cb->($value, $err)])
    Get and touch: retrieve value and update expiration.

  gats($key, $expiry, [$cb->($result, $err)])
    Get and touch with metadata.

  mget(\@keys, [$cb->(\%results, $err)])
    Multi-get using GETKQ + NOOP fence optimization. Results hash contains
    only found keys:

        $mc->mget([qw(k1 k2 k3)], sub {
            my ($results, $err) = @_;
            # $results = { k1 => 'val1', k3 => 'val3' }
            # k2 was a miss (not in hash)
        });

  mgets(\@keys, [$cb->(\%results, $err)])
    Like "mget" but returns full metadata per key:

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

  version([$cb->($version, $err)])
    Get server version string.

  stats([$name,] [$cb->(\%stats, $err)])
    Get server statistics. Optional $name for specific stat group.

  flush([$expiry,] [$cb])
    Invalidate all items. Optional delay in seconds.

  noop([$cb])
    No-operation. Useful as a pipeline fence.

  quit([$cb])
    Send quit command. Server will close connection.

  sasl_auth($username, $password, [$cb])
    Authenticate using SASL PLAIN mechanism. Called automatically on connect
    when "username" and "password" constructor options are set.

        $mc->sasl_auth('user', 'secret', sub {
            my ($result, $err) = @_;
            die "auth failed: $err" if $err;
            # authenticated -- proceed with commands
        });

  sasl_list_mechs([$cb->($mechs, $err)])
    Query available SASL mechanisms. Returns a space-separated string (e.g.,
    "PLAIN").

  reconnect($enable, [$delay_ms], [$max_attempts])
    Configure automatic reconnection.

  reconnect_enabled
    Returns true if reconnect is enabled.

  connect_timeout([$ms])
    Get/set connection timeout in milliseconds.

  command_timeout([$ms])
    Get/set command timeout in milliseconds. When a response is received,
    the timer resets. If no response arrives within the timeout, the
    connection is disconnected with "command timeout" error.

  pending_count
    Number of commands awaiting server response.

  waiting_count
    Number of commands in local queue (flow control).

  max_pending([$limit])
    Get/set concurrent command limit.

  waiting_timeout([$ms])
    Get/set local queue timeout.

  resume_waiting_on_reconnect([$bool])
    Get/set waiting queue behavior on disconnect.

  priority([$num])
    Get/set EV watcher priority (-2 to +2).

  keepalive([$seconds])
    Get/set TCP keepalive.

  skip_pending
    Cancel all pending command callbacks with "(undef, "skipped")".

  skip_waiting
    Cancel all waiting command callbacks with "(undef, "skipped")".

  on_error([$cb])
  on_connect([$cb])
  on_disconnect([$cb])
    Get/set handler callbacks.

DESTRUCTION BEHAVIOR
    When an EV::Memcached object is destroyed while commands are still
    pending or waiting, all pending callbacks receive "(undef,
    "disconnected")" and all waiting callbacks likewise.

    For predictable cleanup:

        $mc->disconnect;
        undef $mc;

    Or cancel callbacks first:

        $mc->skip_pending;
        $mc->skip_waiting;
        $mc->disconnect;

    Circular references: If callbacks close over $mc, break the cycle before
    the object goes out of scope:

        $mc->on_error(undef);
        $mc->on_connect(undef);
        $mc->on_disconnect(undef);

BENCHMARKS
    Measured on Linux with TCP loopback connection, 100-byte values, Perl
    5.40, memcached 1.6.41 ("bench/benchmark.pl"):

                             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 mode (no callback) is roughly 5x faster than callback
    mode due to zero Perl-side overhead per command. Multi-get is the
    fastest path since quiet commands suppress miss responses.

    Callback-based throughput scales inversely with batch size because Perl
    SV allocation dominates when many closures are queued at once. In real
    workloads (commands interleaved with responses), performance stays near
    the 50K-column numbers.

    Flow control ("max_pending") impact (200K commands):

        unlimited       ~131K ops/sec
        max_pending=500 ~126K ops/sec
        max_pending=100 ~120K ops/sec
        max_pending=50  ~117K ops/sec

    Run "perl bench/benchmark.pl" for full results. Set "BENCH_COMMANDS",
    "BENCH_VALUE_SIZE", "BENCH_HOST", and "BENCH_PORT" to customize.

BINARY PROTOCOL
    This module implements the memcached binary protocol directly in XS. The
    binary protocol provides efficient encoding with a fixed 24-byte header,
    support for pipelining via the opaque field, and quiet command variants
    for reduced network traffic.

    Multi-get uses the GETKQ (quiet get with key) opcode followed by a NOOP
    fence. Only cache hits generate responses; misses are silent. The NOOP
    response signals completion of the batch.

    Fire-and-forget "set" uses the SETQ (quiet SET) opcode -- the server
    suppresses the response entirely, eliminating network and parsing
    overhead. Other commands that can fail (add, replace, delete, incr,
    etc.) use normal opcodes even in fire-and-forget mode so error responses
    are properly consumed.

    Keys are validated against the 250-byte protocol limit.

AUTHOR
    vividsnow

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

