Apache HTTPD
mod_socache_memcache.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2* contributor license agreements. See the NOTICE file distributed with
3* this work for additional information regarding copyright ownership.
4* The ASF licenses this file to You under the Apache License, Version 2.0
5* (the "License"); you may not use this file except in compliance with
6* the License. You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17
18#include "httpd.h"
19#include "http_config.h"
20#include "http_protocol.h"
21
22#include "apr.h"
23
24#include "ap_socache.h"
25#include "ap_mpm.h"
26#include "http_log.h"
27#include "apr_memcache.h"
28#include "apr_strings.h"
29#include "mod_status.h"
30
31/* The underlying apr_memcache system is thread safe.. */
32#define MC_KEY_LEN 254
33
34#ifndef MC_DEFAULT_SERVER_PORT
35#define MC_DEFAULT_SERVER_PORT 11211
36#endif
37
38
39#ifndef MC_DEFAULT_SERVER_MIN
40#define MC_DEFAULT_SERVER_MIN 0
41#endif
42
43#ifndef MC_DEFAULT_SERVER_SMAX
44#define MC_DEFAULT_SERVER_SMAX 1
45#endif
46
47#ifndef MC_DEFAULT_SERVER_TTL
48#define MC_DEFAULT_SERVER_TTL apr_time_from_sec(15)
49#endif
50
51module AP_MODULE_DECLARE_DATA socache_memcache_module;
52
53typedef struct {
56
58 const char *servers;
60 const char *tag;
61 apr_size_t taglen; /* strlen(tag) + 1 */
62};
63
65 const char *arg,
66 apr_pool_t *tmp, apr_pool_t *p)
67{
69
70 *context = ctx = apr_palloc(p, sizeof *ctx);
71
72 if (!arg || !*arg) {
73 return "List of server names required to create memcache socache.";
74 }
75
76 ctx->servers = apr_pstrdup(p, arg);
77
78 return NULL;
79}
80
82 const char *namespace,
83 const struct ap_socache_hints *hints,
85{
86 apr_status_t rv;
87 int thread_limit = 0;
89 char *cache_config;
90 char *split;
91 char *tok;
92
94 &socache_memcache_module);
95
97
98 /* Find all the servers in the first run to get a total count */
99 cache_config = apr_pstrdup(p, ctx->servers);
100 split = apr_strtok(cache_config, ",", &tok);
101 while (split) {
102 nservers++;
103 split = apr_strtok(NULL,",", &tok);
104 }
105
106 rv = apr_memcache_create(p, nservers, 0, &ctx->mc);
107 if (rv != APR_SUCCESS) {
109 "Failed to create Memcache Object of '%d' size.",
110 nservers);
111 return rv;
112 }
113
114 /* Now add each server to the memcache */
115 cache_config = apr_pstrdup(p, ctx->servers);
116 split = apr_strtok(cache_config, ",", &tok);
117 while (split) {
119 char *host_str;
120 char *scope_id;
122
123 rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p);
124 if (rv != APR_SUCCESS) {
126 "Failed to Parse memcache Server: '%s'", split);
127 return rv;
128 }
129
130 if (host_str == NULL) {
132 "Failed to Parse Server, "
133 "no hostname specified: '%s'", split);
134 return APR_EINVAL;
135 }
136
137 if (port == 0) {
139 }
140
142 host_str, port,
146 sconf->ttl,
147 &st);
148 if (rv != APR_SUCCESS) {
150 "Failed to Create memcache Server: %s:%d",
151 host_str, port);
152 return rv;
153 }
154
155 rv = apr_memcache_add_server(ctx->mc, st);
156 if (rv != APR_SUCCESS) {
158 "Failed to Add memcache Server: %s:%d",
159 host_str, port);
160 return rv;
161 }
162
163 split = apr_strtok(NULL,",", &tok);
164 }
165
166 ctx->tag = apr_pstrcat(p, namespace, ":", NULL);
167 ctx->taglen = strlen(ctx->tag) + 1;
168
169 /* socache API constraint: */
170 AP_DEBUG_ASSERT(ctx->taglen <= 16);
171
172 return APR_SUCCESS;
173}
174
176{
177 /* noop. */
178}
179
180/* Converts (binary) id into a key prefixed by the predetermined
181 * namespace tag; writes output to key buffer. Returns non-zero if
182 * the id won't fit in the key buffer. */
184 const unsigned char *id, unsigned int idlen,
185 char *key, apr_size_t keylen)
186{
187 char *cp;
188
189 if (idlen * 2 + ctx->taglen >= keylen)
190 return 1;
191
192 cp = apr_cpystrn(key, ctx->tag, ctx->taglen);
193 ap_bin2hex(id, idlen, cp);
194
195 return 0;
196}
197
199 const unsigned char *id, unsigned int idlen,
200 apr_time_t expiry,
201 unsigned char *ucaData, unsigned int nData,
202 apr_pool_t *p)
203{
204 char buf[MC_KEY_LEN];
205 apr_status_t rv;
206
207 if (socache_mc_id2key(ctx, id, idlen, buf, sizeof buf)) {
208 return APR_EINVAL;
209 }
210
211 /* memcache needs time in seconds till expiry; fail if this is not
212 * positive *before* casting to unsigned (apr_uint32_t). */
213 expiry -= apr_time_now();
214 if (apr_time_sec(expiry) <= 0) {
215 return APR_EINVAL;
216 }
217 rv = apr_memcache_set(ctx->mc, buf, (char*)ucaData, nData,
218 apr_time_sec(expiry), 0);
219
220 if (rv != APR_SUCCESS) {
222 "scache_mc: error setting key '%s' "
223 "with %d bytes of data", buf, nData);
224 return rv;
225 }
226
227 return APR_SUCCESS;
228}
229
231 const unsigned char *id, unsigned int idlen,
232 unsigned char *dest, unsigned int *destlen,
233 apr_pool_t *p)
234{
236 char buf[MC_KEY_LEN], *data;
237 apr_status_t rv;
238
239 if (socache_mc_id2key(ctx, id, idlen, buf, sizeof buf)) {
240 return APR_EINVAL;
241 }
242
243 /* ### this could do with a subpool, but _getp looks like it will
244 * eat memory like it's going out of fashion anyway. */
245
246 rv = apr_memcache_getp(ctx->mc, p, buf, &data, &data_len, NULL);
247 if (rv) {
248 if (rv != APR_NOTFOUND) {
250 "scache_mc: 'retrieve' FAIL");
251 }
252 return rv;
253 }
254 else if (data_len > *destlen) {
256 "scache_mc: 'retrieve' OVERFLOW");
257 return APR_ENOMEM;
258 }
259
261 *destlen = data_len;
262
263 return APR_SUCCESS;
264}
265
267 const unsigned char *id,
268 unsigned int idlen, apr_pool_t *p)
269{
270 char buf[MC_KEY_LEN];
271 apr_status_t rv;
272
273 if (socache_mc_id2key(ctx, id, idlen, buf, sizeof buf)) {
274 return APR_EINVAL;
275 }
276
277 rv = apr_memcache_delete(ctx->mc, buf, 0);
278
279 if (rv != APR_SUCCESS) {
281 "scache_mc: error deleting key '%s' ",
282 buf);
283 }
284
285 return rv;
286}
287
289{
290 apr_memcache_t *rc = ctx->mc;
291 int i;
292
293 for (i = 0; i < rc->ntotal; i++) {
296 apr_status_t rv;
297 char *br = (!(flags & AP_STATUS_SHORT) ? "<br />" : "");
298
299 ms = rc->live_servers[i];
300
301 ap_rprintf(r, "Memcached server: %s:%d [%s]%s\n", ms->host, (int)ms->port,
302 (ms->status == APR_MC_SERVER_LIVE) ? "Up" : "Down",
303 br);
304 rv = apr_memcache_stats(ms, r->pool, &stats);
305 if (rv != APR_SUCCESS)
306 continue;
307 if (!(flags & AP_STATUS_SHORT)) {
308 ap_rprintf(r, "<b>Version:</b> <i>%s</i> [%u bits], PID: <i>%u</i>, Uptime: <i>%u hrs</i> <br />\n",
309 stats->version , stats->pointer_size, stats->pid, stats->uptime/3600);
310 ap_rprintf(r, "<b>Clients::</b> Structures: <i>%u</i>, Total: <i>%u</i>, Current: <i>%u</i> <br />\n",
311 stats->connection_structures, stats->total_connections, stats->curr_connections);
312 ap_rprintf(r, "<b>Storage::</b> Total Items: <i>%u</i>, Current Items: <i>%u</i>, Bytes: <i>%" APR_UINT64_T_FMT "</i> <br />\n",
313 stats->total_items, stats->curr_items, stats->bytes);
314 ap_rprintf(r, "<b>CPU::</b> System: <i>%u</i>, User: <i>%u</i> <br />\n",
315 (unsigned)stats->rusage_system, (unsigned)stats->rusage_user );
316 ap_rprintf(r, "<b>Cache::</b> Gets: <i>%u</i>, Sets: <i>%u</i>, Hits: <i>%u</i>, Misses: <i>%u</i> <br />\n",
317 stats->cmd_get, stats->cmd_set, stats->get_hits, stats->get_misses);
318 ap_rprintf(r, "<b>Net::</b> Input bytes: <i>%" APR_UINT64_T_FMT "</i>, Output bytes: <i>%" APR_UINT64_T_FMT "</i> <br />\n",
319 stats->bytes_read, stats->bytes_written);
320 ap_rprintf(r, "<b>Misc::</b> Evictions: <i>%" APR_UINT64_T_FMT "</i>, MaxMem: <i>%u</i>, Threads: <i>%u</i> <br />\n",
321 stats->evictions, stats->limit_maxbytes, stats->threads);
322 ap_rputs("<hr><br />\n", r);
323 }
324 else {
325 ap_rprintf(r, "Version: %s [%u bits], PID: %u, Uptime: %u hrs %s\n",
326 stats->version , stats->pointer_size, stats->pid, stats->uptime/3600, br);
327 ap_rprintf(r, "Clients:: Structures: %d, Total: %d, Current: %u %s\n",
328 stats->connection_structures, stats->total_connections, stats->curr_connections, br);
329 ap_rprintf(r, "Storage:: Total Items: %u, Current Items: %u, Bytes: %" APR_UINT64_T_FMT " %s\n",
330 stats->total_items, stats->curr_items, stats->bytes, br);
331 ap_rprintf(r, "CPU:: System: %u, User: %u %s\n",
332 (unsigned)stats->rusage_system, (unsigned)stats->rusage_user , br);
333 ap_rprintf(r, "Cache:: Gets: %u, Sets: %u, Hits: %u, Misses: %u %s\n",
334 stats->cmd_get, stats->cmd_set, stats->get_hits, stats->get_misses, br);
335 ap_rprintf(r, "Net:: Input bytes: %" APR_UINT64_T_FMT ", Output bytes: %" APR_UINT64_T_FMT " %s\n",
336 stats->bytes_read, stats->bytes_written, br);
337 ap_rprintf(r, "Misc:: Evictions: %" APR_UINT64_T_FMT ", MaxMem: %u, Threads: %u %s\n",
338 stats->evictions, stats->limit_maxbytes, stats->threads, br);
339 }
340 }
341
342}
343
351
364
366{
368
370
371 return sconf;
372}
373
374static const char *socache_mc_set_ttl(cmd_parms *cmd, void *dummy,
375 const char *arg)
376{
378 socache_mc_svr_cfg *sconf = ap_get_module_config(cmd->server->module_config,
379 &socache_memcache_module);
380
382 return apr_pstrcat(cmd->pool, cmd->cmd->name,
383 " has wrong format", NULL);
384 }
385
386 if ((ttl < apr_time_from_sec(0)) || (ttl > apr_time_from_sec(3600))) {
387 return apr_pstrcat(cmd->pool, cmd->cmd->name,
388 " can only be 0 or up to one hour.", NULL);
389 }
390
391 /* apr_memcache_server_create needs a ttl in usec. */
392 sconf->ttl = ttl;
393
394 return NULL;
395}
396
403
405 AP_INIT_TAKE1("MemcacheConnTTL", socache_mc_set_ttl, NULL, RSRC_CONF,
406 "TTL used for the connection with the memcache server(s)"),
407 { NULL }
408};
409
412 NULL, /* create per-dir config structures */
413 NULL, /* merge per-dir config structures */
414 create_server_config, /* create per-server config structures */
415 NULL, /* merge per-server config structures */
416 socache_memcache_cmds, /* table of config file commands */
417 register_hooks /* register hooks */
418};
Apache Multi-Processing Module library.
Small object cache provider interface.
apr_memcache_set(apr_memcache_t *mc, const char *key, char *data, const apr_size_t data_size, apr_uint32_t timeout, apr_uint16_t flags)
apr_memcache_delete(apr_memcache_t *mc, const char *key, apr_uint32_t timeout)
apr_memcache_getp(apr_memcache_t *mc, apr_pool_t *p, const char *key, char **baton, apr_size_t *new_length, apr_uint16_t *flags_)
apr_memcache_stats(apr_memcache_server_t *ms, apr_pool_t *p, apr_memcache_stats_t **stats)
Client interface for memcached.
APR Strings library.
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
#define AP_DECLARE_MODULE(foo)
request_rec * r
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
apr_md5_ctx_t * context
Definition util_md5.h:58
int ap_rprintf(request_rec *r, const char *fmt,...) __attribute__((format(printf
static APR_INLINE int ap_rputs(const char *str, request_rec *r)
apr_status_t ap_register_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, const char *provider_version, const void *provider)
Definition provider.c:35
const char apr_port_t port
Definition http_vhost.h:125
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_NOTFOUND
Definition apr_errno.h:463
#define APR_EINVAL
Definition apr_errno.h:711
apr_brigade_flush void * ctx
const char apr_ssize_t int flags
Definition apr_encode.h:168
const char const apr_size_t data_len
apr_memcache_server_t * ms
apr_pool_t apr_memcache_stats_t ** stats
@ APR_MC_SERVER_LIVE
apr_redis_t * rc
Definition apr_redis.h:173
apr_status_t() ap_socache_iterator_t(ap_socache_instance_t *instance, server_rec *s, void *userctx, const unsigned char *id, unsigned int idlen, const unsigned char *data, unsigned int datalen, apr_pool_t *pool)
Definition ap_socache.h:77
#define AP_SOCACHE_PROVIDER_GROUP
Definition ap_socache.h:218
#define AP_SOCACHE_PROVIDER_VERSION
Definition ap_socache.h:220
#define RSRC_CONF
#define AP_STATUS_SHORT
Definition mod_status.h:32
#define STANDARD20_MODULE_STUFF
void ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
Definition util.c:2314
#define AP_DEBUG_ASSERT(exp)
Definition httpd.h:2283
apr_status_t ap_timeout_parameter_parse(const char *timeout_parameter, apr_interval_time_t *timeout, const char *default_time_unit)
Definition util.c:2622
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
void * data
apr_byte_t ttl
apr_uint16_t apr_port_t
char ** scope_id
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
apr_cmdtype_e cmd
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_sec(time)
Definition apr_time.h:63
#define apr_time_from_sec(sec)
Definition apr_time.h:78
apr_status_t ap_mpm_query(int query_code, int *result)
Definition mpm_common.c:421
#define AP_MPMQ_HARD_LIMIT_THREADS
Definition ap_mpm.h:158
Apache Configuration.
Apache Logging library.
HTTP protocol handling.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
sconf
Definition mod_so.c:349
static void * create_server_config(apr_pool_t *p, server_rec *s)
#define MC_DEFAULT_SERVER_TTL
static const command_rec socache_memcache_cmds[]
static apr_status_t socache_mc_iterate(ap_socache_instance_t *instance, server_rec *s, void *userctx, ap_socache_iterator_t *iterator, apr_pool_t *pool)
static void socache_mc_status(ap_socache_instance_t *ctx, request_rec *r, int flags)
static apr_status_t socache_mc_retrieve(ap_socache_instance_t *ctx, server_rec *s, const unsigned char *id, unsigned int idlen, unsigned char *dest, unsigned int *destlen, apr_pool_t *p)
static apr_status_t socache_mc_store(ap_socache_instance_t *ctx, server_rec *s, const unsigned char *id, unsigned int idlen, apr_time_t expiry, unsigned char *ucaData, unsigned int nData, apr_pool_t *p)
static const ap_socache_provider_t socache_mc
static void register_hooks(apr_pool_t *p)
#define MC_DEFAULT_SERVER_MIN
static const char * socache_mc_set_ttl(cmd_parms *cmd, void *dummy, const char *arg)
static const char * socache_mc_create(ap_socache_instance_t **context, const char *arg, apr_pool_t *tmp, apr_pool_t *p)
#define MC_DEFAULT_SERVER_SMAX
static apr_status_t socache_mc_remove(ap_socache_instance_t *ctx, server_rec *s, const unsigned char *id, unsigned int idlen, apr_pool_t *p)
#define MC_DEFAULT_SERVER_PORT
static int socache_mc_id2key(ap_socache_instance_t *ctx, const unsigned char *id, unsigned int idlen, char *key, apr_size_t keylen)
#define MC_KEY_LEN
static apr_status_t socache_mc_init(ap_socache_instance_t *ctx, const char *namespace, const struct ap_socache_hints *hints, server_rec *s, apr_pool_t *p)
static void socache_mc_destroy(ap_socache_instance_t *context, server_rec *s)
static int thread_limit
Definition mod_status.c:89
Status Report Extension Module to Apache.
apr_memcache_server_status_t status
apr_uint16_t ntotal
Definition apr_redis.h:124
apr_redis_server_t ** live_servers
Definition apr_redis.h:125
A structure that represents the current request.
Definition httpd.h:845
apr_pool_t * pool
Definition httpd.h:847
A structure to store information for each virtual server.
Definition httpd.h:1322
static size_t keylen(KEY s)
Definition xmlparse.c:7166