#ifndef MEMCACHE_H
#define MEMCACHE_H
/*
* A libevent based memcached client that aims for high performance, concurrency and low latency.
*/
#include "config.h"
/*
* Used to store the global information for a memcache context. A context contains both servers and active connections.
*
* Each context has one callback function defined, which is used for all requests.
*/
struct memcache;
/*
* A transaction.
*
* Each request has one callback argument defined, which is used for that request's callbacks.
*/
struct memcache_req;
/*
* Object keys
*/
struct memcache_key {
/*
* Pointer to a char buffer containing the key itself.
*
* A key is a text tring which should uniquely identify a cache entry.
*
* The length limit for a key is usually 250 characters, but this is imposed by the server side (a longer key will
* presumeably cause a CLIENT_ERROR reply).
*
* The key should presumeably also not contain any spaces, carriage returns or newlines, as these are used to
* delimit tokens in the protocol itself.
*
* The buffer does not need to be zero-terminated.
*/
char *buf;
/*
* The length of the key buffer in bytes. This does not include a NUL byte.
*
* If this is given as zero, then the length will be calculsted from buf using strlen(). Empty keys are not
* allowed, so this will result in an error if buf is an empty string.
*/
size_t len;
};
/*
* Object attributes
*/
struct memcache_obj {
/*
* An arbitrary 16-bit (32-bit for >1.2.1) that the server stores transparently.
*/
unsigned int flags;
/*
* Expiration time. If non-zero, either an offset in seconds from current time (up to 60*60*24*30 seconds, or 30d),
* or an absolute 32-bit unix timestamp.
*/
time_t exptime;
/*
* Number of bytes in the entry. This may be zero, in which case there will be no data.
*/
size_t bytes;
/*
* Used for the CMD_STORE_CAS command. An unique 64-bit value that changes if the entry is modified.
*
* Not needed for other commands, and may or may not be provided by CMD_FETCH_GET (will be set to zero).
*/
unsigned long long cas;
};
/*
* Object data
*/
struct memcache_buf {
/*
* The char buffer containing the data.
*/
char *data;
/*
* The total length of the char buffer, and thence the cache entry.
*/
size_t len;
/*
* The amount of data currently available in the buffer. This is used to provide streaming fetches.
*
* This field is *IMPORTANT*! Don't disregard it, or you *will* get incomplete data.
*/
size_t offset;
};
/*
* Available commands
*/
enum memcache_command {
MEMCACHE_CMD_INVALID,
/*
* Retrieve the value of a key from the memcached server.
*
* If the key exists, you will get a RPL_VALUE reply followed by a RPL_END reply.
* If it does not exist, you will just get a RPL_END reply.
*/
MEMCACHE_CMD_FETCH_GET,
/*
* Store this data.
*
* Returns either RPL_STORED or RPL_NOT_STORED.
*/
MEMCACHE_CMD_STORE_SET,
/*
* Store this data, but only if the server doesn't already hold data for this key.
*
* Returns either RPL_STORED or RPL_NOT_STORED.
*/
MEMCACHE_CMD_STORE_ADD,
/*
* Store this data, but only if the server does already hold data for this key.
*
* Returns either RPL_STORED or RPL_NOT_STORED.
*/
MEMCACHE_CMD_STORE_REPLACE,
/*
* Add this data to an existing key after existing data.
*
* obj.flags and obj.exptime are ignored.
*
* Returns ???
*/
MEMCACHE_CMD_STORE_APPEND,
/*
* Add this data to an existing key before existing data.
*
* obj.flags and obj.exptime are ignored.
*
* Returns ???
*/
MEMCACHE_CMD_STORE_PREPEND,
/*
* Check and Set - store this data but only if no one else had updated it since I last fetched it.
*
* obj.cas is required.
*
* Returns RPL_STORED, RPL_NOT_STORED, RPL_EXISTS (data has been modified), or RPL_NOT_FOUND (the item does not
* exist or has been deleted).
*/
MEMCACHE_CMD_STORE_CAS,
MEMCACHE_CMD_MAX,
};
/*
* Replies from the server
*/
enum memcache_reply {
MEMCACHE_RPL_INVALID,
/*
* The library sent an unknown command. This probably means the server is not compatible with said command.
*/
MEMCACHE_RPL_ERROR,
/*
* There was an error in the request that the library sent. The error message is printed out via ERROR.
*/
MEMCACHE_RPL_CLIENT_ERROR,
/*
* There was an error with the server when processing the request. The error message is printed out via ERROR.
*/
MEMCACHE_RPL_SERVER_ERROR,
// CMD_FETCH_*
/*
* The given key was found in the cache. The obj attributes are now known, and the buf data is on the way.
*/
MEMCACHE_RPL_VALUE,
/*
* No more RPL_VALUE replies will be sent. This may be the only reply sent if the key was not found.
*/
MEMCACHE_RPL_END,
// CMD_STORE_*
/*
* The object was succesfully stored in the cache.
*/
MEMCACHE_RPL_STORED,
/*
* The object was not stored in the cache.
*
* This could be for a number of reasons, perhaps the object is too large, the cache is full, the key is in the
* delete queue, or some condition imposed by the STORE_* command was not met.
*/
MEMCACHE_RPL_NOT_STORED,
/*
* The item you were trying to store with a STORE_CAS request has been modified since you last fetched it (i.e.
* obj.cas does not match).
*/
MEMCACHE_RPL_EXISTS,
/*
* The item you were trying to store with a STORE_CAS request did not exist (or has been deleted).
*/
MEMCACHE_RPL_NOT_FOUND,
MEMCACHE_RPL_MAX,
};
/*
* Request states
*/
enum memcache_req_state {
MEMCACHE_STATE_INVALID,
/*
* The request is queued, and has not been sent yet
*/
MEMCACHE_STATE_QUEUED,
/*
* The request is being sent, and the reply has not yet been received
*/
MEMCACHE_STATE_SEND,
/*
* The reply has been received.
*
* req_reply and req_obj will return a non-NULL value, but there is no reply data yet.
*/
MEMCACHE_STATE_REPLY,
/*
* The reply and part of the reply data has been received.
*
* req_reply, req_obj and req_buf will all return non-NULL values, but buf.offset will be smaller than buf.len.
*/
MEMCACHE_STATE_REPLY_DATA,
/*
* The full reply has been received.
*
* req_reply, req_obj will return a non-NULL value, but there is no reply data.
*/
MEMCACHE_STATE_DONE,
/*
* The full reply and reply data has been received.
*
* req_reply, req_obj and req_buf will all return non-NULL values, and buf.offset will be equal to buf.len.
*/
MEMCACHE_STATE_DATA_DONE,
/*
* An error has occurred.
*
* req_reply, req_obj and req_buf may or may not work.
*/
MEMCACHE_STATE_ERROR,
};
/*
* Callback used.
*
* This is called whenever the request's state changes, including when new data is received in the STATE_REPLY_DATA
* state.
*/
typedef void (*memcache_cb) (struct memcache_req *, void*);
/*
* Allocate a new memcache context for use with other methods.
*
* The given callback function is used for all requests in this context.
*/
struct memcache *memcache_alloc (memcache_cb cb_fn);
/*
* Add a server to the pool of available servers.
*
* At most <max_connections> connections will be kept open to this server, and additional requests will be queued.
*/
int memcache_add_server (struct memcache *mc, struct config_endpoint *endpoint, int max_connections);
/*
* Attempt to fetch a key from the cache.
*
* The given callback argument will be used when invoking the context's callback for this request.
*
* The state machine will work as follows:
*
* req_state multi req_reply
* ---------------------------------------------
* STATE_QUEUE ?
* STATE_SEND
* STATE_REPLY RPL_VALUE
* STATE_REPLY_DATA * RPL_VALUE
* STATE_DATA_DONE RPL_END
*
* STATE_DONE RPL_END
*
* STATE_ERROR RPL_{ERROR,CLIENT_ERROR,SERVER_ERROR}
*
* The item attributes/data can be accessed via req_obj/req_buf as described in `enum memcache_state`.
*/
struct memcache_req *memcache_fetch (struct memcache *mc, const struct memcache_key *key, void *cb_arg);
/*
* Attempt to store an item into the cache.
*
* The cmd argument can be used to specify what CMD_STORE_* command to use.
*
* The given memcache_key is copied, including the char array pointed to by buf.
* Both obj and buf are also copied, but buf.data will not be copied - the pointer must remain valid until the request is done.
*
* The given callback argument will be used when invoking the context's callback for this request.
*
* The state machine will work as follows:
*
* req_state multi req_reply
* ---------------------------------------------
* STATE_QUEUE ?
* STATE_SEND
* STATE_REPLY RPL_{STORED,NOT_STORED,EXISTS,NOT_FOUND}
* STATE_DONE RPL_{STORED,NOT_STORED,EXISTS,NOT_FOUND}
*
* STATE_ERROR RPL_{ERROR,CLIENT_ERROR,SERVER_ERROR}
*
*/
struct memcache_req *memcache_store (struct memcache *mc, enum memcache_command cmd, const struct memcache_key *key, const struct memcache_obj *obj, const struct memcache_buf *buf, void *cb_arg);
/*
* Request state.
*
* Should always return a valid value.
*/
enum memcache_req_state memcache_req_state (struct memcache_req *req);
/*
* Request command.
*
* Should always return a valid value.
*/
enum memcache_command memcache_req_cmd (struct memcache_req *req);
/*
* Request reply.
*
* Will return a valid value in the STATE_REPLY, STATE_REPLY_DATA, STATE_DONE and STATE_DATA_DONE states.
*/
enum memcache_reply memcache_req_reply (struct memcache_req *req);
/*
* Request key.
*
* Will return a valid valuein all states
*/
const struct memcache_key *keymemcache_req_key (struct memcache_req *req);
/*
* Request data.
*
* Will return a valid value in the STATE_REPLY, STATE_REPLY_DATA, STATE_DONE and STATE_DATA_DONE states.
*/
const struct memcache_obj *memcache_req_obj (struct memcache_req *req);
/*
* Request buf.
*
* Will return a valid value in the STATE_REPLY_DATA and STATE_DATA_DONE states.
*
* Note that buf.offset may be less than buf.len in the STATE_REPLY_DATA state.
*/
const struct memcache_buf *memcache_req_buf (struct memcache_req *req);
/*
* Abort a running request, regardless of what state it is in.
*
* You do not need to call req_free after this.
*
* XXX: unimplemented
*/
void memcache_req_abort (struct memcache_req *req);
/*
* Free a req that is in the STATE_DONE, STATE_DATA_DONE or STATE_ERROR state.
*/
void memcache_req_free (struct memcache_req *req);
/*
* Translate commands/replies/states into strings.
*/
const char *memcache_command_str (enum memcache_command cmd);
const char *memcache_reply_str (enum memcache_reply reply);
const char *memcache_state_str (enum memcache_req_state state);
#endif /* MEMCACHE_H */