memcached

Portable Memcached client implementing the text (ASCII) protocol. This library uses the sockets library and supports all backend Prolog systems supported by that library: ECLiPSe, GNU Prolog, SICStus Prolog, SWI-Prolog, Trealla Prolog, and XVM.

API documentation

Open the ../../apis/library_index.html#memcached link in a web browser.

Loading

To load this library, load the loader.lgt file:

| ?- logtalk_load(memcached(loader)).

Testing

To test this library predicates, load the tester.lgt file:

| ?- logtalk_load(memcached(tester)).

Note: Tests require a running Memcached server on localhost port 11211 (the default). To install and start Memcached:

On macOS:

$ brew install memcached
$ memcached -d

On Linux (Debian/Ubuntu):

$ sudo apt-get install memcached
$ sudo systemctl start memcached

On Linux (RHEL/Fedora):

$ sudo dnf install memcached
$ sudo systemctl start memcached

Protocol Version

This library implements the Memcached text (ASCII) protocol as documented in the official specification:

https://github.com/memcached/memcached/blob/master/doc/protocol.txt

The text protocol is the standard protocol supported by all Memcached clients and servers. All commands use simple text lines terminated by \r\n.

Features

  • Full storage command support: set, add, replace, append, prepend, cas

  • Retrieval commands: get, gets (with CAS token), multi-get, gat, gats

  • Key deletion with delete

  • Atomic increment/decrement with incr/decr

  • Item expiration management with touch, gat, gats

  • Server management: flush_all, version, stats

  • Graceful disconnect with quit

  • Proper handling of all protocol response codes

Usage

Connecting to a Memcached server

Basic connection to localhost on the default port (11211):

?- memcached::connect(localhost, Connection).

Connection to a specific host and port:

?- memcached::connect('cache.example.com', 11211, Connection).

Storing data

Store a value unconditionally:

?- memcached::set(Connection, my_key, 'Hello, World!').

Store with flags and expiration time (in seconds):

?- memcached::set(Connection, my_key, 'Hello!', 0, 3600).

Store only if the key does not exist:

?- memcached::add(Connection, new_key, 'New value', 0, 60).

Store only if the key already exists:

?- memcached::replace(Connection, existing_key, 'Updated', 0, 60).

Append data to an existing value:

?- memcached::append(Connection, my_key, ' World!').

Prepend data to an existing value:

?- memcached::prepend(Connection, my_key, 'Hello ').

Retrieving data

Get a value by key:

?- memcached::get(Connection, my_key, Value).

Get a value with flags:

?- memcached::get(Connection, my_key, Value, Flags).

Get a value with CAS token (for optimistic locking):

?- memcached::gets(Connection, my_key, Value, CasUnique).

Get multiple keys at once:

?- memcached::mget(Connection, [key1, key2, key3], Items).

Check-and-Set (CAS)

CAS provides optimistic locking for cache updates:

?- memcached::gets(Connection, my_key, Value, CasUnique),
   % ... process value ...
   memcached::cas(Connection, my_key, 'New value', 0, 60, CasUnique).

If another client modifies the value between gets and cas, the cas command will throw error(memcached_error(exists), _).

Deleting data

Delete an item by key:

?- memcached::delete(Connection, my_key).

Fails if the key does not exist.

Increment/Decrement

Atomically increment a numeric value:

?- memcached::set(Connection, counter, '100'),
   memcached::incr(Connection, counter, 5, NewValue).
% NewValue = 105

Atomically decrement a numeric value:

?- memcached::decr(Connection, counter, 3, NewValue).
% NewValue = 102

Note: The item must already exist and contain a decimal representation of a 64-bit unsigned integer. Decrementing below 0 yields 0.

Touch and Get-and-Touch

Update expiration time without fetching:

?- memcached::touch(Connection, my_key, 3600).

Fetch and update expiration time in one operation:

?- memcached::gat(Connection, my_key, 3600, Value).

Fetch with CAS and update expiration:

?- memcached::gats(Connection, my_key, 3600, Value, CasUnique).

Server management

Invalidate all items:

?- memcached::flush_all(Connection).

Invalidate all items after a delay (in seconds):

?- memcached::flush_all(Connection, 30).

Get server version:

?- memcached::version(Connection, Version).

Get server statistics:

?- memcached::stats(Connection, Stats).

Get specific statistics:

?- memcached::stats(Connection, items, Stats).

Disconnecting

?- memcached::disconnect(Connection).

API Summary

Connection management

  • connect(+Host, +Port, -Connection) - Connect to server

  • connect(+Host, -Connection) - Connect to server on default port

  • disconnect(+Connection) - Disconnect from server

Storage commands

  • set(+Connection, +Key, +Value, +Flags, +ExpTime) - Store unconditionally

  • set(+Connection, +Key, +Value) - Store with default flags and no expiration

  • add(+Connection, +Key, +Value, +Flags, +ExpTime) - Store only if new

  • replace(+Connection, +Key, +Value, +Flags, +ExpTime) - Store only if exists

  • append(+Connection, +Key, +Value) - Append to existing value

  • prepend(+Connection, +Key, +Value) - Prepend to existing value

  • cas(+Connection, +Key, +Value, +Flags, +ExpTime, +CasUnique) - Check-and-set

Retrieval commands

  • get(+Connection, +Key, -Value) - Get value

  • get(+Connection, +Key, -Value, -Flags) - Get value and flags

  • gets(+Connection, +Key, -Value, -CasUnique) - Get with CAS token

  • gets(+Connection, +Key, -Value, -Flags, -CasUnique) - Get with flags and CAS

  • mget(+Connection, +Keys, -Items) - Multi-get

Deletion

  • delete(+Connection, +Key) - Delete item

Increment/Decrement

  • incr(+Connection, +Key, +Amount, -NewValue) - Increment

  • decr(+Connection, +Key, +Amount, -NewValue) - Decrement

Touch

  • touch(+Connection, +Key, +ExpTime) - Update expiration

  • gat(+Connection, +Key, +ExpTime, -Value) - Get and touch

  • gats(+Connection, +Key, +ExpTime, -Value, -CasUnique) - Get-and-touch with CAS

Server commands

  • flush_all(+Connection) - Invalidate all items

  • flush_all(+Connection, +Delay) - Invalidate all items after delay

  • version(+Connection, -Version) - Get server version

  • stats(+Connection, -Stats) - Get general statistics

  • stats(+Connection, +Argument, -Stats) - Get specific statistics

Error Handling

Most predicates throw error(memcached_error(Reason), Context) on failure. Common error reasons:

  • connection_failed - Could not establish TCP connection

  • not_stored - Storage condition not met (e.g. add on existing key)

  • exists - CAS conflict (item was modified by another client)

  • not_found - CAS on non-existent key

  • server_error(Message) - Server returned an error

Retrieval predicates (get, gets, gat, gats) fail (rather than throw) when the requested key is not found. The delete, incr, decr, and touch predicates also fail when the key is not found.

Key Format

  • Keys are atoms up to 250 characters

  • Keys must not contain control characters or whitespace

  • Keys are case-sensitive

Expiration Times

  • 0 means the item never expires (may still be evicted by LRU)

  • Values up to 2592000 (30 days) are treated as relative seconds

  • Values over 2592000 are treated as absolute Unix timestamps

  • Negative values cause immediate expiration