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