99 #define DICT_MC_DEF_HOST "localhost"
100 #define DICT_MC_DEF_PORT "11211"
101 #define DICT_MC_DEF_MEMCACHE "inet:" DICT_MC_DEF_HOST ":" DICT_MC_DEF_PORT
102 #define DICT_MC_DEF_KEY_FMT "%s"
103 #define DICT_MC_DEF_MC_TTL 3600
104 #define DICT_MC_DEF_MC_TIMEOUT 2
105 #define DICT_MC_DEF_MC_FLAGS 0
106 #define DICT_MC_DEF_MAX_TRY 2
107 #define DICT_MC_DEF_MAX_LINE 1024
108 #define DICT_MC_DEF_MAX_DATA 10240
109 #define DICT_MC_DEF_ERR_PAUSE 1
111 #define DICT_MC_NAME_MEMCACHE "memcache"
112 #define DICT_MC_NAME_BACKUP "backup"
113 #define DICT_MC_NAME_KEY_FMT "key_format"
114 #define DICT_MC_NAME_MC_TTL "ttl"
115 #define DICT_MC_NAME_MC_TIMEOUT "timeout"
116 #define DICT_MC_NAME_MC_FLAGS "flags"
117 #define DICT_MC_NAME_MAX_TRY "max_try"
118 #define DICT_MC_NAME_MAX_LINE "line_size_limit"
119 #define DICT_MC_NAME_MAX_DATA "data_size_limit"
120 #define DICT_MC_NAME_ERR_PAUSE "retry_pause"
125 #define STR(x) vstring_str(x)
126 #define LEN(x) VSTRING_LEN(x)
132 static int dict_memcache_set(
DICT_MC *dict_mc,
const char *value,
int ttl)
136 size_t data_len = strlen(value);
143 msg_warn(
"database %s:%s: data for key %s is too long (%s=%d) "
150 for (count = 0; count < dict_mc->
max_tries; count++) {
157 ttl, (
long) data_len) < 0
162 msg_warn(errno ?
"database %s:%s: I/O error: %m" :
163 "database %s:%s: I/O error",
165 }
else if (strcmp(
STR(dict_mc->
clnt_buf),
"STORED") != 0) {
167 msg_warn(
"database %s:%s: update failed: %.30s",
181 static const char *dict_memcache_get(
DICT_MC *dict_mc)
187 for (count = 0; count < dict_mc->
max_tries; count++) {
195 msg_warn(errno ?
"database %s:%s: I/O error: %m" :
196 "database %s:%s: I/O error",
198 }
else if (strcmp(
STR(dict_mc->
clnt_buf),
"END") == 0) {
202 "VALUE %*s %*s %ld", &todo) != 1
203 || todo < 0 || todo > dict_mc->
max_data) {
205 msg_warn(
"%s: unexpected memcache server reply: %.30s",
209 msg_warn(
"%s: EOF receiving memcache server reply",
225 static int dict_memcache_del(
DICT_MC *dict_mc)
230 for (count = 0; count < dict_mc->
max_tries; count++) {
238 msg_warn(errno ?
"database %s:%s: I/O error: %m" :
239 "database %s:%s: I/O error",
241 }
else if (strcmp(
STR(dict_mc->
clnt_buf),
"DELETED") == 0) {
244 }
else if (strcmp(
STR(dict_mc->
clnt_buf),
"NOT_FOUND") == 0) {
249 msg_warn(
"database %s:%s: delete failed: %.30s",
260 static ssize_t dict_memcache_prepare_key(
DICT_MC *dict_mc,
const char *name)
276 #define DICT_MC_NO_KEY (0)
277 #define DICT_MC_NO_QUOTING ((void (*)(DICT *, const char *, VSTRING *)) 0)
298 static int dict_memcache_valid_key(
DICT_MC *dict_mc,
300 const char *operation,
301 void (*log_func) (
const char *,...))
306 #define DICT_MC_SKIP(why) do { \
307 if (msg_verbose || log_func != msg_info) \
308 log_func("%s: skipping %s for name \"%s\": %s", \
309 dict_mc->dict.name, operation, name, (why)); \
310 DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, 0); \
319 if (dict_memcache_prepare_key(dict_mc, name) == 0)
321 for (cp = (
unsigned char *)
STR(dict_mc->
key_buf); *cp; cp++)
322 if (isascii(*cp) && isspace(*cp))
330 static int dict_memcache_update(
DICT *dict,
const char *name,
333 const char *myname =
"dict_memcache_update";
342 if (dict_memcache_valid_key(dict_mc, name,
"update",
msg_warn) == 0)
348 upd_res = dict_memcache_set(dict_mc, value, dict_mc->
mc_ttl);
355 upd_res = backup->
update(backup, name, value);
359 msg_info(
"%s: %s: update key \"%s\"(%s) => \"%s\" %s",
361 value, dict_mc->
error ?
"(memcache error)" : (backup
362 && backup->
error) ?
"(backup error)" :
"(no error)");
369 static const char *dict_memcache_lookup(
DICT *dict,
const char *name)
371 const char *myname =
"dict_memcache_lookup";
380 if (dict_memcache_valid_key(dict_mc, name,
"lookup",
msg_info) == 0)
386 retval = dict_memcache_get(dict_mc);
396 retval = backup->
lookup(backup, name);
400 dict_memcache_set(dict_mc, retval, dict_mc->
mc_ttl);
404 msg_info(
"%s: %s: key \"%s\"(%s) => %s",
406 retval ? retval : dict_mc->
error ?
"(memcache error)" :
407 (backup && backup->
error) ?
"(backup error)" :
"(not found)");
414 static int dict_memcache_delete(
DICT *dict,
const char *name)
416 const char *myname =
"dict_memcache_delete";
425 if (dict_memcache_valid_key(dict_mc, name,
"delete",
msg_info) == 0)
432 del_res = dict_memcache_del(dict_mc);
439 del_res = backup->
delete(backup, name);
443 msg_info(
"%s: %s: delete key \"%s\"(%s) => %s",
445 dict_mc->
error ?
"(memcache error)" : (backup
446 && backup->
error) ?
"(backup error)" :
"(no error)");
453 static int dict_memcache_sequence(
DICT *dict,
int function,
const char **key,
456 const char *myname =
"dict_memcache_sequence";
462 msg_warn(
"database %s:%s: first/next support requires backup database",
466 seq_res = backup->
sequence(backup,
function, key, value);
468 msg_info(
"%s: %s: key \"%s\" => %s",
469 myname, dict_mc->
dict.
name, *key ? *key :
"(not found)",
470 *value ? *value : backup->
error ?
"(backup error)" :
478 static void dict_memcache_close(
DICT *dict)
511 "%s:%s map is not allowed for security-sensitive data",
513 open_flags &= (O_RDONLY | O_RDWR | O_WRONLY | O_APPEND);
514 if (open_flags != O_RDONLY && open_flags != O_RDWR)
516 "%s:%s map requires O_RDONLY or O_RDWR access mode",
524 "open %s: %m", name));
532 if (open_flags == O_RDWR) {
537 dict_mc->
dict.
close = dict_memcache_close;
598 return (&dict_mc->
dict);
VSTREAM * auto_clnt_access(AUTO_CLNT *auto_clnt)
#define DICT_MC_DEF_KEY_FMT
#define DICT_MC_DEF_MC_FLAGS
#define DICT_MC_DEF_ERR_PAUSE
#define DICT_MC_SKIP(why)
#define DICT_FLAG_NO_UNAUTH
void(* close)(struct DICT *)
#define DICT_MC_NAME_MAX_DATA
int(* delete)(struct DICT *, const char *)
#define DICT_MC_NAME_MC_FLAGS
#define DICT_MC_DEF_MAX_TRY
DICT * dict_open(const char *, int, int)
int cfg_get_int(const CFG_PARSER *parser, const char *name, int defval, int min, int max)
#define DICT_FLAG_MULTI_WRITER
#define DICT_MC_DEF_MC_TTL
#define DICT_FLAG_FOLD_FIX
void db_common_free_ctx(void *ctxPtr)
DICT * dict_memcache_open(const char *name, int open_flags, int dict_flags)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
int db_common_dict_partial(void *ctxPtr)
#define DICT_MC_DEF_MAX_LINE
int(* update)(struct DICT *, const char *, const char *)
#define DICT_STAT_SUCCESS
#define DICT_MC_NAME_MC_TIMEOUT
void db_common_parse_domain(CFG_PARSER *parser, void *ctxPtr)
#define DICT_MC_NO_QUOTING
int db_common_expand(void *ctxArg, const char *format, const char *value, const char *key, VSTRING *result, db_quote_callback_t quote_func)
AUTO_CLNT * auto_clnt_create(const char *service, int timeout, int max_idle, int max_ttl)
int memcache_fwrite(VSTREAM *stream, const char *cp, ssize_t todo)
#define DICT_MC_NAME_KEY_FMT
#define VSTRING_RESET(vp)
void msg_warn(const char *fmt,...)
int memcache_printf(VSTREAM *stream, const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
#define DICT_MC_DEF_MEMCACHE
int db_common_check_domain(void *ctxPtr, const char *addr)
char * lowercase(char *string)
#define DICT_MC_NAME_ERR_PAUSE
void auto_clnt_free(AUTO_CLNT *auto_clnt)
const char *(* lookup)(struct DICT *, const char *)
#define DICT_ERR_VAL_RETURN(dict, err, val)
#define DICT_MC_NAME_MEMCACHE
char * cfg_get_str(const CFG_PARSER *parser, const char *name, const char *defval, int min, int max)
#define DICT_MC_NAME_BACKUP
#define DICT_MC_DEF_MAX_DATA
#define DICT_FLAG_PATTERN
CFG_PARSER * cfg_parser_free(CFG_PARSER *parser)
#define DICT_TYPE_MEMCACHE
CFG_PARSER * cfg_parser_alloc(const char *pname)
void auto_clnt_recover(AUTO_CLNT *auto_clnt)
VSTRING * vstring_free(VSTRING *vp)
int memcache_fread(VSTREAM *stream, VSTRING *buf, ssize_t todo)
int db_common_parse(DICT *dict, void **ctxPtr, const char *format, int query)
#define DICT_MC_NAME_MAX_LINE
#define DICT_MC_DEF_MC_TIMEOUT
int(* sequence)(struct DICT *, int, const char **, const char **)
DICT * dict_alloc(const char *, const char *, ssize_t)
int memcache_get(VSTREAM *stream, VSTRING *vp, ssize_t bound)
#define DICT_MC_NAME_MAX_TRY
DICT * dict_surrogate(const char *dict_type, const char *dict_name, int open_flags, int dict_flags, const char *fmt,...)
#define DICT_MC_NAME_MC_TTL
void msg_info(const char *fmt,...)