memcached

package
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package memcached is celeris's native Memcached driver. It speaks both the text and binary wire protocols directly on top of the celeris event loop, using the same async-bridge architecture as the Redis and PostgreSQL drivers: one in-flight request enqueued per conn, responses demuxed from the loop's recv callback, and per-worker idle pools so handlers stay on the same CPU that dispatched them.

Usage

client, err := memcached.NewClient("localhost:11211",
    memcached.WithEngine(srv),           // optional; omit for a standalone loop
    memcached.WithProtocol(memcached.ProtocolText),
)
defer client.Close()

if err := client.Set(ctx, "key", "value", time.Minute); err != nil {
    log.Fatal(err)
}
v, err := client.Get(ctx, "key")

WithEngine routes the driver's FDs through the same epoll/io_uring instance as the HTTP workers. When it is omitted, a package-level standalone loop is resolved and reference-counted (driver/internal/eventloop).

DSNs

Addresses may optionally include a "memcache://" or "memcached://" scheme prefix; the prefix is stripped. The resulting "host:port" is passed to net.Dialer verbatim. TLS is not supported in v1.4.0.

Options

Typed Commands

The typed API on Client covers:

  • Storage: Set, Add, Replace, Append, Prepend, CAS.
  • Retrieval: Get, GetBytes, GetMulti, GetMultiBytes, Gets (returns CAS).
  • Arithmetic: Incr, Decr.
  • Keys: Delete, Touch.
  • Server: Flush, FlushAfter, Stats, Version, Ping.

Values passed to Set / Add / Replace / CAS may be string, []byte, integer, float, bool, nil, or fmt.Stringer. Anything else returns an error.

Errors

Non-sentinel server errors surface as *MemcachedError carrying the reply kind ("ERROR", "CLIENT_ERROR", "SERVER_ERROR") or, in binary mode, the raw status code.

Pool

Like the Redis and Postgres drivers, memcached uses async.Pool for worker-affinity connection pooling. Each worker owns an idle list guarded by its own lock; Acquire prefers the caller's worker before scanning neighbors. Acquire blocks when MaxOpen is reached (wait-queue semantics) rather than returning ErrPoolExhausted.

WithEngine and standalone operation

WithEngine is optional. When omitted, NewClient resolves a standalone event loop backed by the platform's best mechanism (epoll on Linux, goroutine-per-conn on Darwin). The standalone loop is reference-counted inside driver/internal/eventloop and shared across all drivers that omit WithEngine. Correctness is identical with or without WithEngine; sharing the HTTP server's event loop reduces per-IO syscalls and improves data locality because driver FDs land on the same worker goroutine as HTTP handlers.

Text vs binary protocol

The text protocol is the default. Every memcached deployment supports it, responses are self-describing, and the parser is trivially debugged by reading a PCAP. The binary protocol is opt-in via WithProtocol; it adds an opaque correlation ID, fixed-size framing, and explicit status codes. The binary dialect is useful where malformed user input or embedded NULs in values must round-trip cleanly. Both dialects truly pipeline Client.GetMulti in a single round trip — binary uses OpGetKQ + OpNoop, text uses the multi-key `get` command. Multi-packet server replies such as binary Stats are decoded natively on the active conn.

Expiration times

Callers pass a Go time.Duration relative TTL. The driver rewrites it on the wire as either a relative second-count (when <= 30 days) or an absolute Unix timestamp (when > 30 days), matching the memcached server convention. Pass 0 for no expiration.

Key validation

Keys are validated against text-protocol rules (1..250 bytes, no whitespace or control bytes) uniformly in both dialects, so that callers who switch from text to binary do not accidentally ship previously valid-looking keys that the text server would have rejected.

Multi-server sharding (ClusterClient)

Production memcached deployments fan keys across N independent nodes; the memcached protocol has no cluster-aware peer discovery, so sharding is a client-side concern. ClusterClient owns a static ring of Client instances (one per configured address) and routes each key via a libmemcached-compatible ketama consistent-hash ring.

cc, err := memcached.NewClusterClient(memcached.ClusterConfig{
    Addrs: []string{
        "memcache-a:11211",
        "memcache-b:11211",
        "memcache-c:11211",
    },
    // Optional: relative weights (nil = equal).
    // Weights: []uint32{1, 2, 1},
})
defer cc.Close()
cc.Set(ctx, "user:42", "payload", time.Hour)

The ring assigns 160 virtual nodes per unit weight, placed at MD5("<addr>-<vnode>") boundaries (4 ring points per digest). Lookup uses CRC32-IEEE on the user key and a binary search with wrap-around. Removing one of N nodes only re-homes the ~1/N share of keys it owned; the rest keep their owner, matching the usual ketama guarantee.

The ClusterClient API mirrors Client command-for-command:

  • Single-key ops (Get, Set, Delete, Incr, ...) route to pickNode(key).
  • GetMulti / GetMultiBytes partition keys by owner, fan out one sub-request per node in parallel, and merge the per-node responses. On error the first error wins; partial results from other nodes are discarded.
  • Stats, Version return a per-node map keyed by address.
  • Flush, FlushAfter, Ping fan out to every node; the first error wins.
  • NodeFor(key) exposes the ring's routing decision for debugging and for out-of-band work that needs to track per-node state.

Topology is static for the lifetime of the client: memcached nodes do not gossip and ClusterClient does not run a background refresh loop. Adding or removing a node requires tearing down the client and building a new one. For a dynamically-changing fleet, deploy a proxy such as mcrouter or twemproxy in front of the nodes and point the single-node Client at the proxy.

Known limitations (v1.4.0)

  • No TLS — deploy over VPC, loopback, or a sidecar.
  • No SASL authentication; memcached servers configured with -Y will reject the driver's handshake. Deploy with network-level auth.
  • No server-side compression. Values are sent as-is; large payloads should be compressed on the client side.
  • ClusterClient topology is static: no background refresh. Memcached nodes do not gossip. To add/remove nodes at runtime, tear down and rebuild the client, or front the fleet with mcrouter.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrCASConflict = errors.New("celeris-memcached: CAS conflict")

ErrCASConflict is returned by CAS when the server's stored CAS token no longer matches the caller-supplied one (concurrent modification).

View Source
var ErrCacheMiss = errors.New("celeris-memcached: cache miss")

ErrCacheMiss is returned by Get/GetBytes/Touch/CAS when the requested key does not exist on the server. Matches the "NOT_FOUND\r\n" text reply and the StatusKeyNotFound binary status.

View Source
var ErrClosed = errors.New("celeris-memcached: client closed")

ErrClosed is returned when a command is issued against a closed Client.

View Source
var ErrInvalidCAS = errors.New("celeris-memcached: CAS token must be non-zero (did you call Gets first?)")

ErrInvalidCAS is returned by Client.CAS when casID=0 is passed. Memcached treats a CAS value of 0 as "don't check", which would silently turn the CAS call into an unconditional Set. A legitimate CAS token returned by Gets is never 0, so casID=0 always indicates a caller bug (forgot to call Gets first, copied the token wrong, etc.). Fail loudly rather than silently degrade.

View Source
var ErrMalformedKey = errors.New("celeris-memcached: malformed key")

ErrMalformedKey is returned before wire contact when a key violates the text-protocol constraints (empty, too long, or contains whitespace/control bytes). The binary protocol has no such restrictions, but the client rejects the same set uniformly so a caller can switch dialects without changing their key-hygiene assumptions.

View Source
var ErrNoNodes = errors.New("celeris-memcached: cluster has no nodes")

ErrNoNodes is returned when a ClusterClient has no live nodes configured (typically because every ClusterConfig.Addrs entry was empty or all seed dials failed).

View Source
var ErrNotStored = errors.New("celeris-memcached: item not stored")

ErrNotStored is returned by Add/Replace/Append/Prepend when the server declines to store the value — Add finds the key already present, Replace / Append / Prepend find it missing, or the Append/Prepend target is a counter rather than a string.

View Source
var ErrPoolExhausted = errors.New("celeris-memcached: pool exhausted")

ErrPoolExhausted is returned when no connection is available and none can be dialed within MaxOpen.

View Source
var ErrProtocol = errors.New("celeris-memcached: protocol error")

ErrProtocol is returned when the server reply cannot be decoded.

Functions

func WithWorker

func WithWorker(ctx context.Context, workerID int) context.Context

WithWorker returns ctx with a preferred worker hint.

Types

type CASItem

type CASItem struct {
	Key   string
	Value []byte
	Flags uint32
	CAS   uint64
}

CASItem is the key + value + CAS token triple returned by Client.Gets.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is the high-level handle users interact with. It owns a pool of connections and hands out per-command round trips.

func NewClient

func NewClient(addr string, opts ...Option) (*Client, error)

NewClient dials a pool at addr using the given options. Connections are established lazily on first command.

When opened without WithEngine(srv), the client uses direct net.TCPConn I/O on the caller's goroutine — no event-loop indirection. This matches github.com/bradfitz/gomemcache in shape (Go's netpoll parks the goroutine on EPOLLIN transparently) and closes the foreign-HTTP gap vs gomc on the MSR1 bench from ~17% to within noise.

When opened WithEngine, the mini-loop sync path (WriteAndPollBusy) is used so DB I/O colocates with the celeris HTTP engine's worker.

addr may optionally include a "memcache://" or "memcached://" scheme prefix; the prefix is stripped and the remaining "host:port" is used verbatim. TLS is not supported in v1.4.0.

Example

ExampleNewClient shows the basic Set/Get loop. The client is lazy: the first command triggers the TCP dial.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/goceleris/celeris/driver/memcached"
)

func main() {
	client, err := memcached.NewClient("localhost:11211")
	if err != nil {
		log.Fatal(err)
	}
	defer func() { _ = client.Close() }()

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	if err := client.Set(ctx, "greeting", "hello, world", time.Minute); err != nil {
		log.Fatal(err)
	}
	v, err := client.Get(ctx, "greeting")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(v)
}

func (*Client) Add

func (c *Client) Add(ctx context.Context, key string, value any, ttl time.Duration) error

Add stores value at key only if the key does not already exist. Returns ErrNotStored when the key is present.

func (*Client) Append

func (c *Client) Append(ctx context.Context, key, value string) error

Append appends value to the existing value at key. Returns ErrNotStored when the key is missing.

func (*Client) CAS

func (c *Client) CAS(ctx context.Context, key string, value any, casID uint64, ttl time.Duration) (bool, error)

CAS performs a compare-and-swap update: the store succeeds only if the server's current CAS token matches casID. Returns (false, ErrCASConflict) on mismatch, (false, ErrCacheMiss) if the key is missing, and (true, nil) on success.

Example

ExampleClient_CAS performs an optimistic read-modify-write.

package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/goceleris/celeris/driver/memcached"
)

func main() {
	client, _ := memcached.NewClient("localhost:11211")
	defer func() { _ = client.Close() }()

	ctx := context.Background()
	item, err := client.Gets(ctx, "counter")
	if err != nil {
		log.Fatal(err)
	}
	newValue := string(item.Value) + "!"
	ok, err := client.CAS(ctx, "counter", newValue, item.CAS, time.Hour)
	if err != nil && !errors.Is(err, memcached.ErrCASConflict) {
		log.Fatal(err)
	}
	fmt.Println("stored:", ok)
}

func (*Client) Close

func (c *Client) Close() error

Close tears down every pooled connection. Safe to call on a nil Client.

func (*Client) Decr

func (c *Client) Decr(ctx context.Context, key string, delta uint64) (uint64, error)

Decr atomically decrements the integer value at key by delta and returns the new value. The memcached server clamps the result at 0 (it does not wrap to MAX_UINT).

func (*Client) Delete

func (c *Client) Delete(ctx context.Context, key string) error

Delete removes key from the cache. Returns ErrCacheMiss if the key did not exist.

func (*Client) Flush

func (c *Client) Flush(ctx context.Context) error

Flush wipes every entry across every slab class. Immediate.

func (*Client) FlushAfter

func (c *Client) FlushAfter(ctx context.Context, delay time.Duration) error

FlushAfter schedules a flush to take effect after delay. Implemented as a relative exptime argument to flush_all / OpFlush extras.

func (*Client) Get

func (c *Client) Get(ctx context.Context, key string) (string, error)

Get fetches the string value at key. Returns ErrCacheMiss when the key is missing.

Example

ExampleClient_Get illustrates handling the cache-miss sentinel.

package main

import (
	"context"
	"errors"
	"fmt"
	"log"

	"github.com/goceleris/celeris/driver/memcached"
)

func main() {
	client, _ := memcached.NewClient("localhost:11211")
	defer func() { _ = client.Close() }()

	ctx := context.Background()
	v, err := client.Get(ctx, "session:42")
	switch {
	case errors.Is(err, memcached.ErrCacheMiss):
		fmt.Println("miss")
	case err != nil:
		log.Fatal(err)
	default:
		fmt.Println(v)
	}
}

func (*Client) GetBytes

func (c *Client) GetBytes(ctx context.Context, key string) ([]byte, error)

GetBytes is the []byte variant of Client.Get. The returned slice is a fresh copy that the caller owns.

func (*Client) GetMulti

func (c *Client) GetMulti(ctx context.Context, keys ...string) (map[string]string, error)

GetMulti fetches multiple keys in one round trip. Missing keys are omitted from the returned map. Each value is a fresh copy owned by the caller.

Example

ExampleClient_GetMulti fetches several keys in one round trip (text protocol) or sequential GETs (binary protocol).

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/goceleris/celeris/driver/memcached"
)

func main() {
	client, _ := memcached.NewClient("localhost:11211")
	defer func() { _ = client.Close() }()

	ctx := context.Background()
	out, err := client.GetMulti(ctx, "user:1", "user:2", "user:3")
	if err != nil {
		log.Fatal(err)
	}
	for k, v := range out {
		fmt.Println(k, "=", v)
	}
}

func (*Client) GetMultiBytes

func (c *Client) GetMultiBytes(ctx context.Context, keys ...string) (map[string][]byte, error)

GetMultiBytes is the []byte variant of Client.GetMulti.

func (*Client) Gets

func (c *Client) Gets(ctx context.Context, key string) (CASItem, error)

Gets fetches a value along with its CAS token. The returned item's CAS field can be passed to Client.CAS to perform an atomic update.

func (*Client) IdleConnWorkers

func (c *Client) IdleConnWorkers() []int

IdleConnWorkers returns the Worker() IDs of every currently-idle connection. Intended for tests and introspection asserting that per-CPU affinity is actually honored by the dial path.

func (*Client) Incr

func (c *Client) Incr(ctx context.Context, key string, delta uint64) (uint64, error)

Incr atomically increments the integer value at key by delta and returns the new value. The server returns ErrCacheMiss if the key is missing (use Set first to initialize) or a MemcachedError if the existing value is not a decimal integer.

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) error

Ping issues a VERSION (cheaper than a full stats call) and discards the reply. Useful as a liveness probe.

func (*Client) PoolStats

func (c *Client) PoolStats() async.PoolStats

PoolStats returns driver pool occupancy. Named PoolStats rather than Stats so it doesn't collide with the server-side Client.Stats command that queries the memcached server's own statistics map.

func (*Client) Prepend

func (c *Client) Prepend(ctx context.Context, key, value string) error

Prepend prepends value to the existing value at key. Returns ErrNotStored when the key is missing.

func (*Client) Protocol

func (c *Client) Protocol() Protocol

Protocol returns the wire dialect negotiated at dial time.

func (*Client) Replace

func (c *Client) Replace(ctx context.Context, key string, value any, ttl time.Duration) error

Replace stores value at key only if the key already exists. Returns ErrNotStored when the key is missing.

func (*Client) Set

func (c *Client) Set(ctx context.Context, key string, value any, ttl time.Duration) error

Set stores value at key, overwriting any existing value.

Example

ExampleClient_Set stores a value with a 10-minute TTL.

package main

import (
	"context"
	"log"
	"time"

	"github.com/goceleris/celeris/driver/memcached"
)

func main() {
	client, _ := memcached.NewClient("localhost:11211")
	defer func() { _ = client.Close() }()

	ctx := context.Background()
	if err := client.Set(ctx, "counter", "0", 10*time.Minute); err != nil {
		log.Fatal(err)
	}
}

func (*Client) Stats

func (c *Client) Stats(ctx context.Context) (map[string]string, error)

Stats returns the server's general statistics map.

func (*Client) Touch

func (c *Client) Touch(ctx context.Context, key string, ttl time.Duration) error

Touch updates the expiration of key without fetching the value. Returns ErrCacheMiss if the key is missing.

func (*Client) Version

func (c *Client) Version(ctx context.Context) (string, error)

Version returns the server version string.

type ClusterClient

type ClusterClient struct {
	// contains filtered or unexported fields
}

ClusterClient talks to a fixed set of memcached servers, routing each key through a consistent-hash ring so addition/removal of a single server only re-homes ~1/N of the key space. Memcached has no cluster protocol: topology is strictly static from the client's point of view (add a node → build a new ClusterClient).

The ring uses the ketama algorithm: each node owns virtualNodesPerWeight × weight ring points, placed at MD5("addr-vnode") boundaries (4 points per 16-byte digest). Lookup hashes the user key with the same MD5-first-four-little-endian form so celeris is drop-in compatible with libmemcached and any ketama-adjacent client (dalli, gomemcache/ketama, mcrouter, twemproxy): a mixed-client fleet all agree on which node owns which key.

func NewClusterClient

func NewClusterClient(cfg ClusterConfig) (*ClusterClient, error)

NewClusterClient builds a ring across the given memcached endpoints. Each address becomes its own Client with its own pool. If any seed address fails to dial the whole construction is aborted and every already-opened node is closed, so no goroutine or FD leaks on partial failure.

Topology is static for the lifetime of the client: there is no background refresh loop. Memcached nodes do not gossip. To add or remove a node, tear the client down and build a new one.

func (*ClusterClient) Add

func (c *ClusterClient) Add(ctx context.Context, key string, value any, ttl time.Duration) error

Add forwards to the ring owner of key.

func (*ClusterClient) Addrs

func (c *ClusterClient) Addrs() []string

Addrs returns the configured address list in the original Addrs order. Useful for diagnostics and tests; the returned slice is a copy.

func (*ClusterClient) Append

func (c *ClusterClient) Append(ctx context.Context, key, value string) error

Append forwards to the ring owner of key.

func (*ClusterClient) CAS

func (c *ClusterClient) CAS(ctx context.Context, key string, value any, casID uint64, ttl time.Duration) (bool, error)

CAS forwards to the ring owner of key.

func (*ClusterClient) Close

func (c *ClusterClient) Close() error

Close tears down every node's connection pool. Safe to call multiple times.

func (*ClusterClient) Decr

func (c *ClusterClient) Decr(ctx context.Context, key string, delta uint64) (uint64, error)

Decr forwards to the ring owner of key.

func (*ClusterClient) Delete

func (c *ClusterClient) Delete(ctx context.Context, key string) error

Delete forwards to the ring owner of key.

func (*ClusterClient) Flush

func (c *ClusterClient) Flush(ctx context.Context) error

Flush fans a Flush to every node in parallel. Returns the first error encountered; on success the whole cluster has been wiped.

func (*ClusterClient) FlushAfter

func (c *ClusterClient) FlushAfter(ctx context.Context, delay time.Duration) error

FlushAfter schedules a delayed flush on every node. Each node starts its own local timer; the actual flushes will not be perfectly synchronized across nodes (memcached has no cluster-wide clock).

func (*ClusterClient) Get

func (c *ClusterClient) Get(ctx context.Context, key string) (string, error)

Get forwards to the ring owner of key.

func (*ClusterClient) GetBytes

func (c *ClusterClient) GetBytes(ctx context.Context, key string) ([]byte, error)

GetBytes forwards to the ring owner of key.

func (*ClusterClient) GetMulti

func (c *ClusterClient) GetMulti(ctx context.Context, keys ...string) (map[string]string, error)

GetMulti partitions keys by their ring owner, fans out one GetMulti per node in parallel, and merges the per-node results into a single map. If any sub-call returns an error the first such error is returned; partial results from the other nodes are discarded — same failure semantics as the single-server Client.GetMulti.

Missing keys are omitted (standard memcached semantics). The output map is owned by the caller.

func (*ClusterClient) GetMultiBytes

func (c *ClusterClient) GetMultiBytes(ctx context.Context, keys ...string) (map[string][]byte, error)

GetMultiBytes is the []byte variant of ClusterClient.GetMulti.

func (*ClusterClient) Gets

func (c *ClusterClient) Gets(ctx context.Context, key string) (CASItem, error)

Gets forwards to the ring owner of key.

func (*ClusterClient) Incr

func (c *ClusterClient) Incr(ctx context.Context, key string, delta uint64) (uint64, error)

Incr forwards to the ring owner of key.

func (*ClusterClient) NodeFor

func (c *ClusterClient) NodeFor(key string) string

NodeFor returns the addr of the node that key maps to. Exposed as a stable API so callers can pre-compute routing, emit debug output, or shard keyed work outside the driver (e.g. "rebalance everything on node X before draining it"). Returns "" if the client has no nodes (closed or empty).

func (*ClusterClient) Ping

func (c *ClusterClient) Ping(ctx context.Context) error

Ping pings every node in parallel. Returns the first error encountered.

func (*ClusterClient) Prepend

func (c *ClusterClient) Prepend(ctx context.Context, key, value string) error

Prepend forwards to the ring owner of key.

func (*ClusterClient) Replace

func (c *ClusterClient) Replace(ctx context.Context, key string, value any, ttl time.Duration) error

Replace forwards to the ring owner of key.

func (*ClusterClient) Set

func (c *ClusterClient) Set(ctx context.Context, key string, value any, ttl time.Duration) error

Set forwards to the ring owner of key.

func (*ClusterClient) Stats

func (c *ClusterClient) Stats(ctx context.Context) (map[string]map[string]string, error)

Stats returns each node's statistics map, keyed by address.

func (*ClusterClient) Touch

func (c *ClusterClient) Touch(ctx context.Context, key string, ttl time.Duration) error

Touch forwards to the ring owner of key.

func (*ClusterClient) Version

func (c *ClusterClient) Version(ctx context.Context) (map[string]string, error)

Version returns each node's server version string, keyed by address.

type ClusterConfig

type ClusterConfig struct {
	// Addrs is the list of memcached endpoints in "host:port" form to shard
	// across. At least one address is required.
	Addrs []string

	// Weights optionally assigns a relative weight to each address, indexed
	// by position in Addrs. A nil or empty slice means equal weight. A node
	// with weight 2 owns twice as many ring points as a node with weight 1.
	// Length must either be 0 or exactly equal to len(Addrs).
	Weights []uint32

	// Protocol selects the wire dialect used by every node client. Same
	// semantics as [Config.Protocol]; default text.
	Protocol Protocol

	// MaxOpen caps the per-node connection pool. Same semantics as
	// [Config.MaxOpen]; zero means NumWorkers * 4 per node.
	MaxOpen int

	// Timeout is the advisory per-op deadline forwarded to each node client.
	Timeout time.Duration

	// DialTimeout is the TCP dial timeout forwarded to each node client.
	DialTimeout time.Duration

	// Engine hooks the cluster into a running celeris.Server's event loop.
	// If nil, a standalone loop is resolved for each node client.
	Engine eventloop.ServerProvider
}

ClusterConfig configures a multi-server Memcached client driven by a ketama consistent-hash ring. Memcached servers do not gossip topology, so the Addrs list is authoritative and static for the lifetime of the client.

type Config

type Config struct {
	// Addr is the TCP endpoint in "host:port" form.
	Addr string
	// Protocol selects text vs binary at dial time. Default is text.
	Protocol Protocol
	// MaxOpen is the total connection cap across all workers. Zero means
	// NumWorkers * 4.
	MaxOpen int
	// MaxIdlePerWorker bounds each worker's idle list; default 2.
	MaxIdlePerWorker int
	// DialTimeout is the TCP dial timeout; default 5s.
	DialTimeout time.Duration
	// Timeout is the advisory per-op deadline used when the caller's context
	// carries no deadline. Default 3s.
	Timeout time.Duration
	// MaxLifetime is the max age of a pooled conn; default 30m.
	MaxLifetime time.Duration
	// MaxIdleTime is the max idle duration before eviction; default 5m.
	MaxIdleTime time.Duration
	// HealthCheckInterval is the background health-check sweep interval.
	// Default 30s; a negative value disables the sweep.
	HealthCheckInterval time.Duration
	// Engine hooks the driver into a running celeris.Server's event loop.
	// If nil, a standalone loop is resolved on [NewClient].
	Engine eventloop.ServerProvider
}

Config controls a Client. Use Option functions to set fields; the zero value is not directly usable.

type MemcachedError

type MemcachedError struct {
	Kind   string
	Status uint16
	Msg    string
}

MemcachedError wraps a server-side error reply.

For text protocol it carries the Kind tag ("ERROR", "CLIENT_ERROR", "SERVER_ERROR") and the accompanying message. For binary protocol it carries the raw Status code and the response body (usually a human message).

func (*MemcachedError) Error

func (e *MemcachedError) Error() string

Error implements the error interface.

type Option

type Option func(*Config)

Option mutates a Config during NewClient.

func WithDialTimeout

func WithDialTimeout(d time.Duration) Option

WithDialTimeout sets the TCP dial timeout.

func WithEngine

func WithEngine(sp eventloop.ServerProvider) Option

WithEngine hooks the driver into a celeris.Server's event loop.

func WithHealthCheckInterval

func WithHealthCheckInterval(d time.Duration) Option

WithHealthCheckInterval sets the background health-check sweep interval. Default 30s; pass a negative value to disable.

func WithMaxIdlePerWorker

func WithMaxIdlePerWorker(n int) Option

WithMaxIdlePerWorker bounds each worker's idle list.

func WithMaxIdleTime

func WithMaxIdleTime(d time.Duration) Option

WithMaxIdleTime sets the pooled conn idle eviction.

func WithMaxLifetime

func WithMaxLifetime(d time.Duration) Option

WithMaxLifetime sets the pooled conn lifetime.

func WithMaxOpen

func WithMaxOpen(n int) Option

WithMaxOpen sets the total connection cap.

func WithProtocol

func WithProtocol(p Protocol) Option

WithProtocol selects the wire dialect. Default is text.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the default per-op deadline when the caller's ctx has none.

type Protocol

type Protocol uint8

Protocol selects the memcached wire dialect spoken by a Client. Every memcached deployment supports text; binary was deprecated upstream but remains broadly available and is sometimes preferred for its CAS semantics and fixed-size packet framing. Text is the default.

const (
	// ProtocolText is the line-oriented ASCII dialect (default).
	ProtocolText Protocol = iota
	// ProtocolBinary is the 24-byte-header binary dialect.
	ProtocolBinary
)

func (Protocol) String

func (p Protocol) String() string

String returns a short name for diagnostics.

Directories

Path Synopsis
Package protocol implements the text and binary wire protocols used by the celeris native Memcached driver.
Package protocol implements the text and binary wire protocols used by the celeris native Memcached driver.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL