Skip to main content

Crate ringline_memcache

Crate ringline_memcache 

Source
Expand description

ringline-native Memcache client for use inside the ringline async runtime.

This client wraps a ringline::ConnCtx and provides typed Memcache command methods that use with_bytes() + ResponseBytes::parse() for zero-copy incremental parsing. It is designed for single-threaded, single-connection use within ringline’s AsyncEventHandler::on_start() or connection tasks.

All key and value parameters accept impl AsRef<[u8]>, so you can pass &str, String, &[u8], Vec<u8>, Bytes, etc.

§Sequential API (Simple)

The basic API sends one command and awaits its response:

use ringline::ConnCtx;
use ringline_memcache::Client;

async fn example(conn: ConnCtx) -> Result<(), ringline_memcache::Error> {
    let mut client = Client::new(conn);
    client.set("hello", "world").await?;
    let val = client.get("hello").await?;
    assert_eq!(val.unwrap().data.as_ref(), b"world");
    Ok(())
}

§Fire/Recv Pipelining API (High Throughput)

For higher throughput, use the fire/recv pattern to pipeline multiple commands without waiting for each response:

┌─────────────────────────────────────────────────────────────────┐
│                        Application                              │
│                                                                 │
│   client.fire_get("key1", 1)?;  ──┐                            │
│   client.fire_get("key2", 2)?;  ──┼───→ [single TCP send]      │
│   client.fire_get("key3", 3)?;  ──┘                            │
│                              │                                │
│                              ▼                                │
│                    [Memcache processes]                       │
│                              │                                │
│                              ▼                                │
│   let r1 = client.recv().await?;  ←── [response 1, user_data=1]│
│   let r2 = client.recv().await?;  ←── [response 2, user_data=2]│
│   let r3 = client.recv().await?;  ←── [response 3, user_data=3]│
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
use ringline::ConnCtx;
use ringline_memcache::{Client, CompletedOp};

async fn pipelined_example(conn: ConnCtx) -> Result<(), ringline_memcache::Error> {
    let mut client = Client::new(conn);

    // Fire multiple requests (synchronous, non-blocking)
    client.fire_get(b"session:abc", 1)?;
    client.fire_get(b"session:def", 2)?;
    client.fire_get(b"session:ghi", 3)?;

    // Recv responses in order (async, blocks until each arrives)
    match client.recv().await? {
        CompletedOp::Get { result, user_data, .. } => {
            assert_eq!(user_data, 1);
            let value = result?; // Option<Value>
            println!("session:abc = {:?}", value);
        }
        _ => unreachable!(),
    }

    // Continue with remaining responses...
    match client.recv().await? {
        CompletedOp::Get { result: _, user_data, .. } => {
            assert_eq!(user_data, 2);
        }
        _ => unreachable!(),
    }

    match client.recv().await? {
        CompletedOp::Get { result: _, user_data, .. } => {
            assert_eq!(user_data, 3);
        }
        _ => unreachable!(),
    }

    Ok(())
}

§Fire/Recv Benefits

  • Overlaps network RTT: All commands sent before any response received
  • Better TCP utilization: Multiple commands coalesced into fewer segments
  • Correlation via user_data: Attach opaque u64 to each fire, returned on recv
  • Zero-copy values: Responses are Bytes::slice() into the recv accumulator

§Available Fire Methods

§Important Notes

  • Responses must be consumed in FIFO order (protocol guarantee)
  • recv() returns Error::NoPending if called with no in-flight requests
  • Timing is zero-overhead when no callbacks/metrics are configured

§Copy Semantics

PathCopiesMechanism
Recv (values)0with_bytes() + ResponseBytes::parse(). Keys and values are Bytes::slice() references into the accumulator — zero allocation, O(1) refcount.
Send (commands)1encode_request() serializes into Vec<u8>, then conn.send() copies into the send pool.
Send (SET value, guard)0 (value)Client::set_with_guard: prefix+suffix copied to pool, value stays in-place via SendGuard.

TLS connections add encryption copies on the send path regardless of SendGuard usage.

Re-exports§

pub use pool::Pool;
pub use pool::PoolConfig;
pub use sharded::ShardedClient;
pub use sharded::ShardedConfig;

Modules§

pool
Connection pool for ringline-memcache.
sharded
Ketama-sharded client for ringline-memcache.

Structs§

Client
A ringline-native Memcache client wrapping a single connection.
ClientBuilder
Builder for creating a Client with per-request callbacks and metrics.
ClientMetrics
Built-in histogram-based metrics, available when the metrics feature is enabled. Not registered globally — the caller decides how to expose them.
CommandResult
Result metadata for a completed command, passed to the on_result callback.
GetValue
A value returned from a multi-key GET command, including the key.
Value
A value returned from a single-key GET command.

Enums§

CommandType
The type of Memcache command that completed.
CompletedOp
A completed fire/recv operation with its result.
Error
Errors returned by the ringline Memcache client.

Constants§

MAX_KEY_LEN
Maximum key length per memcache text-protocol spec.
MAX_VALUE_LEN
Maximum value length matching the parser cap in memcache-proto (MAX_VALUE_DATA_LEN) and memcached’s default -I 1 MiB item size.