Postfix3.3.1
dict_memcache.c
[詳解]
1 /*++
2 /* NAME
3 /* dict_memcache 3
4 /* SUMMARY
5 /* dictionary interface to memcaches
6 /* SYNOPSIS
7 /* #include <dict_memcache.h>
8 /*
9 /* DICT *dict_memcache_open(name, open_flags, dict_flags)
10 /* const char *name;
11 /* int open_flags;
12 /* int dict_flags;
13 /* DESCRIPTION
14 /* dict_memcache_open() opens a memcache, providing
15 /* a dictionary interface for Postfix key->value mappings.
16 /* The result is a pointer to the installed dictionary.
17 /*
18 /* Configuration parameters are described in memcache_table(5).
19 /*
20 /* Arguments:
21 /* .IP name
22 /* The path to the Postfix memcache configuration file.
23 /* .IP open_flags
24 /* O_RDONLY or O_RDWR. This function ignores flags that don't
25 /* specify a read, write or append mode.
26 /* .IP dict_flags
27 /* See dict_open(3).
28 /* SEE ALSO
29 /* dict(3) generic dictionary manager
30 /* HISTORY
31 /* .ad
32 /* .fi
33 /* The first memcache client for Postfix was written by Omar
34 /* Kilani, and was based on libmemcache. The current
35 /* implementation implements the memcache protocol directly,
36 /* and bears no resemblance to earlier work.
37 /* AUTHOR(S)
38 /* Wietse Venema
39 /* IBM T.J. Watson Research
40 /* P.O. Box 704
41 /* Yorktown Heights, NY 10598, USA
42 /*--*/
43 
44 /* System library. */
45 
46 #include <sys_defs.h>
47 #include <errno.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <stdio.h> /* XXX sscanf() */
51 
52 /* Utility library. */
53 
54 #include <msg.h>
55 #include <mymalloc.h>
56 #include <dict.h>
57 #include <vstring.h>
58 #include <stringops.h>
59 #include <auto_clnt.h>
60 #include <vstream.h>
61 
62 /* Global library. */
63 
64 #include <cfg_parser.h>
65 #include <db_common.h>
66 #include <memcache_proto.h>
67 
68 /* Application-specific. */
69 
70 #include <dict_memcache.h>
71 
72  /*
73  * Structure of one memcache dictionary handle.
74  */
75 typedef struct {
76  DICT dict; /* parent class */
77  CFG_PARSER *parser; /* common parameter parser */
78  void *dbc_ctxt; /* db_common context */
79  char *key_format; /* query key translation */
80  int timeout; /* client timeout */
81  int mc_ttl; /* memcache update expiration */
82  int mc_flags; /* memcache update flags */
83  int err_pause; /* delay between errors */
84  int max_tries; /* number of tries */
85  int max_line; /* reply line limit */
86  int max_data; /* reply data limit */
87  char *memcache; /* memcache server spec */
88  AUTO_CLNT *clnt; /* memcache client stream */
89  VSTRING *clnt_buf; /* memcache client buffer */
90  VSTRING *key_buf; /* lookup key */
91  VSTRING *res_buf; /* lookup result */
92  int error; /* memcache dict_errno */
93  DICT *backup; /* persistent backup */
94 } DICT_MC;
95 
96  /*
97  * Memcache option defaults and names.
98  */
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
110 
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"
121 
122  /*
123  * SLMs.
124  */
125 #define STR(x) vstring_str(x)
126 #define LEN(x) VSTRING_LEN(x)
127 
128 /*#define msg_verbose 1*/
129 
130 /* dict_memcache_set - set memcache key/value */
131 
132 static int dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl)
133 {
134  VSTREAM *fp;
135  int count;
136  size_t data_len = strlen(value);
137 
138  /*
139  * Return a permanent error if we can't store this data. This results in
140  * loss of information.
141  */
142  if (data_len > dict_mc->max_data) {
143  msg_warn("database %s:%s: data for key %s is too long (%s=%d) "
144  "-- not stored", DICT_TYPE_MEMCACHE, dict_mc->dict.name,
145  STR(dict_mc->key_buf), DICT_MC_NAME_MAX_DATA,
146  dict_mc->max_data);
147  /* Not stored! */
149  }
150  for (count = 0; count < dict_mc->max_tries; count++) {
151  if (count > 0)
152  sleep(dict_mc->err_pause);
153  if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
154  break;
155  } else if (memcache_printf(fp, "set %s %d %d %ld",
156  STR(dict_mc->key_buf), dict_mc->mc_flags,
157  ttl, (long) data_len) < 0
158  || memcache_fwrite(fp, value, strlen(value)) < 0
159  || memcache_get(fp, dict_mc->clnt_buf,
160  dict_mc->max_line) < 0) {
161  if (count > 0)
162  msg_warn(errno ? "database %s:%s: I/O error: %m" :
163  "database %s:%s: I/O error",
164  DICT_TYPE_MEMCACHE, dict_mc->dict.name);
165  } else if (strcmp(STR(dict_mc->clnt_buf), "STORED") != 0) {
166  if (count > 0)
167  msg_warn("database %s:%s: update failed: %.30s",
168  DICT_TYPE_MEMCACHE, dict_mc->dict.name,
169  STR(dict_mc->clnt_buf));
170  } else {
171  /* Victory! */
173  }
174  auto_clnt_recover(dict_mc->clnt);
175  }
177 }
178 
179 /* dict_memcache_get - get memcache key/value */
180 
181 static const char *dict_memcache_get(DICT_MC *dict_mc)
182 {
183  VSTREAM *fp;
184  long todo;
185  int count;
186 
187  for (count = 0; count < dict_mc->max_tries; count++) {
188  if (count > 0)
189  sleep(dict_mc->err_pause);
190  if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
191  break;
192  } else if (memcache_printf(fp, "get %s", STR(dict_mc->key_buf)) < 0
193  || memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0) {
194  if (count > 0)
195  msg_warn(errno ? "database %s:%s: I/O error: %m" :
196  "database %s:%s: I/O error",
197  DICT_TYPE_MEMCACHE, dict_mc->dict.name);
198  } else if (strcmp(STR(dict_mc->clnt_buf), "END") == 0) {
199  /* Not found. */
200  DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, (char *) 0);
201  } else if (sscanf(STR(dict_mc->clnt_buf),
202  "VALUE %*s %*s %ld", &todo) != 1
203  || todo < 0 || todo > dict_mc->max_data) {
204  if (count > 0)
205  msg_warn("%s: unexpected memcache server reply: %.30s",
206  dict_mc->dict.name, STR(dict_mc->clnt_buf));
207  } else if (memcache_fread(fp, dict_mc->res_buf, todo) < 0) {
208  if (count > 0)
209  msg_warn("%s: EOF receiving memcache server reply",
210  dict_mc->dict.name);
211  } else {
212  /* Victory! */
213  if (memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0
214  || strcmp(STR(dict_mc->clnt_buf), "END") != 0)
215  auto_clnt_recover(dict_mc->clnt);
216  DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, STR(dict_mc->res_buf));
217  }
218  auto_clnt_recover(dict_mc->clnt);
219  }
220  DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_RETRY, (char *) 0);
221 }
222 
223 /* dict_memcache_del - delete memcache key/value */
224 
225 static int dict_memcache_del(DICT_MC *dict_mc)
226 {
227  VSTREAM *fp;
228  int count;
229 
230  for (count = 0; count < dict_mc->max_tries; count++) {
231  if (count > 0)
232  sleep(dict_mc->err_pause);
233  if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
234  break;
235  } else if (memcache_printf(fp, "delete %s", STR(dict_mc->key_buf)) < 0
236  || memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0) {
237  if (count > 0)
238  msg_warn(errno ? "database %s:%s: I/O error: %m" :
239  "database %s:%s: I/O error",
240  DICT_TYPE_MEMCACHE, dict_mc->dict.name);
241  } else if (strcmp(STR(dict_mc->clnt_buf), "DELETED") == 0) {
242  /* Victory! */
244  } else if (strcmp(STR(dict_mc->clnt_buf), "NOT_FOUND") == 0) {
245  /* Not found! */
247  } else {
248  if (count > 0)
249  msg_warn("database %s:%s: delete failed: %.30s",
250  DICT_TYPE_MEMCACHE, dict_mc->dict.name,
251  STR(dict_mc->clnt_buf));
252  }
253  auto_clnt_recover(dict_mc->clnt);
254  }
256 }
257 
258 /* dict_memcache_prepare_key - prepare lookup key */
259 
260 static ssize_t dict_memcache_prepare_key(DICT_MC *dict_mc, const char *name)
261 {
262 
263  /*
264  * Optionally case-fold the search string.
265  */
266  if (dict_mc->dict.flags & DICT_FLAG_FOLD_FIX) {
267  if (dict_mc->dict.fold_buf == 0)
268  dict_mc->dict.fold_buf = vstring_alloc(10);
269  vstring_strcpy(dict_mc->dict.fold_buf, name);
270  name = lowercase(STR(dict_mc->dict.fold_buf));
271  }
272 
273  /*
274  * Optionally expand the query key format.
275  */
276 #define DICT_MC_NO_KEY (0)
277 #define DICT_MC_NO_QUOTING ((void (*)(DICT *, const char *, VSTRING *)) 0)
278 
279  if (dict_mc->key_format != 0
280  && strcmp(dict_mc->key_format, DICT_MC_DEF_KEY_FMT) != 0) {
281  VSTRING_RESET(dict_mc->key_buf);
282  if (db_common_expand(dict_mc->dbc_ctxt, dict_mc->key_format,
283  name, DICT_MC_NO_KEY, dict_mc->key_buf,
284  DICT_MC_NO_QUOTING) == 0)
285  return (0);
286  } else {
287  vstring_strcpy(dict_mc->key_buf, name);
288  }
289 
290  /*
291  * The length indicates whether the expansion is empty or not.
292  */
293  return (LEN(dict_mc->key_buf));
294 }
295 
296 /* dict_memcache_valid_key - validate key */
297 
298 static int dict_memcache_valid_key(DICT_MC *dict_mc,
299  const char *name,
300  const char *operation,
301  void (*log_func) (const char *,...))
302 {
303  unsigned char *cp;
304  int rc;
305 
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); \
311  } while (0)
312 
313  if (*name == 0)
314  DICT_MC_SKIP("empty lookup key");
315  if ((rc = db_common_check_domain(dict_mc->dbc_ctxt, name)) == 0)
316  DICT_MC_SKIP("domain mismatch");
317  if (rc < 0)
318  DICT_ERR_VAL_RETURN(dict_mc, rc, 0);
319  if (dict_memcache_prepare_key(dict_mc, name) == 0)
320  DICT_MC_SKIP("empty lookup key expansion");
321  for (cp = (unsigned char *) STR(dict_mc->key_buf); *cp; cp++)
322  if (isascii(*cp) && isspace(*cp))
323  DICT_MC_SKIP("name contains space");
324 
325  DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, 1);
326 }
327 
328 /* dict_memcache_update - update memcache */
329 
330 static int dict_memcache_update(DICT *dict, const char *name,
331  const char *value)
332 {
333  const char *myname = "dict_memcache_update";
334  DICT_MC *dict_mc = (DICT_MC *) dict;
335  DICT *backup = dict_mc->backup;
336  int upd_res;
337 
338  /*
339  * Skip updates with an inapplicable key, noisily. This results in loss
340  * of information.
341  */
342  if (dict_memcache_valid_key(dict_mc, name, "update", msg_warn) == 0)
343  DICT_ERR_VAL_RETURN(dict, dict_mc->error, DICT_STAT_FAIL);
344 
345  /*
346  * Update the memcache first.
347  */
348  upd_res = dict_memcache_set(dict_mc, value, dict_mc->mc_ttl);
349  dict->error = dict_mc->error;
350 
351  /*
352  * Update the backup database last.
353  */
354  if (backup) {
355  upd_res = backup->update(backup, name, value);
356  dict->error = backup->error;
357  }
358  if (msg_verbose)
359  msg_info("%s: %s: update key \"%s\"(%s) => \"%s\" %s",
360  myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
361  value, dict_mc->error ? "(memcache error)" : (backup
362  && backup->error) ? "(backup error)" : "(no error)");
363 
364  return (upd_res);
365 }
366 
367 /* dict_memcache_lookup - lookup memcache */
368 
369 static const char *dict_memcache_lookup(DICT *dict, const char *name)
370 {
371  const char *myname = "dict_memcache_lookup";
372  DICT_MC *dict_mc = (DICT_MC *) dict;
373  DICT *backup = dict_mc->backup;
374  const char *retval;
375 
376  /*
377  * Skip lookups with an inapplicable key, silently. This is just asking
378  * for information that cannot exist.
379  */
380  if (dict_memcache_valid_key(dict_mc, name, "lookup", msg_info) == 0)
381  DICT_ERR_VAL_RETURN(dict, dict_mc->error, (char *) 0);
382 
383  /*
384  * Search the memcache first.
385  */
386  retval = dict_memcache_get(dict_mc);
387  dict->error = dict_mc->error;
388 
389  /*
390  * Search the backup database last. Update the memcache if the data is
391  * found.
392  */
393  if (backup) {
394  backup->error = 0;
395  if (retval == 0) {
396  retval = backup->lookup(backup, name);
397  dict->error = backup->error;
398  /* Update the cache. */
399  if (retval != 0)
400  dict_memcache_set(dict_mc, retval, dict_mc->mc_ttl);
401  }
402  }
403  if (msg_verbose)
404  msg_info("%s: %s: key \"%s\"(%s) => %s",
405  myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
406  retval ? retval : dict_mc->error ? "(memcache error)" :
407  (backup && backup->error) ? "(backup error)" : "(not found)");
408 
409  return (retval);
410 }
411 
412 /* dict_memcache_delete - delete memcache entry */
413 
414 static int dict_memcache_delete(DICT *dict, const char *name)
415 {
416  const char *myname = "dict_memcache_delete";
417  DICT_MC *dict_mc = (DICT_MC *) dict;
418  DICT *backup = dict_mc->backup;
419  int del_res;
420 
421  /*
422  * Skip lookups with an inapplicable key, noisily. This is just deleting
423  * information that cannot exist.
424  */
425  if (dict_memcache_valid_key(dict_mc, name, "delete", msg_info) == 0)
426  DICT_ERR_VAL_RETURN(dict, dict_mc->error, dict_mc->error ?
428 
429  /*
430  * Update the memcache first.
431  */
432  del_res = dict_memcache_del(dict_mc);
433  dict->error = dict_mc->error;
434 
435  /*
436  * Update the persistent database last.
437  */
438  if (backup) {
439  del_res = backup->delete(backup, name);
440  dict->error = backup->error;
441  }
442  if (msg_verbose)
443  msg_info("%s: %s: delete key \"%s\"(%s) => %s",
444  myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
445  dict_mc->error ? "(memcache error)" : (backup
446  && backup->error) ? "(backup error)" : "(no error)");
447 
448  return (del_res);
449 }
450 
451 /* dict_memcache_sequence - first/next lookup */
452 
453 static int dict_memcache_sequence(DICT *dict, int function, const char **key,
454  const char **value)
455 {
456  const char *myname = "dict_memcache_sequence";
457  DICT_MC *dict_mc = (DICT_MC *) dict;
458  DICT *backup = dict_mc->backup;
459  int seq_res;
460 
461  if (backup == 0) {
462  msg_warn("database %s:%s: first/next support requires backup database",
463  DICT_TYPE_MEMCACHE, dict_mc->dict.name);
464  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
465  } else {
466  seq_res = backup->sequence(backup, function, key, value);
467  if (msg_verbose)
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)" :
471  "(not found)");
472  DICT_ERR_VAL_RETURN(dict, backup->error, seq_res);
473  }
474 }
475 
476 /* dict_memcache_close - close memcache */
477 
478 static void dict_memcache_close(DICT *dict)
479 {
480  DICT_MC *dict_mc = (DICT_MC *) dict;
481 
482  cfg_parser_free(dict_mc->parser);
483  db_common_free_ctx(dict_mc->dbc_ctxt);
484  if (dict_mc->key_format)
485  myfree(dict_mc->key_format);
486  myfree(dict_mc->memcache);
487  auto_clnt_free(dict_mc->clnt);
488  vstring_free(dict_mc->clnt_buf);
489  vstring_free(dict_mc->key_buf);
490  vstring_free(dict_mc->res_buf);
491  if (dict->fold_buf)
492  vstring_free(dict->fold_buf);
493  if (dict_mc->backup)
494  dict_close(dict_mc->backup);
495  dict_free(dict);
496 }
497 
498 /* dict_memcache_open - open memcache */
499 
500 DICT *dict_memcache_open(const char *name, int open_flags, int dict_flags)
501 {
502  DICT_MC *dict_mc;
503  char *backup;
504  CFG_PARSER *parser;
505 
506  /*
507  * Sanity checks.
508  */
509  if (dict_flags & DICT_FLAG_NO_UNAUTH)
510  return (dict_surrogate(DICT_TYPE_MEMCACHE, name, open_flags, dict_flags,
511  "%s:%s map is not allowed for security-sensitive data",
512  DICT_TYPE_MEMCACHE, name));
513  open_flags &= (O_RDONLY | O_RDWR | O_WRONLY | O_APPEND);
514  if (open_flags != O_RDONLY && open_flags != O_RDWR)
515  return (dict_surrogate(DICT_TYPE_MEMCACHE, name, open_flags, dict_flags,
516  "%s:%s map requires O_RDONLY or O_RDWR access mode",
517  DICT_TYPE_MEMCACHE, name));
518 
519  /*
520  * Open the configuration file.
521  */
522  if ((parser = cfg_parser_alloc(name)) == 0)
523  return (dict_surrogate(DICT_TYPE_MEMCACHE, name, open_flags, dict_flags,
524  "open %s: %m", name));
525 
526  /*
527  * Create the dictionary object.
528  */
529  dict_mc = (DICT_MC *) dict_alloc(DICT_TYPE_MEMCACHE, name,
530  sizeof(*dict_mc));
531  dict_mc->dict.lookup = dict_memcache_lookup;
532  if (open_flags == O_RDWR) {
533  dict_mc->dict.update = dict_memcache_update;
534  dict_mc->dict.delete = dict_memcache_delete;
535  }
536  dict_mc->dict.sequence = dict_memcache_sequence;
537  dict_mc->dict.close = dict_memcache_close;
538  dict_mc->dict.flags = dict_flags;
539  dict_mc->key_buf = vstring_alloc(10);
540  dict_mc->res_buf = vstring_alloc(10);
541 
542  /*
543  * Parse the configuration file.
544  */
545  dict_mc->parser = parser;
546  dict_mc->key_format = cfg_get_str(dict_mc->parser, DICT_MC_NAME_KEY_FMT,
547  DICT_MC_DEF_KEY_FMT, 0, 0);
548  dict_mc->timeout = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MC_TIMEOUT,
549  DICT_MC_DEF_MC_TIMEOUT, 0, 0);
550  dict_mc->mc_ttl = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MC_TTL,
551  DICT_MC_DEF_MC_TTL, 0, 0);
552  dict_mc->mc_flags = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MC_FLAGS,
553  DICT_MC_DEF_MC_FLAGS, 0, 0);
554  dict_mc->err_pause = cfg_get_int(dict_mc->parser, DICT_MC_NAME_ERR_PAUSE,
555  DICT_MC_DEF_ERR_PAUSE, 1, 0);
556  dict_mc->max_tries = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MAX_TRY,
557  DICT_MC_DEF_MAX_TRY, 1, 0);
558  dict_mc->max_line = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MAX_LINE,
559  DICT_MC_DEF_MAX_LINE, 1, 0);
560  dict_mc->max_data = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MAX_DATA,
561  DICT_MC_DEF_MAX_DATA, 1, 0);
562  dict_mc->memcache = cfg_get_str(dict_mc->parser, DICT_MC_NAME_MEMCACHE,
563  DICT_MC_DEF_MEMCACHE, 0, 0);
564 
565  /*
566  * Initialize the memcache client.
567  */
568  dict_mc->clnt = auto_clnt_create(dict_mc->memcache, dict_mc->timeout, 0, 0);
569  dict_mc->clnt_buf = vstring_alloc(100);
570 
571  /*
572  * Open the optional backup database.
573  */
574  backup = cfg_get_str(dict_mc->parser, DICT_MC_NAME_BACKUP,
575  (char *) 0, 0, 0);
576  if (backup) {
577  dict_mc->backup = dict_open(backup, open_flags, dict_flags);
578  myfree(backup);
579  } else
580  dict_mc->backup = 0;
581 
582  /*
583  * Parse templates and common database parameters. Maps that use
584  * substring keys should only be used with the full input key.
585  */
586  dict_mc->dbc_ctxt = 0;
587  db_common_parse(&dict_mc->dict, &dict_mc->dbc_ctxt,
588  dict_mc->key_format, 1);
589  db_common_parse_domain(dict_mc->parser, dict_mc->dbc_ctxt);
590  if (db_common_dict_partial(dict_mc->dbc_ctxt))
591  /* Breaks recipient delimiters */
592  dict_mc->dict.flags |= DICT_FLAG_PATTERN;
593  else
594  dict_mc->dict.flags |= DICT_FLAG_FIXED;
595 
596  dict_mc->dict.flags |= DICT_FLAG_MULTI_WRITER;
597 
598  return (&dict_mc->dict);
599 }
int msg_verbose
Definition: msg.c:177
VSTREAM * auto_clnt_access(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:251
#define DICT_MC_DEF_KEY_FMT
#define DICT_MC_DEF_MC_FLAGS
#define DICT_MC_DEF_ERR_PAUSE
#define DICT_MC_NO_KEY
void myfree(void *ptr)
Definition: mymalloc.c:207
#define DICT_MC_SKIP(why)
#define DICT_FLAG_NO_UNAUTH
Definition: dict.h:123
void(* close)(struct DICT *)
Definition: dict.h:87
#define DICT_MC_NAME_MAX_DATA
int(* delete)(struct DICT *, const char *)
Definition: dict.h:84
char * name
Definition: dict.h:80
#define DICT_MC_NAME_MC_FLAGS
#define DICT_FLAG_FIXED
Definition: dict.h:114
int flags
Definition: dict.h:81
VSTRING * res_buf
Definition: dict_memcache.c:91
#define DICT_ERR_RETRY
Definition: dict.h:178
#define DICT_STAT_FAIL
Definition: dict.h:185
#define DICT_MC_DEF_MAX_TRY
DICT * dict_open(const char *, int, int)
Definition: dict_open.c:421
void * dbc_ctxt
Definition: dict_memcache.c:78
int cfg_get_int(const CFG_PARSER *parser, const char *name, int defval, int min, int max)
Definition: cfg_parser.c:281
#define DICT_FLAG_MULTI_WRITER
Definition: dict.h:129
#define DICT_MC_DEF_MC_TTL
#define DICT_FLAG_FOLD_FIX
Definition: dict.h:124
int err_pause
Definition: dict_memcache.c:83
#define DICT_ERR_NONE
Definition: dict.h:177
void db_common_free_ctx(void *ctxPtr)
Definition: db_common.c:288
DICT * dict_memcache_open(const char *name, int open_flags, int dict_flags)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
int db_common_dict_partial(void *ctxPtr)
Definition: db_common.c:276
Definition: dict.h:78
#define DICT_MC_DEF_MAX_LINE
AUTO_CLNT * clnt
Definition: dict_memcache.c:88
int(* update)(struct DICT *, const char *, const char *)
Definition: dict.h:83
#define DICT_STAT_SUCCESS
Definition: dict.h:186
char * key_format
Definition: dict_memcache.c:79
#define DICT_MC_NAME_MC_TIMEOUT
void db_common_parse_domain(CFG_PARSER *parser, void *ctxPtr)
Definition: db_common.c:251
#define DICT_MC_NO_QUOTING
#define LEN(x)
int db_common_expand(void *ctxArg, const char *format, const char *value, const char *key, VSTRING *result, db_quote_callback_t quote_func)
Definition: db_common.c:299
AUTO_CLNT * auto_clnt_create(const char *service, int timeout, int max_idle, int max_ttl)
Definition: auto_clnt.c:271
int memcache_fwrite(VSTREAM *stream, const char *cp, ssize_t todo)
#define DICT_MC_NAME_KEY_FMT
#define VSTRING_RESET(vp)
Definition: vstring.h:77
void msg_warn(const char *fmt,...)
Definition: msg.c:215
int memcache_printf(VSTREAM *stream, const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define DICT_MC_DEF_MEMCACHE
int error
Definition: dict.h:94
int db_common_check_domain(void *ctxPtr, const char *addr)
Definition: db_common.c:521
int max_tries
Definition: dict_memcache.c:84
char * lowercase(char *string)
Definition: lowercase.c:34
#define DICT_MC_NAME_ERR_PAUSE
void auto_clnt_free(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:316
const char *(* lookup)(struct DICT *, const char *)
Definition: dict.h:82
#define DICT_ERR_VAL_RETURN(dict, err, val)
Definition: dict.h:192
#define DICT_MC_NAME_MEMCACHE
char * cfg_get_str(const CFG_PARSER *parser, const char *name, const char *defval, int min, int max)
Definition: cfg_parser.c:261
#define DICT_MC_NAME_BACKUP
#define DICT_MC_DEF_MAX_DATA
#define DICT_FLAG_PATTERN
Definition: dict.h:115
void dict_free(DICT *)
Definition: dict_alloc.c:163
CFG_PARSER * cfg_parser_free(CFG_PARSER *parser)
Definition: cfg_parser.c:309
int mc_flags
Definition: dict_memcache.c:82
char * memcache
Definition: dict_memcache.c:87
#define DICT_TYPE_MEMCACHE
Definition: dict_memcache.h:22
int max_line
Definition: dict_memcache.c:85
CFG_PARSER * cfg_parser_alloc(const char *pname)
Definition: cfg_parser.c:227
void auto_clnt_recover(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:239
int mc_ttl
Definition: dict_memcache.c:81
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define STR(x)
VSTRING * clnt_buf
Definition: dict_memcache.c:89
#define DICT_STAT_ERROR
Definition: dict.h:187
int memcache_fread(VSTREAM *stream, VSTRING *buf, ssize_t todo)
int db_common_parse(DICT *dict, void **ctxPtr, const char *format, int query)
Definition: db_common.c:185
#define DICT_MC_NAME_MAX_LINE
#define DICT_MC_DEF_MC_TIMEOUT
int(* sequence)(struct DICT *, int, const char **, const char **)
Definition: dict.h:85
DICT * dict_alloc(const char *, const char *, ssize_t)
Definition: dict_alloc.c:135
VSTRING * fold_buf
Definition: dict.h:92
CFG_PARSER * parser
Definition: dict_memcache.c:77
int memcache_get(VSTREAM *stream, VSTRING *vp, ssize_t bound)
int timeout
Definition: dict_memcache.c:80
int max_data
Definition: dict_memcache.c:86
#define DICT_MC_NAME_MAX_TRY
DICT dict
Definition: dict_memcache.c:76
DICT * backup
Definition: dict_memcache.c:93
VSTRING * key_buf
Definition: dict_memcache.c:90
DICT * dict_surrogate(const char *dict_type, const char *dict_name, int open_flags, int dict_flags, const char *fmt,...)
#define dict_close(dp)
Definition: dict.h:240
#define DICT_MC_NAME_MC_TTL
void msg_info(const char *fmt,...)
Definition: msg.c:199