Documentation
¶
Overview ¶
Package memcache implements a modern memcached client using only the meta text protocol (mg, ms, md, ma, me, and mn).
The Client's methods are one verb per operation (Get, Fetch, Update, Incr, Take, ...), each returning business values. A miss is a normal answer, never an error; concurrency coordination (leases, compare-and-swap loops, request merging) is the library's job and never appears in caller code; failure behavior is an explicit policy (Degrade, OnError). Values are []byte in this release; the typed layer arrives with generic methods in go1.27.
The 1:1 protocol layer remains fully available behind Client.Meta. Client is safe for concurrent use.
Index ¶
- Constants
- Variables
- func RefreshAhead(d time.Duration) interface{ ... }
- type AmbiguousWriteError
- type ArithmeticOperation
- type ArithmeticResult
- type Client
- func (c *Client) Add(ctx context.Context, key string, value []byte, ttl time.Duration) (bool, error)
- func (c *Client) Append(ctx context.Context, key string, fragment []byte, ttl time.Duration) error
- func (c *Client) Close() error
- func (c *Client) Decr(ctx context.Context, key string, delta uint64, ttl time.Duration) (uint64, error)
- func (c *Client) Delete(ctx context.Context, key string) error
- func (c *Client) DeleteMany(ctx context.Context, keys []string) error
- func (c *Client) Fetch(ctx context.Context, key string, ttl time.Duration, ...) ([]byte, error)
- func (c *Client) Get(ctx context.Context, key string, options ...GetOption) ([]byte, bool, error)
- func (c *Client) GetMany(ctx context.Context, keys []string, options ...GetOption) (map[string][]byte, error)
- func (c *Client) Incr(ctx context.Context, key string, delta uint64, ttl time.Duration) (uint64, error)
- func (c *Client) Inspect(ctx context.Context, key string) (ItemInfo, bool, error)
- func (c *Client) Invalidate(ctx context.Context, key string, grace time.Duration) error
- func (c *Client) Meta() *MetaClient
- func (c *Client) Prepend(ctx context.Context, key string, fragment []byte, ttl time.Duration) error
- func (c *Client) Replace(ctx context.Context, key string, value []byte, ttl time.Duration) (bool, error)
- func (c *Client) Set(ctx context.Context, key string, value []byte, ttl time.Duration) error
- func (c *Client) SetMany(ctx context.Context, mapping map[string][]byte, ttl time.Duration) error
- func (c *Client) Take(ctx context.Context, key string) ([]byte, error)
- func (c *Client) Touch(ctx context.Context, key string, ttl time.Duration) error
- func (c *Client) Update(ctx context.Context, key string, ttl time.Duration, ...) ([]byte, error)
- type DeleteOperation
- type DialContextFunc
- type Expiration
- type FetchOption
- type GetOperation
- type GetOption
- type GetResult
- type GetStatus
- type ItemInfo
- type LeaseState
- type MetaArithmeticOptions
- type MetaClient
- func (m *MetaClient) Arithmetic(ctx context.Context, key string, options MetaArithmeticOptions) (ArithmeticResult, error)
- func (m *MetaClient) Batch(ctx context.Context, operations []Operation) ([]OperationResult, error)
- func (m *MetaClient) Debug(ctx context.Context, key string) (map[string]string, error)
- func (m *MetaClient) Delete(ctx context.Context, key string, options MetaDeleteOptions) (MutationResult, error)
- func (m *MetaClient) Execute(ctx context.Context, command MetaCommand) (RawResponse, error)
- func (m *MetaClient) Get(ctx context.Context, key string, options MetaGetOptions) (GetResult, error)
- func (m *MetaClient) Noop(ctx context.Context) error
- func (m *MetaClient) Set(ctx context.Context, key string, value []byte, options MetaSetOptions) (MutationResult, error)
- type MetaCommand
- type MetaDeleteOptions
- type MetaGetOptions
- type MetaSetOptions
- type Metadata
- type MutationResult
- type MutationStatus
- type Operation
- type OperationResult
- type Option
- func WithDialTimeout(timeout time.Duration) Option
- func WithDialer(dial DialContextFunc) Option
- func WithIdleTimeout(timeout time.Duration) Option
- func WithMaxIdleConns(max int) Option
- func WithMaxItemSize(max int) Option
- func WithNetwork(network string) Option
- func WithRouter(router Router) Option
- func WithServers(servers ...string) Option
- func WithTimeout(timeout time.Duration) Option
- type PolicyOption
- type ProtocolError
- type RawResponse
- type RendezvousRouter
- type ResponseCode
- type Router
- type ServerError
- type SetOperation
- type StoreMode
- type ValueState
Constants ¶
const Forever time.Duration = 0
Forever stores without expiration. TTL is a positional parameter on every verb that needs one, so "never expire" is always a visible choice at the call site, never a silent fallback.
Variables ¶
var ( // ErrCacheMiss is a protocol-layer sentinel returned by MetaClient.Debug // when the key is absent. Client verbs never return it: a miss is a // normal answer there, expressed by the ok result or key absence. ErrCacheMiss = errors.New("memcache: cache miss") // ErrClosed is returned after a client has been closed. ErrClosed = errors.New("memcache: client is closed") // ErrNotStored means a conditional mutation was not applied. ErrNotStored = errors.New("memcache: value not stored") // ErrConflict is returned by Update and Take when their optimistic // retry loop keeps losing to concurrent writers. ErrConflict = errors.New("memcache: too many conflicting concurrent writes") )
Functions ¶
func RefreshAhead ¶
func RefreshAhead(d time.Duration) interface { PolicyOption FetchOption }
RefreshAhead makes Fetch refresh a value in the background once its remaining TTL enters the window, so no reader ever pays the recompute latency. Meaningful only on Fetch, or as a client-wide default.
Types ¶
type AmbiguousWriteError ¶
AmbiguousWriteError means a side-effecting request reached the connection, but its result could not be observed. Retrying it may duplicate the effect. It is the one error class Degrade never absorbs: degrading covers "the cache is unavailable", not "the write may or may not have landed".
func (*AmbiguousWriteError) Error ¶
func (e *AmbiguousWriteError) Error() string
func (*AmbiguousWriteError) Unwrap ¶
func (e *AmbiguousWriteError) Unwrap() error
type ArithmeticOperation ¶
type ArithmeticOperation struct {
Key string
Options MetaArithmeticOptions
}
ArithmeticOperation is a batch meta arithmetic command.
type ArithmeticResult ¶
type ArithmeticResult struct {
Key string
Status MutationStatus
Value uint64
HasValue bool
Metadata Metadata
ReturnedKey []byte
Opaque string
}
ArithmeticResult describes an increment or decrement outcome.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a concurrent meta-protocol memcached client. Its methods are one verb per operation, returning business values. The 1:1 protocol layer stays available behind Meta.
func NewServers ¶
NewServers creates a client for one or more backends. It is the preferred multi-server constructor; keys are routed with RendezvousRouter by default.
func (*Client) Add ¶
func (c *Client) Add(ctx context.Context, key string, value []byte, ttl time.Duration) (bool, error)
Add stores only when the key is absent and reports whether this caller won. The bool is the caller's whole answer, so Add keeps it; it is also why Degrade never fakes a result here.
func (*Client) Append ¶
Append adds a fragment to the end of a raw bytes value, creating the value with ttl on a miss. The ttl applies only at creation; later appends never extend an existing value's lifetime. Fragments bypass any value encoding; how the accumulated bytes are structured is the caller's business.
func (*Client) Close ¶
Close cancels background refreshes and any in-flight Fetch loaders, releases idle connections, and prevents new work. Requests already on the wire finish their exchange. Close is idempotent.
func (*Client) Decr ¶
func (c *Client) Decr(ctx context.Context, key string, delta uint64, ttl time.Duration) (uint64, error)
Decr subtracts delta from a decimal counter, saturating at zero. A miss creates the counter at zero with ttl; as with Incr, the ttl applies only at creation.
func (*Client) Delete ¶
Delete removes a key. Deleting an absent key is a success: the goal state already holds.
func (*Client) DeleteMany ¶
DeleteMany removes a set of keys in one round trip per backend.
func (*Client) Fetch ¶
func (c *Client) Fetch(ctx context.Context, key string, ttl time.Duration, loader func(context.Context) ([]byte, error), options ...FetchOption) ([]byte, error)
Fetch returns the cached value or computes it exactly once, storing the computed value for ttl. On a miss it takes a server-side lease so that across processes and goroutines a single loader runs while everyone else waits for its result; near expiry (inside RefreshAhead) or during an Invalidate grace period it returns the current value immediately and recomputes in the background. Fetch never fails because coordination failed: every path ends in a value, the loader's own error, or the caller's context error, and write-back failures only reach OnError. Paths that compute without a lease (Degrade, a lease held elsewhere) still merge through the in-process flight map, so a process runs at most one loader per key.
The loader does not run on the calling context: a background refresh outlives its caller, and a miss-path result is shared by every waiter in the process, so one short-deadline caller must not cancel it for everyone. The loader receives a context owned by the client (carrying the winning caller's deadline on the miss path) and must not rely on request-scoped values.
func (*Client) Get ¶
Get reads a value. A miss is a normal answer, not an error: ok reports presence, err reports infrastructure failure, and the two never mix. A value kept stale by Invalidate is returned as an ordinary hit. The Touch option makes the same command also slide the hit's expiration.
func (*Client) GetMany ¶
func (c *Client) GetMany(ctx context.Context, keys []string, options ...GetOption) (map[string][]byte, error)
GetMany reads a set of keys in one round trip per backend and returns the hits; a miss is expressed by key absence. With Degrade enabled a failing backend only removes its own keys from the result.
func (*Client) Incr ¶
func (c *Client) Incr(ctx context.Context, key string, delta uint64, ttl time.Duration) (uint64, error)
Incr adds delta to a decimal counter, creating it with ttl on a miss so the first request counts as delta. The ttl applies only at creation; later increments never extend an existing counter's lifetime, which is exactly what fixed-window counting needs. The result feeds business decisions, so Degrade never fakes one: infrastructure failures surface.
func (*Client) Inspect ¶
Inspect returns an item's metadata without transferring its value or bumping its LRU position. It is an observability tool; branching business logic on metadata is not a supported pattern.
func (*Client) Invalidate ¶
Invalidate marks a value stale instead of dropping it. For the grace period, readers keep the old copy while Fetch elects one caller to recompute in the background; afterwards the key decays into a normal miss. The grace bound also guarantees recovery when an elected recomputer crashes without writing: the entry dies on schedule and the next Fetch re-elects. It is an upper bound only while nothing renews the key, since Touch slides it like any other expiration. Invalidate pairs with Fetch-managed keys; use Delete when the old value must not be served for even a second.
func (*Client) Meta ¶
func (c *Client) Meta() *MetaClient
Meta returns the protocol-layer escape hatch. The returned client shares this client's connection pools and configuration.
func (*Client) Prepend ¶
Prepend adds a fragment to the front of a raw bytes value, creating the value with ttl on a miss; as with Append, the ttl applies only at creation.
func (*Client) Replace ¶
func (c *Client) Replace(ctx context.Context, key string, value []byte, ttl time.Duration) (bool, error)
Replace stores only when the key still exists and reports whether it did. It is the write half of session renewal: false means the session ended mid-request and there is nothing to write back to.
func (*Client) Set ¶
Set unconditionally stores a value for ttl. Storing without expiration is the explicit choice Forever.
func (*Client) SetMany ¶
SetMany stores a set of values in one round trip per backend, all sharing the same ttl.
func (*Client) Take ¶
Take atomically reads a value and deletes it: read with version, delete only if unchanged, retry when a concurrent write slipped in between. Bytes appended between the read and the delete are never lost. A nil result means there was nothing to take; a miss and an empty value are deliberately the same answer. The result feeds the caller's next step, so Degrade never absorbs failures here.
func (*Client) Touch ¶
Touch extends a key's TTL without transferring its value, as one blind protocol command. A missing key is not an error; there is simply nothing left to extend. The touch is memcached's native one and applies to whatever it hits, including an entry kept stale by Invalidate, so a revocation that must stick goes through Delete.
func (*Client) Update ¶
func (c *Client) Update(ctx context.Context, key string, ttl time.Duration, fn func(current []byte, found bool) ([]byte, error)) ([]byte, error)
Update atomically transforms a value and stores the result for ttl: read with version, apply fn, write back only if unchanged, retry on conflict. Version tokens never appear in user code. On a miss fn receives (nil, false); returning an error from fn aborts the whole operation without writing. fn may run multiple times and must be pure. A value kept stale by Invalidate is treated as a miss: fn transforms rather than recomputes, and transforming invalidated data would silently launder it back to fresh.
type DeleteOperation ¶
type DeleteOperation struct {
Key string
Options MetaDeleteOptions
}
DeleteOperation is a batch meta delete.
type DialContextFunc ¶
DialContextFunc opens a server connection and must be safe for concurrent use.
type Expiration ¶
type Expiration int64
Expiration is sent using memcached's TTL rules. ExpiresIn uses relative seconds through 30 days and automatically converts longer durations to an absolute timestamp; ExpiresAt can be used explicitly.
const (
NoExpiration Expiration = 0
)
func ExpiresAt ¶
func ExpiresAt(t time.Time) Expiration
ExpiresAt converts a timestamp to memcached's absolute Unix-time form.
func ExpiresIn ¶
func ExpiresIn(d time.Duration) Expiration
ExpiresIn converts a relative duration to whole seconds, rounding a positive sub-second duration up to one second.
type FetchOption ¶
type FetchOption interface {
// contains filtered or unexported methods
}
FetchOption modifies a Fetch call.
type GetOperation ¶
type GetOperation struct {
Key string
Options MetaGetOptions
}
GetOperation is a batch meta get.
type GetOption ¶
type GetOption interface {
// contains filtered or unexported methods
}
GetOption modifies a single Get or GetMany call.
func Touch ¶
Touch makes a read slide each hit's expiration to ttl in the same protocol command, which turns Get into the read half of session renewal. The slide is memcached's native touch and is blind: it extends whatever the read hits, including an entry kept stale by Invalidate, so a revocation that must stick goes through Delete. Touch(Forever) removes the expiration.
type GetResult ¶
type GetResult struct {
Key string
Status GetStatus
Value []byte
Metadata Metadata
ValueState ValueState
Lease LeaseState
ReturnedKey []byte
Opaque string
}
GetResult describes a meta get without collapsing protocol states into an error. Value is present only for a value-bearing hit.
type ItemInfo ¶
type ItemInfo struct {
// TTL is the remaining lifetime. A negative value means the item never
// expires.
TTL time.Duration
// Size is the stored value's size in bytes.
Size int
// LastAccess is the time since the item was last read or written.
LastAccess time.Duration
// HitBefore reports whether the item was ever hit since it was stored.
HitBefore bool
}
ItemInfo is the read-only metadata returned by Inspect.
type LeaseState ¶
type LeaseState uint8
LeaseState reports ownership of a vivify or early-refresh lease.
const ( LeaseNone LeaseState = iota LeaseGranted LeaseBusy )
type MetaArithmeticOptions ¶ added in v0.1.2
type MetaArithmeticOptions struct {
Delta uint64
Decrement bool
Initial *uint64
InitialTTL *Expiration
Touch *Expiration
CompareCAS *uint64
SetCAS *uint64
MetadataOnly bool
ReturnTTL bool
ReturnCAS bool
ReturnKey bool
Opaque string
}
MetaArithmeticOptions exposes meta arithmetic behavior.
type MetaClient ¶
type MetaClient struct {
// contains filtered or unexported fields
}
MetaClient is the 1:1 protocol layer behind Client.Meta. Its methods map directly onto the meta commands (mg, ms, md, ma, me, mn) and return typed results without collapsing protocol states into errors. Anything the Client's verbs do not cover is expressible here.
func (*MetaClient) Arithmetic ¶
func (m *MetaClient) Arithmetic(ctx context.Context, key string, options MetaArithmeticOptions) (ArithmeticResult, error)
Arithmetic performs configurable unsigned 64-bit meta arithmetic.
func (*MetaClient) Batch ¶
func (m *MetaClient) Batch(ctx context.Context, operations []Operation) ([]OperationResult, error)
Batch executes operations in pipelines grouped by backend and restores input order. All operations are validated before any network write. Per-operation transport failures are returned in OperationResult.Err so a failure on one backend does not erase successful results from another.
func (*MetaClient) Debug ¶
Debug returns the me command's internal key/value metadata. A miss is reported as ErrCacheMiss.
func (*MetaClient) Delete ¶
func (m *MetaClient) Delete(ctx context.Context, key string, options MetaDeleteOptions) (MutationResult, error)
Delete performs a configurable meta delete or stale invalidation.
func (*MetaClient) Execute ¶
func (m *MetaClient) Execute(ctx context.Context, command MetaCommand) (RawResponse, error)
Execute runs a raw command against the server selected by its key.
func (*MetaClient) Get ¶
func (m *MetaClient) Get(ctx context.Context, key string, options MetaGetOptions) (GetResult, error)
Get performs a configurable meta get.
func (*MetaClient) Noop ¶
func (m *MetaClient) Noop(ctx context.Context) error
Noop checks every configured backend with the meta no-op command.
func (*MetaClient) Set ¶
func (m *MetaClient) Set(ctx context.Context, key string, value []byte, options MetaSetOptions) (MutationResult, error)
Set performs a configurable meta set in any of its five modes.
type MetaCommand ¶
MetaCommand is the raw escape hatch for protocol extensions. Command must be a supported two-byte meta command. Flags omit their separating spaces.
type MetaDeleteOptions ¶ added in v0.1.2
type MetaDeleteOptions struct {
CompareCAS *uint64
SetCAS *uint64
Invalidate bool
StaleFor *Expiration
DropValue bool
ReturnKey bool
Opaque string
}
MetaDeleteOptions exposes meta delete behavior.
type MetaGetOptions ¶ added in v0.1.2
type MetaGetOptions struct {
MetadataOnly bool
ReturnCAS bool
ReturnTTL bool
ReturnSize bool
ReturnLastAccess bool
ReturnHitBefore bool
ReturnClientFlags bool
ReturnKey bool
Touch *Expiration
VivifyTTL *Expiration
RefreshBefore *Expiration
UnlessCAS *uint64
SetCAS *uint64
NoLRUBump bool
Opaque string
}
MetaGetOptions exposes meta get behavior. Zero values perform a normal value read. Set MetadataOnly for an explicit metadata-only operation. When VivifyTTL and RefreshBefore are combined, the wire protocol cannot distinguish a real empty value won for early refresh from a newly vivified empty placeholder. Value-bearing reads use the reference clients' empty value heuristic; metadata-only reads reject that combination.
type MetaSetOptions ¶ added in v0.1.2
type MetaSetOptions struct {
TTL Expiration
ClientFlags uint32
Mode StoreMode
CompareCAS *uint64
SetCAS *uint64
Invalidate bool
VivifyTTL *Expiration
ReturnCAS bool
ReturnSize bool
ReturnKey bool
Opaque string
}
MetaSetOptions exposes meta set behavior.
type Metadata ¶
type Metadata struct {
CAS *uint64
TTL *int64
Size *uint64
ClientFlags *uint32
LastAccess *uint64
HitBefore *bool
}
Metadata contains values requested from a meta get/arithmetic response. Pointer fields distinguish a returned zero from a field not requested.
type MutationResult ¶
type MutationResult struct {
Key string
Status MutationStatus
CAS *uint64
Size *uint64
ReturnedKey []byte
Opaque string
}
MutationResult describes a set or delete outcome.
func (MutationResult) Applied ¶
func (r MutationResult) Applied() bool
type MutationStatus ¶
type MutationStatus uint8
MutationStatus describes a conditional set, delete, or arithmetic outcome.
const ( MutationUnknown MutationStatus = iota MutationApplied MutationNotFound MutationAlreadyExists MutationCASMismatch )
type Operation ¶
type Operation interface {
// contains filtered or unexported methods
}
Operation is one item accepted by Client.Batch. The concrete operation structs below are the only implementations.
type OperationResult ¶
type OperationResult struct {
Get *GetResult
Mutation *MutationResult
Arithmetic *ArithmeticResult
Err error
Ambiguous bool
}
OperationResult contains exactly one typed result when Err is nil. Ambiguous is true when a side effect may have happened but no response or barrier proved its outcome.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option configures the client at construction time. Engine options such as WithTimeout implement only this interface; policy options additionally implement PolicyOption.
func WithDialTimeout ¶
WithDialTimeout sets the connection establishment timeout.
func WithDialer ¶
func WithDialer(dial DialContextFunc) Option
WithDialer supplies a custom dialer, useful for TLS and tests.
func WithIdleTimeout ¶
WithIdleTimeout bounds how long a pooled connection may sit idle before it is discarded and replaced by a fresh dial. Connections silently dropped by a restarted server or an intermediary while idle would otherwise surface as a spurious error, or as an AmbiguousWriteError on a mutation. Zero disables the limit. The default is 90 seconds.
func WithMaxIdleConns ¶
WithMaxIdleConns sets the number of idle connections retained per server. Active connections are not capped. Zero disables pooling.
func WithMaxItemSize ¶
WithMaxItemSize rejects larger outgoing and incoming values. Zero disables the limit. The default is 1 MiB, matching a default memcached server.
func WithNetwork ¶
WithNetwork changes the network passed to the dialer (normally "tcp" or "unix").
func WithRouter ¶
WithRouter supplies the multi-server routing policy.
func WithServers ¶
WithServers configures all backends. Keys are routed consistently across the list. At least one non-empty address is required.
func WithTimeout ¶
WithTimeout sets the total deadline for one command or one backend's batch exchange. Context deadlines take precedence when sooner. A zero duration disables this client-side timeout.
type PolicyOption ¶
type PolicyOption interface {
Option
// contains filtered or unexported methods
}
PolicyOption is an Option that declares a client-wide policy default, such as RefreshAhead, Degrade, or OnError. Engine options are not PolicyOptions.
func Degrade ¶
func Degrade(on bool) PolicyOption
Degrade selects the failure policy for the whole client. When enabled, reads report an infrastructure failure as a miss and unconditional writes give up silently; every absorbed error still reaches OnError. Verbs whose answer feeds a business decision (Add, Replace, Update, Incr, Decr, Take) keep returning errors, and an AmbiguousWriteError is never absorbed. The default is to return every error.
func OnError ¶
func OnError(hook func(error)) PolicyOption
OnError installs the observability hook for failures that never reach a caller: errors absorbed by Degrade, background loader failures, and Fetch write-back failures. The hook must be safe for concurrent use and must not block.
type ProtocolError ¶
type ProtocolError struct{ Message string }
ProtocolError reports malformed or unexpected data from a server.
func (*ProtocolError) Error ¶
func (e *ProtocolError) Error() string
type RawResponse ¶
type RawResponse struct {
Code ResponseCode
Value []byte
Metadata Metadata
Key []byte
Opaque string
Won bool
Busy bool
Stale bool
Flags []string
Debug map[string]string
// contains filtered or unexported fields
}
RawResponse is a lightly parsed response from ExecuteMeta.
type RendezvousRouter ¶
type RendezvousRouter struct{}
RendezvousRouter implements highest-random-weight hashing. Routing uses the original key bytes and is stable across processes.
type ResponseCode ¶
type ResponseCode string
ResponseCode is the two-byte meta protocol result code.
const ( ResponseHeader ResponseCode = "HD" ResponseValue ResponseCode = "VA" ResponseMiss ResponseCode = "EN" ResponseNotStored ResponseCode = "NS" ResponseExists ResponseCode = "EX" ResponseNotFound ResponseCode = "NF" ResponseNoop ResponseCode = "MN" ResponseDebug ResponseCode = "ME" )
type Router ¶
Router selects a server index for a key. Implementations must be safe for concurrent use and return an index in [0, len(servers)). Routers supplied with WithRouter receive a slice private to each call and may reorder it before Pick returns; the selected address is mapped back to its connection pool. Implementations must not retain or mutate the slice after Pick returns.
type ServerError ¶
ServerError represents an ERROR, CLIENT_ERROR, or SERVER_ERROR response.
func (*ServerError) Error ¶
func (e *ServerError) Error() string
type SetOperation ¶
type SetOperation struct {
Key string
Value []byte
Options MetaSetOptions
}
SetOperation is a batch meta set.
type ValueState ¶
type ValueState uint8
ValueState distinguishes fresh, stale, and lease-placeholder values.
const ( ValueUnknown ValueState = iota ValueFresh ValueStale ValueMissing )