/* -*- mode: C -*- * * Copyright (c) 2004-2005 Sean Chittenden * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * The following copyright is included as the TAILQ_* macros come from * sys/queue.h which has the following LICENSE/Copyright notice. XXX * * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 * $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $ */ #ifndef MEMCACHE_H #define MEMCACHE_H #include #include #include #include #ifdef __MEMCACHE__ # define mc_const #else # define mc_const const #endif #ifdef __cplusplus extern "C" { #endif /* Macros for the platform int definitions */ typedef uint16_t u_int16_t; typedef uint32_t u_int32_t; /* Macros for testing versions */ #define MEMCACHE_VER "1.4.0.rc2" #define MEMCACHE_VERNUM 10400 #define MEMCACHE_RELDATE 20060220 /* A handful of #define's for callbacks that discourage developers * from improperly using the interface. */ #define MCM_CALLBACK_CTXT md597f78ab4a96c3e71c3bb9fe036f37367 #define MCM_CALLBACK_KEY md5783365dee46035fa36d8d9e6fe15da0f #define MCM_CALLBACK_LEN md54c1f40392e708222b8a25a4337cd05fd #define MCM_CALLBACK_MC md5646277084faa5a0f511793a728521ef5 #define MCM_CALLBACK_PTR md57f5686851aeded9e00761d4aaaac20ee #define MCM_CALLBACK_RES md52e8a13a74753effc0f149a3ce900dc28 #define MCM_ERR_MASK md5fc9f4e2249ad88de0081136fef04defa #define MCM_ERR_FUNC_ERR_CTXT md5096953205b8982964e25927bd8154148 #define MCM_ERR_FUNC_MC_CTXT md521e67c8edeaac774b00d960e230c8686 #define MCM_KEY_VALID_KEY md58926735b19e189407440aa1ba3ab1962 #define MCM_KEY_VALID_LEN md5d6077405f1a7b35ddeac18ccc2a8f4c7 /* Our initial read(2) buffer has to be long enough to read the * first line of the response. ie: * * "VALUE #{'k' * 250} #{2 ** 15} #{2 ** 32}\r\n.length => 275 * * However, since we want to avoid the number of system calls * necessary, include trailing part of the protocol in our estimate: * * "\r\nEND\r\n".length => 7 * * Which yields a mandatory limit of 282 bytes for a successful * response. If we wish to try and get lucky with our first read(2) * call and be able to read(2) in small values without making a second * read(2) call, pad this number with a sufficiently large byte value. * If most of your keys are 512B, then a INIT_GET_BUF_SIZE of 794 * would be prudent (512 + 282). * * The default value of 4096 means that values less than 724 bytes * will always be read(2) via the first read(2) call. Increasing this * value to large values is not beneficial. If a second read(2) call * is necessary, the read(2) will be made with a sufficiently large * buffer already allocated. */ #ifndef INIT_GET_BUF_SIZE # define INIT_GET_BUF_SIZE ((size_t)4096) #endif #define MAX_KEY_LEN 250 /* Error severity levels */ #define MCM_ERR_LVL_NONE 0x00 /* INFO: Execution information */ #define MCM_ERR_LVL_INFO 0x01 /* NOTICE: Routine usage information (ie: deactivated a down server) */ #define MCM_ERR_LVL_NOTICE 0x02 /* WARN: Problem during execution (ie: invalid data of sorts) */ #define MCM_ERR_LVL_WARN 0x04 /* ERR: Severe problem during execution (ie: OS system/library call failed) */ #define MCM_ERR_LVL_ERR 0x08 /* FATAL: Unable to proceed with execution (ie: protocol ) */ #define MCM_ERR_LVL_FATAL 0x10 /* MC_ compatiblity for severity */ #define MC_ERR_LVL_INFO MCM_ERR_LVL_INFO #define MC_ERR_LVL_NOTICE MCM_ERR_LVL_NOTICE #define MC_ERR_LVL_WARN MCM_ERR_LVL_WARN #define MC_ERR_LVL_ERR MCM_ERR_LVL_ERR #define MC_ERR_LVL_FATAL MCM_ERR_LVL_FATAL /* Set various error codes */ #define MCM_ERR_NONE 0 #define MCM_ERR_ASSERT 1 #define MCM_ERR_LIB_SNPRINTF 2 #define MCM_ERR_LIB_STRTOL 3 #define MCM_ERR_LIB_STRTOLL 4 #define MCM_ERR_MC_RECONN 5 #define MCM_ERR_MC_SEND_CMD 6 #define MCM_ERR_MC_SERV_LIST 7 #define MCM_ERR_MC_STORE 8 #define MCM_ERR_MC_VALID_SERVER 9 #define MCM_ERR_MEM_MALLOC 10 #define MCM_ERR_MEM_REALLOC 11 #define MCM_ERR_NET_CONNECT 12 #define MCM_ERR_NET_HOST 13 #define MCM_ERR_PROTO 14 #define MCM_ERR_SYS_CLOSE 16 #define MCM_ERR_SYS_CONNECT 17 #define MCM_ERR_SYS_FCNTL 18 #define MCM_ERR_SYS_READ 19 #define MCM_ERR_SYS_SELECT 20 #define MCM_ERR_SYS_SETSOCKOPT 21 #define MCM_ERR_SYS_SOCKET 22 #define MCM_ERR_SYS_WRITEV 23 #define MCM_ERR_TEST 24 #define MCM_ERR_TIMEOUT 25 #define MCM_ERR_TRACE 26 #define MCM_ERR_UNKNOWN_STAT 27 /* Various values for _flags. Use their function counterparts instead * of testing these bits directly (ie: mcm_res_free_on_delete(), * mcm_res_found(), and mcm_res_attempted()). */ #define MCM_RES_FREE_ON_DELETE 0x01 #define MCM_RES_NO_FREE_ON_DELETE 0x02 #define MCM_RES_FOUND 0x04 #define MCM_RES_ATTEMPTED 0x08 #define MCM_RES_NEED_FREE_KEY 0x10 /* Aliases for MCM_RES_* #define's. Use their function counterparts * instead of testing these bits directly (ie: * mc_res_free_on_delete(), mc_res_found(), and * mc_res_attempted()). */ #define MC_RES_FREE_ON_DELETE MCM_RES_FREE_ON_DELETE #define MC_RES_NO_FREE_ON_DELETE MCM_RES_NO_FREE_ON_DELETE #define MC_RES_FOUND MCM_RES_FOUND #define MC_RES_ATTEMPTED MCM_RES_ATTEMPTED #define MC_RES_NEED_FREE_KEY MCM_RES_NEED_FREE_KEY /* A convenience macro that lets people avoid the expense of strlen(3) * if they're using a string that's defined at compile time. */ #define MCM_CSTRLEN(_str) (sizeof(_str) - 1) /* * Function authors MUST use the following two macros instead of * explicitly defining the various struct members. These MD5s *will* * change every release to ensure developers (ie, YOU!) use these * macros. Consider yourself warned. */ /* Error function signature and arguments */ #define MCM_CALLBACK_FUNC const struct memcache_ctxt *MCM_CALLBACK_CTXT, struct memcache_res *MCM_CALLBACK_RES, void *MCM_CALLBACK_PTR #define MCM_CALLBACK_SIG const struct memcache_ctxt *, struct memcache_res *, void * #define MCM_ERR_FUNC_ARGS const void *MCM_ERR_FUNC_MC_CTXT, void *MCM_ERR_FUNC_ERR_CTXT #define MCM_ERR_FUNC_SIG const void *, void * /* This see memcache.c:mcm_err_func() for an example on how to use * this. */ #define MCM_ERR_INIT_CTXT(_ctxt, _ectxt) do { \ _ctxt = (const struct memcache_ctxt *)MCM_ERR_FUNC_MC_CTXT; \ _ectxt = (struct memcache_err_ctxt *)MCM_ERR_FUNC_ERR_CTXT; \ } while (0) /* Key validation function signature and arguments */ #define MCM_KEY_VALID_FUNC_ARGS const void *MCM_KEY_VALID_CTXT, char *MCM_KEY_VALID_KEY, size_t MCM_KEY_VALID_LEN #define MCM_KEY_VALID_FUNC_SIG const void *, char *, size_t #define MCM_KEY_VALID_INIT(_ctxt, _key, _len) do { \ _ctxt = (const struct memcache_ctxt *)MCM_KEY_VALID_CTXT; \ _key = (char *)MCM_KEY_VALID_KEY; \ _len = MCM_KEY_VALID_LEN; \ } while (0) /* Hash function signature and arguments. * * Arg 1: struct memcache_ctxt * * Arg 2: struct memcache * * Arg 3: key * Arg 4: key length */ #define MCM_HASH_FUNC const void *MCM_CALLBACK_CTXT, const void *MCM_CALLBACK_MC, const char *MCM_CALLBACK_KEY, const size_t MCM_CALLBACK_LEN #define MCM_HASH_SIG const void *, const void *, const char *, const size_t #define MCM_HASH_INIT(_ctxt, _mc, _key, _len) do { \ _ctxt = (const struct memcache_ctxt *)MCM_CALLBACK_CTXT; \ _mc = (const struct memcache *)MCM_CALLBACK_MC; \ _key = (const char *)MCM_CALLBACK_KEY; \ _len = MCM_CALLBACK_LEN; \ } while (0) /* Begin various TAILQ macros */ #define TRASHIT(x) do {(x) = (void *)-1;} while (0) #define TAILQ_HEAD_INITIALIZER(head) { NULL, &(head).tqh_first } #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_FOREACH(var, head, field) \ for (var = TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field)) #define TAILQ_INIT(head) do { \ TAILQ_FIRST((head)) = NULL; \ (head)->tqh_last = &TAILQ_FIRST((head)); \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ TAILQ_NEXT((elm), field) = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if ((TAILQ_NEXT((elm), field)) != NULL) \ TAILQ_NEXT((elm), field)->field.tqe_prev = (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ TRASHIT((elm)->field.tqe_next); \ TRASHIT((elm)->field.tqe_prev); \ } while (0) /* End various TAILQ macros */ /* Load struct memcache_buf, but none of the prototypes that operate * on struct memcache_buf. */ #include /* Error handling information struct */ struct memcache_err_ctxt { /* A generic pointer not used by memcache(3), but can be used by * calling programs. */ void *misc; /* The function name that generated the error */ const char *funcname; /* The line number in source file that had the problem */ mc_const u_int32_t lineno; /* The errno. If zero, there was no errno set. */ mc_const u_int32_t errnum; /* memcache(3) specific error code */ mc_const u_int32_t errcode; /* Severity of the error (INFO, NOTICE, WARN, ERR, FATAL) */ mc_const char severity; /* Should we continue executing after we return from this error * handler? 'y'es, 'n'o, or 'a'bort? Handlers can modify this * value and change the execution of the error handler * dispatcher. */ char cont; /* An optional return code that error handlers can set to return * application specific status codes to memcache(3) callers. Where * integers are returned, this value will be returned to the caller * if it is a non-zero value. */ int32_t retcode; /* If memcache(3) causes the program to exit from an error handler, * it will use the following exit status. */ int sysexit; /* The error message that pertains to the given error code */ const char *errstr; /* Per-error specific error message (null terminated) */ const char *errmsg; /* The length of the error message. */ mc_const size_t errlen; /* Pointer to the struct memcache_ctxt of the calling function. */ const void *ctxt; }; /* The memcache API allows callers to provide their own memory * allocation routines to aid in embedability with existing programs, * libraries, programming languages, and environments that have their * own memory handling routines. */ typedef void (*mcFreeFunc)(void *mem); typedef void *(*mcMallocFunc)(const size_t size); typedef void *(*mcReallocFunc)(void *mem, const size_t size); /* See the MCM_ERR_FUNC_* macros for details on the arguments and * memcache.c:mcm_err_func() for an example of how to use this. */ typedef int32_t (*mcErrFunc)(MCM_ERR_FUNC_ARGS); /* Function prototype for scanning keys and either changing values of * invalid keys, or returning an error code. See the MCM_KEY_VALID_* * macros to gain access to the passed in values. */ typedef int32_t (*mcKeyValidFunc)(const void *, char *, size_t); /* Function prototype for hashing keys. See MCM_HASH_FUNC docs for * argument explaination. */ typedef u_int32_t (*mcHashKeyFunc)(MCM_HASH_FUNC); /* Function prototype for finding a server. * * Arg1: struct memcache_ctxt * * Arg2: struct memcache * * Arg3: hash value */ typedef void *(*mcServerFindFunc)(const void *, void *, const u_int32_t); /* This structure is only used to support multiple memory contexts. * By default, all memcache(3) API calls use the global memory * context, mcGlobalCtxt. Under special circumstances (ie, Apache), * it is necessary to have multiple memory contexts that correspond * with their various different calling libraries (PHP, PostgreSQL, * APR, etc). struct memcache_ctxt and its friends mcm_*() are used * to fulfill this goal. Under most instances, programs, use of * mc_*() is sufficient, however there is nothing wrong with defining * your own memory context. * * mcMallocAtomic is used where applicable in the event that the * calling application makes use of a garbage collection mechanism * (ie, Boehm). In non-GC'ed environments, this should be set to the * same things as mcMalloc. When allocating a struct memcache_ctxt * object, it is absolutely necessary to allocate a new context and * assign it to call mcMemNewCtxt() instead of independently creating * a struct memcache_ctxt object (ie: "struct memcache_ctxt *ctxt; * ctxt = mcMemNewCtxt(...);" == good. "struct memcache_ctxt ctxt; * bzero(ctxt, sizeof(struct memcache_ctxt));" == bad. */ struct memcache_ctxt { /* Memory context function pointers. */ mcFreeFunc mcFree; mcMallocFunc mcMalloc; mcMallocFunc mcMallocAtomic; mcReallocFunc mcRealloc; /* Error handling system. Users only need to worry about having * mcErrFunc(). All warnings, etc., go through this function. See * struct mcm_errctxt for details on information passed to the * handler. */ mcErrFunc mcErr; /* Key validation system. Certain applications need to verify the * contents of keys and ensure that various values are contained * inside of keys. If this function pointer is not null, before * keys are sent to the server, they will be passed to this function * pointer for testing/modification. All modifications to the key * must be in place and can not change the memory location or the * length of the key. */ mcKeyValidFunc mcKeyValid; /* Key hash function. */ mcHashKeyFunc mcHashKey; /* Find Server function. */ mcServerFindFunc mcServerFind; /* In non-fatal, normal operating conditions, it is plausble (indeed * likely) that certain operations are going to fail, but do so * wihin the bounds of normal operating levels for memcache(7). * Prime examples include performing an increment operation on a key * that doesn't exist. Given that such cases are to be considered * normal, it is less than desirable to fall back to the error * handling system in memcache(3). The following errnum value acts * to mimic the global errno(2) value, but on a per-context * basis. */ u_int32_t errnum; /* Internal. Pointer to the last command that was written out: the * state of this pointer is not guaranteed and its use is internal * to memcache(3). Only used when a server dies and we need to pass * around the server's last command or other data. */ struct memcache_buf *_rbuf; struct memcache_buf *_wbuf; u_int32_t _last_hash; /* Pointer to the context's error context/information. */ struct memcache_err_ctxt *ectxt; /* Determines what error levels are ignored. See mc_err_filter_*() * for the interface to this struct member. Manual manipulation is * prohibited. */ u_int32_t MCM_ERR_MASK; }; struct memcache_server { /* A generic pointer not used by memcache(3), but can be used by * calling programs. */ void *misc; /* The hostname of the server. */ char *hostname; /* Port number of the host we're connecting to. */ char *port; /* The file descriptor for this server */ int fd; /* The timeout for this server */ struct timeval tv; /* Is this particular server active or not? * * 'd' == Down Last request was unsuccessful * 'n' == No host The hostname doesn't exist * 't' == Try Haven't connected to it yet, will attempt * 'u' == Up Has been connected to successfully */ char active; /* A cached copy of the looked up host. */ struct addrinfo *hostinfo; /* The number of addresses in the cached copy. If there is more * than one per DNS entry (discouraged), we establish a connection * to them all. */ u_int32_t num_addrs; #ifdef HAVE_SELECT /* Reduces the amount of user time required when reading data. */ fd_set fds; #endif /* read(2) buffer */ struct memcache_buf *rbuf; /* write(2) buffer */ struct memcache_buf *wbuf; u_int32_t _last_hash; /* Internal. A cursor for where we are in the buffer. This changes * every time we examine a bit of data in our buffer. */ size_t soff; /* Internal. A pointer to the start of the current line in the * buffer. */ size_t startoff; /* Misc list bits */ TAILQ_ENTRY(memcache_server) entries; }; struct memcache_server_stats { pid_t pid; time_t uptime; time_t time; char *version; struct timeval rusage_user; struct timeval rusage_system; u_int32_t curr_items; u_int64_t total_items; u_int64_t bytes; u_int32_t curr_connections; u_int64_t total_connections; u_int32_t connection_structures; u_int64_t cmd_get; #ifdef SEAN_HACKS u_int64_t cmd_refresh; #endif u_int64_t cmd_set; u_int64_t get_hits; u_int64_t get_misses; #ifdef SEAN_HACKS u_int64_t refresh_hits; u_int64_t refresh_misses; #endif u_int64_t bytes_read; u_int64_t bytes_written; u_int64_t limit_maxbytes; }; /* struct memcache. Any of the bits that are commented as "Internal" * should not be twiddled with, ever. The misc member can be used by * applications and is *never* touched/accessed by memcache(3). Its * primary purpose is to aid in embedding memcache(3) in other * programming languages. */ struct memcache { /* A generic pointer not used by memcache(3), but can be used by * calling programs. */ void *misc; /* The default timeout for all servers. */ struct timeval tv; /* The number of servers in **servers. */ u_int32_t num_servers; /* An array of usable memcache_servers. */ struct memcache_server **servers; /* The complete list of servers. */ TAILQ_HEAD(memcache_server_list, memcache_server) server_list; }; struct memcache_res { /* A generic pointer not used by memcache(3), but can be used by * calling programs. */ void *misc; char *key; /* key */ size_t len; /* length of key */ u_int32_t hash; /* hash of the key */ size_t bytes; /* length of val */ void *val; /* the value */ /* If size is zero (default), the memory for val is automatically * allocated using mcMalloc(3). If size is zero, _flags has its * MC_RES_FREE_ON_DELETE bit set. * * If size is non-zero, memcache(3) assumes that the caller has set * val to an available portion of memory that is size bytes long. * memcache(3) will only populate val with as many bytes as are * specified by size (ie, it will trim the value in order to fit * into val). If size is non-zero, _flags has its * MC_RES_NO_FREE_ON_DELETE bit set by default. */ size_t size; TAILQ_ENTRY(memcache_res) entries; /* This is the client supplied flags. Please note, this flags is * very different than _flags (_flags is an internal bit and * shouldn't be read/changed, etc). */ u_int16_t flags; /* If _flags has 0x01 set, val will be free(3)'ed on when this * struct is cleaned up via mc_res_free() or the request is cleaned * up via mc_req_free(). * * If _flags has is 0x02 set, val will not be free(3)'ed when this * response or its parent request are cleaned up. * * Note: Use mc_res_free_on_delete() to set the "free on delete" * bits. */ char _flags; }; struct memcache_req { /* A generic pointer not used by memcache(3), but can be used by * calling programs. */ void *misc; TAILQ_HEAD(memcache_res_list, memcache_res) query; TAILQ_HEAD(memcache_res_cb_list, memcache_res_cb) cb; u_int16_t num_keys; }; /* Call back interface bits. memcache(3) offers a callback * mechanism wherein many get requests can be lumped together into a * single get request. After a response has been read from the * server, the callbacks are executed. * * Example: * * static void my_callback_func(MCM_CALLBACK_SIG); * static void * my_callback_func(MCM_CALLBACK_FUNC) { * struct my_struct *ptr = (struct my_struct *)MCM_CALLBACK_PTR; * struct memcache_ctxt *ctxt = MCM_CALLBACK_CTXT; * struct memcache_res *res = MCM_CALLBACK_RES; * ... * } * * and callbacks are registered like: * * struct memcache_req *req = mc_req_new(); * struct memcache_res *res = mc_req_add(req, key, key_len); * mc_res_register_fetch_cb(req, res, my_callback_func, NULL); * * or, if you want to pass an optional void * pointer: * * struct my_struct *ptr; * struct memcache_res_cb *cb = mc_res_register_fetch_cb(req, res, my_callback_func, ptr); * * Then call mc_get() like normal whenever and your callback will be * executed. Ex: * * mc_get(req); */ typedef void (*mcResCallback)(MCM_CALLBACK_FUNC); struct memcache_res_cb { void *misc; const struct memcache_ctxt *ctxt; struct memcache_req *req; struct memcache_res *res; mcResCallback cb; TAILQ_ENTRY(memcache_res_cb) entries; }; /* Adds a given key to the cache */ int mc_add(struct memcache *mc, char *key, const size_t key_len, const void *val, const size_t bytes, const time_t expire, const u_int16_t flags); /* Gets the value from memcache and allocates the data for the caller. * It is the caller's responsibility to free the returned value. * mc_get() is the preferred interface, however. */ void *mc_aget(struct memcache *mc, char *key, const size_t len); /* Gets the value from memcache and allocates the data for the caller. * It is the caller's responsibility to free the returned value. If * retlen is non-null, the size of the response will be set upon * return, or zero in the event of a failure. mc_get() is the * preferred interface, however. */ void *mc_aget2(struct memcache *mc, char *key, const size_t len, size_t *retlen); #ifdef SEAN_HACKS void *mc_alisten(struct memcache *mc, char *key, const size_t len); /* Gets the value from memcache and allocates the data for the caller. * It is the caller's responsibility to free the returned value. * mc_refresh() is the preferred interface, however. */ void *mc_arefresh(struct memcache *mc, char *key, const size_t len); #endif /* Decrements a given key */ u_int32_t mc_decr(struct memcache *mc, char *key, const size_t key_len, const u_int32_t val); /* Deletes a given key */ int mc_delete(struct memcache *mc, char *key, const size_t key_len, const time_t hold); /* Returns true if the given error level was added to the filter */ int mc_err_filter_add(const u_int32_t err_mask); /* Returns true if the given error level was removed from the filter */ int mc_err_filter_del(const u_int32_t err_mask); /* Returns the current filter mask. This interface has a questionable * future and may get removed or have its result set change from * release to release. */ u_int32_t mc_err_filter_get(void); /* Returns true if the specified error level is being filtered. */ int mc_err_filter_test(const u_int32_t err_lvl); /* Executes the error handler for testing */ void mc_err_test(void); /* Flushes all keys on a given server */ int mc_flush(struct memcache *mc, struct memcache_server *ms); /* Flushes all keys on all servers */ int mc_flush_all(struct memcache *mc); /* cleans up a memcache object. */ void mc_free(struct memcache *mc); /* mc_get() is the preferred method of accessing memcache. It accepts * multiple keys and lets a user (should they so choose) perform * memory caching to reduce the number of mcMalloc(3) calls makes. */ void mc_get(struct memcache *mc, struct memcache_req *req); /* Generates a hash value from a given key */ u_int32_t mc_hash(const struct memcache *mc, const char *key, const size_t len); /* Generates a hash value from a given key (depreciated, use mc_hash())*/ u_int32_t mc_hash_key(const char *key, const size_t len); /* Increments a given key */ u_int32_t mc_incr(struct memcache *mc, char *key, const size_t key_len, const u_int32_t val); /* Allocates a new memcache object */ struct memcache *mc_new(void); #ifdef SEAN_HACKS void mc_listen(struct memcache *mc, struct memcache_req *req); /* mc_refresh() is the preferred method of accessing memcache. It * accepts multiple keys and lets a user (should they so choose) * perform memory caching to reduce the number of mcMalloc(3) calls * makes. mc_refresh() differs from mc_get() in that mc_refresh * updates the expiration time to be now + whatever the expiration for * the item was set to. Sessions should use this as a way of noting * sessions expiring. */ void mc_refresh(struct memcache *mc, struct memcache_req *req); #endif /* Returns the release date for the library */ u_int32_t mc_reldate(void); /* Replaces a given key to the cache */ int mc_replace(struct memcache *mc, char *key, const size_t key_len, const void *val, const size_t bytes, const time_t expire, const u_int16_t flags); /* Safely adds a key to a given request (the key is mc_strdup()'ed). See mc_req_add_ref() to avoid the mc_strdup(): note the warning in mc_req_add_ref() if you decide to use the other function. */ struct memcache_res *mc_req_add(struct memcache_req *req, char *key, const size_t len); /* Adds a key to a given request. Stores a pointer to key. key can not be modified or free(3)'ed until the passed in request and the returning struct memcache_res object is done being used. */ struct memcache_res *mc_req_add_ref(struct memcache_req *req, char *key, const size_t len); /* Cleans up a given request and its subsequent responses. If _flags * has the MC_RES_FREE_ON_DELETE bit set (default), it will clean up * the value too. If _flags has MC_RES_NO_FREE_ON_DELETE set, * however, it is the caller's responsibility to free the value. To * prevent double free(3) errors, if a value is free(3)'ed before * mc_req_free() is called, set val to NULL. */ void mc_req_free(struct memcache_req *req); /* Allocates a new memcache request object. */ struct memcache_req *mc_req_new(void); /* Returns 1 if there has been an attempt by the library to fill the * struct's bits from a memcache server. Returns 0 if there has been * no attempt to fill this struct's data. */ int mc_res_attempted(const struct memcache_res *res); /* Tells the response object to free the allocated memory when it gets * cleaned up or to let the caller manage the memory. */ void mc_res_free_on_delete(struct memcache_res *res, const int free_on_delete); /* Returns 1 if the given memcache_res struct contains data that was * found and if there has been an attempt at filling the data. Return * 0 if no value was found for the key *or* there has been no attempt * at filling the data. */ int mc_res_found(const struct memcache_res *res); /* Cleans up an individual response object. Normally this is not * necessary as a call to mc_req_free() will clean up its response * objects. */ void mc_res_free(struct memcache_req *req, struct memcache_res *res); /* Registers a callback with the request so that upon completion of a * fetch request, a callback gets executed. */ int mc_res_register_fetch_cb(struct memcache_req *req, struct memcache_res *res, mcResCallback cb, void *misc); /* Marks a given server as available again. Does not reconnect to the * server, however. */ int mc_server_activate(struct memcache *mc, struct memcache_server *ms); /* Mark all servers as available. Does not connect to any servers, * but marks them as available. */ int mc_server_activate_all(struct memcache *mc); /* Disconnects from a given server and marks it as down. */ void mc_server_deactivate(struct memcache *mc, struct memcache_server *ms); /* Disconnects from a given server */ void mc_server_disconnect(struct memcache_server *ms); /* Disconnects from all servers (leaves their active flag alone). */ void mc_server_disconnect_all(const struct memcache *mc); /* When given a hash value, this function returns the appropriate * server to connect to in order to find the key. */ struct memcache_server *mc_server_find(struct memcache *mc, const u_int32_t hash); /* Adds a server to the list of available servers. By default, * servers are assumed to be available. Return codes: * * 0: success * -1: Unable to allocate a new server instance * -2: Unable to strdup hostname * -3: Unable to strdup port * -4: Unable to Unable to resolve the host, server deactivated, but added to list * -5: Unable to realloc(3) the server list, server list unchanged */ int mc_server_add(struct memcache *mc, const char *hostname, const char *port); int mc_server_add2(struct memcache *mc, const char *hostname, const size_t hostname_len, const char *port, const size_t port_len); int mc_server_add3(struct memcache *mc, struct memcache_server *ms); /* Like the above, except hostport can be in the format: * "hostname:port" or just "hostname". Ex: "127.0.0.1:11211" */ int mc_server_add4(struct memcache *mc, mc_const char *hostport); /* Same as mc_server_add4(), except with a length for hostport */ int mc_server_add5(struct memcache *mc, mc_const char *hostport, const size_t hostlen); /* Free's the space from a struct memcache_server. Use mc_free(3) * instead: only use this function if you really know what you're * doing. */ void mc_server_free(struct memcache_server *ms); /* Creates a new server struct */ struct memcache_server *mc_server_new(void); /* Cleans up a given stat's object */ void mc_server_stats_free(struct memcache_server_stats *s); /* Gets a stats object from the given server. It is the caller's * responsibility to cleanup the resulting object via * mc_server_stats_free(). */ struct memcache_server_stats *mc_server_stats(struct memcache *mc, struct memcache_server *ms); /* Set the timeout on a per server basis */ int mc_server_timeout(struct memcache_server *ms, const int sec, const int usec); /* Sets a given key */ int mc_set(struct memcache *mc, char *key, const size_t key_len, const void *val, const size_t bytes, const time_t expire, const u_int16_t flags); /* Creates a stats object for all available servers and returns the * cumulative stats. Per host-specific data is generally the same as * the last server queried. */ struct memcache_server_stats *mc_stats(struct memcache *mc); /* memcache(3)'s strdup */ char *mc_strdup(const char *str); /* memcache(3)'s strnchr(3) */ char *mc_strnchr(mc_const char *str, const int c, const size_t len); /* memcache(3)'s strndup: returns a dup of str up to len bytes long, * and pads the string with a null character (ie: len + 1). */ char *mc_strndup(const char *str, const size_t len); /* Sets the default timeout for new servers. */ void mc_timeout(struct memcache *mc, const int sec, const int usec); /* Returns a numeric version of the library */ u_int32_t mc_vernum(void); /* Returns a string version of the library */ const char *mc_version(void); /* BEGIN memory management API functions and support for multiple * memory contexts. Most users of memcache(3) should use the * functions prototyped above. The below functions should be used by * advanced developers seeking a tad bit more control over their app's * use of memcache(3), authors of language extensions, or developers * who need to write modules that exist inside of a single process * with multiple memory allocation routines (ex: Apache and PHP). */ /* The following two functions are used to setup additional memory * allocations for programs that use memcache(3), but are not using * the standard system memory management routines (ex: PostgreSQL, * Ruby, etc.) */ int mcMemSetup(mcFreeFunc freeFunc, mcMallocFunc mallocFunc, mcMallocFunc mallocAtomicFunc, mcReallocFunc reallocFunc); int mcMemGet(mcFreeFunc *freeFunc, mcMallocFunc *mallocFunc, mcMallocFunc *mallocAtomicFunc, mcReallocFunc *reallocFunc); /* Returns a pointer to the global context. */ inline struct memcache_ctxt *mc_global_ctxt(void); /* The next two functions are used to setup an error handler. */ int mcErrSetup(mcErrFunc errFunc); int mcErrSetupCtxt(struct memcache_ctxt *ctxt, mcErrFunc errFunc); int mcErrGet(mcErrFunc *errFunc); /* From here on out, the API assumes callers are providing a valid * memory context. This allows multiple memory contexts to exist * inside the same process. Very handy for PHP/Apache/APR authors, or * developers in similar situations. For maximum portability and * embedability, use of the mcm_*() functions is *strongly* * encouraged. */ /* Creates a new memory context from scratch: should be sufficient for * most applications. */ struct memcache_ctxt *mcMemNewCtxt(mcFreeFunc freeFunc, mcMallocFunc mallocFunc, mcMallocFunc mallocAtomicFunc, mcReallocFunc reallocFunc); /* Safely assigns the various function pointers to the passed in * memory context. Only needed when an application needs to change * its memory allocation routines (not sure why this would ever need * to happen, to be honest). */ int mcMemSetupCtxt(struct memcache_ctxt *ctxt, mcFreeFunc freeFunc, mcMallocFunc mallocFunc, mcMallocFunc mallocAtomicFunc, mcReallocFunc reallocFunc); /* Free's a given memcache context */ void mcMemFreeCtxt(struct memcache_ctxt *ctxt); /* Functions from here to the bottom of the section behave identically * to the above functions, except they have one additional argument, a * struct memcache_ctxt pointer. See above for documentation. */ int mcm_add(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t key_len, const void *val, const size_t bytes, const time_t expire, const u_int16_t flags); void *mcm_aget(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t len); void *mcm_aget2(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t len, size_t *retlen); #ifdef SEAN_HACKS void *mcm_alisten(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t len); void *mcm_arefresh(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t len); #endif u_int32_t mcm_decr(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t key_len, const u_int32_t val); int mcm_delete(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t key_len, const time_t hold); void mcm_err(const struct memcache_ctxt *ctxt, const u_int32_t flags, const char *funcname, const u_int32_t lineno, const u_int32_t errcode, const char *msg, const u_int32_t msglen, const u_int32_t errlvl); int mcm_err_filter_add(struct memcache_ctxt *ctxt, const u_int32_t err_mask); int mcm_err_filter_del(struct memcache_ctxt *ctxt, const u_int32_t err_mask); u_int32_t mcm_err_filter_get(const struct memcache_ctxt *ctxt); int mcm_err_filter_test(const struct memcache_ctxt *ctxt, const u_int32_t err_lvl); void mcm_err_test(const struct memcache_ctxt *ctxt); int mcm_flush(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms); int mcm_flush_all(struct memcache_ctxt *ctxt, struct memcache *mc); void mcm_free(struct memcache_ctxt *ctxt, struct memcache *mc); void mcm_get(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_req *req); u_int32_t mcm_hash(const struct memcache_ctxt *ctxt, const struct memcache *mc, const char *key, const size_t len); u_int32_t mcm_hash_key(const struct memcache_ctxt *ctxt, const char *key, const size_t len); u_int32_t mcm_incr(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t key_len, const u_int32_t val); struct memcache *mcm_new(struct memcache_ctxt *ctxt); #ifdef SEAN_HACKS void mcm_listen(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_req *req); void mcm_refresh(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_req *req); #endif u_int32_t mcm_reldate(const struct memcache_ctxt *ctxt); int mcm_replace(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t key_len, const void *val, const size_t bytes, const time_t expire, const u_int16_t flags); struct memcache_res *mcm_req_add(const struct memcache_ctxt *ctxt, struct memcache_req *req, char *key, const size_t len); struct memcache_res *mcm_req_add_ref(const struct memcache_ctxt *ctxt, struct memcache_req *req, char *key, const size_t len); void mcm_req_free(const struct memcache_ctxt *ctxt, struct memcache_req *req); struct memcache_req *mcm_req_new(const struct memcache_ctxt *ctxt); int mcm_res_attempted(const struct memcache_ctxt *ctxt, const struct memcache_res *res); int mcm_res_found(const struct memcache_ctxt *ctxt, const struct memcache_res *res); void mcm_res_free(const struct memcache_ctxt *ctxt, struct memcache_req *req, struct memcache_res *res); void mcm_res_free_on_delete(const struct memcache_ctxt *ctxt, struct memcache_res *res, const int free_on_delete); int mcm_res_register_fetch_cb(struct memcache_ctxt *ctxt, struct memcache_req *req, struct memcache_res *res, mcResCallback callback, void *misc); int mcm_server_activate(const struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms); int mcm_server_activate_all(const struct memcache_ctxt *ctxt, struct memcache *mc); int mcm_server_add(struct memcache_ctxt *ctxt, struct memcache *mc, const char *hostname, const char *port); int mcm_server_add2(struct memcache_ctxt *ctxt, struct memcache *mc, const char *hostname, const size_t hostname_len, const char *port, const size_t port_len); int mcm_server_add3(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms); int mcm_server_add4(struct memcache_ctxt *ctxt, struct memcache *mc, mc_const char *hostport); int mcm_server_add5(struct memcache_ctxt *ctxt, struct memcache *mc, mc_const char *hostport, const size_t hostlen); void mcm_server_deactivate(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms); void mcm_server_disconnect(const struct memcache_ctxt *ctxt, struct memcache_server *ms); void mcm_server_disconnect_all(const struct memcache_ctxt *ctxt, const struct memcache *mc); struct memcache_server *mcm_server_find(const struct memcache_ctxt *ctxt, struct memcache *mc, const u_int32_t hash); void mcm_server_free(struct memcache_ctxt *ctxt, struct memcache_server *ms); struct memcache_server *mcm_server_new(struct memcache_ctxt *ctxt); void mcm_server_stats_free(const struct memcache_ctxt *ctxt, struct memcache_server_stats *s); struct memcache_server_stats *mcm_server_stats(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms); int mcm_server_timeout(const struct memcache_ctxt *ctxt, struct memcache_server *ms, const int sec, const int usec); int mcm_set(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t key_len, const void *val, const size_t bytes, const time_t expire, const u_int16_t flags); struct memcache_server_stats *mcm_stats(struct memcache_ctxt *ctxt, struct memcache *mc); char *mcm_strdup(const struct memcache_ctxt *ctxt, const char *str); char *mcm_strnchr(const struct memcache_ctxt *ctxt, mc_const char *str, const int c, const size_t len); char *mcm_strndup(const struct memcache_ctxt *ctxt, const char *str, const size_t len); char *mcm_strnstr(const struct memcache_ctxt *ctxt, mc_const char *s, const char *find, size_t slen); void mcm_timeout(const struct memcache_ctxt *ctxt, struct memcache *mc, const int sec, const int usec); u_int32_t mcm_vernum(const struct memcache_ctxt *ctxt); const char *mcm_version(const struct memcache_ctxt *ctxt); /* END memory management API functions */ /* BEGIN - Error handling convenience macros */ #define ERR_FLAG 0x1 #define WARN_FLAG 0x2 #define NO_ERRNO_FLAG 0x4 #define MCM_ERR(_code) mcm_err(ctxt, ERR_FLAG, __FUNCTION__, __LINE__, _code, NULL, 0, 0) #define MCM_ERR_MSG(_code, _msg) mcm_err(ctxt, ERR_FLAG, __FUNCTION__, __LINE__, _code, _msg, (_msg != NULL ? strlen(_msg) : 0), 0) #define MCM_ERR_MSG_LVL(_code, _msg, _lvl) mcm_err(ctxt, ERR_FLAG, __FUNCTION__, __LINE__, _code, _msg, (_msg != NULL ? strlen(_msg) : 0), _lvl) #define MCM_ERRX(_code) mcm_err(ctxt, ERR_FLAG|NO_ERRNO_FLAG, __FUNCTION__, __LINE__, _code, NULL, 0, 0) #define MCM_ERRX_MSG_LVL(_code, _msg, _lvl) mcm_err(ctxt, ERR_FLAG|NO_ERRNO_FLAG, __FUNCTION__, __LINE__, _code, _msg, (_msg != NULL ? strlen(_msg) : 0), _lvl) #define MCM_ERRX_MSG(_code, _msg) mcm_err(ctxt, ERR_FLAG|NO_ERRNO_FLAG, __FUNCTION__, __LINE__, _code, _msg, (_msg != NULL ? strlen(_msg) : 0), 0) #define MCM_WARNX(_code, _msg) mcm_err(ctxt, WARN_FLAG|NO_ERRNO_FLAG, __FUNCTION__, __LINE__, _code, _msg, (_msg != NULL ? strlen(_msg) : 0), 0) #define MCM_WARN_MSG(_code, _msg) mcm_err(ctxt, WARN_FLAG, __FUNCTION__, __LINE__, _code, _msg, (_msg != NULL ? strlen(_msg) : 0), 0) #define MCM_WARN_MSGLEN(_code, _m, _l) mcm_err(ctxt, WARN_FLAG, __FUNCTION__, __LINE__, _code, _m, _l, 0) #define MCM_WARN_MSG_LVL(_code, _msg, _lvl) mcm_err(ctxt, WARN_FLAG, __FUNCTION__, __LINE__, _code, _msg, (_msg != NULL ? strlen(_msg) : 0), _lvl) #define MCM_WARNX_MSG(_code, _msg) mcm_err(ctxt, WARN_FLAG|NO_ERRNO_FLAG, __FUNCTION__, __LINE__, _code, _msg, (_msg != NULL ? strlen(_msg) : 0), 0) #define MCM_WARNX_MSGLEN(_code, _m, _l) mcm_err(ctxt, WARN_FLAG|NO_ERRNO_FLAG, __FUNCTION__, __LINE__, _code, _m, _l, 0) #define MCM_RET_CODE(_v) (ctxt->ectxt->retcode != 0 ? ctxt->ectxt->retcode : _v) /* END - Error handling convenience macros */ /* APIs that should be implemented: */ /* Resets all DNS entries */ void mc_server_reset_all_dns(struct memcache *mc); /* Resets only one host's DNS cache */ void mc_server_reset_dns(struct memcache *mc, const char *hostname, const int port); #ifdef TCP_NODELAY /* Enable/disable TCP_NODELAY */ void mc_nodelay_enable(struct memcache *mc, const int enable); /* Enable/disable TCP_NODELAY for a given server */ void mc_server_nodelay_enable(struct memcache_server *ms, const int enable); #endif /* Set the number of seconds you're willing to wait in total for a * response. ??? */ #ifdef __cplusplus } #endif #endif