Blame modules/cache/mod_socache_memcache.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
* contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
* this work for additional information regarding copyright ownership.
Packit 90a5c9
* The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
* (the "License"); you may not use this file except in compliance with
Packit 90a5c9
* the License.  You may obtain a copy of the License at
Packit 90a5c9
*
Packit 90a5c9
*     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
*
Packit 90a5c9
* Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
* distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
* See the License for the specific language governing permissions and
Packit 90a5c9
* limitations under the License.
Packit 90a5c9
*/
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
#include "httpd.h"
Packit 90a5c9
#include "http_config.h"
Packit 90a5c9
#include "http_protocol.h"
Packit 90a5c9
Packit 90a5c9
#include "apr.h"
Packit 90a5c9
#include "apu_version.h"
Packit 90a5c9
Packit 90a5c9
/* apr_memcache support requires >= 1.3 */
Packit 90a5c9
#if APU_MAJOR_VERSION > 1 || \
Packit 90a5c9
    (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION > 2)
Packit 90a5c9
#define HAVE_APU_MEMCACHE 1
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#ifdef HAVE_APU_MEMCACHE
Packit 90a5c9
Packit 90a5c9
#include "ap_socache.h"
Packit 90a5c9
#include "ap_mpm.h"
Packit 90a5c9
#include "http_log.h"
Packit 90a5c9
#include "apr_memcache.h"
Packit 90a5c9
#include "apr_strings.h"
Packit 90a5c9
#include "mod_status.h"
Packit 90a5c9
Packit 90a5c9
/* The underlying apr_memcache system is thread safe.. */
Packit 90a5c9
#define MC_KEY_LEN 254
Packit 90a5c9
Packit 90a5c9
#ifndef MC_DEFAULT_SERVER_PORT
Packit 90a5c9
#define MC_DEFAULT_SERVER_PORT 11211
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
#ifndef MC_DEFAULT_SERVER_MIN
Packit 90a5c9
#define MC_DEFAULT_SERVER_MIN 0
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#ifndef MC_DEFAULT_SERVER_SMAX
Packit 90a5c9
#define MC_DEFAULT_SERVER_SMAX 1
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#ifndef MC_DEFAULT_SERVER_TTL
Packit 90a5c9
#define MC_DEFAULT_SERVER_TTL    apr_time_from_sec(15)
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
module AP_MODULE_DECLARE_DATA socache_memcache_module;
Packit 90a5c9
Packit 90a5c9
typedef struct {
Packit 90a5c9
    apr_uint32_t ttl;
Packit 90a5c9
} socache_mc_svr_cfg;
Packit 90a5c9
Packit 90a5c9
struct ap_socache_instance_t {
Packit 90a5c9
    const char *servers;
Packit 90a5c9
    apr_memcache_t *mc;
Packit 90a5c9
    const char *tag;
Packit 90a5c9
    apr_size_t taglen; /* strlen(tag) + 1 */
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const char *socache_mc_create(ap_socache_instance_t **context,
Packit 90a5c9
                                     const char *arg,
Packit 90a5c9
                                     apr_pool_t *tmp, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    ap_socache_instance_t *ctx;
Packit 90a5c9
Packit 90a5c9
    *context = ctx = apr_palloc(p, sizeof *ctx);
Packit 90a5c9
Packit 90a5c9
    if (!arg || !*arg) {
Packit 90a5c9
        return "List of server names required to create memcache socache.";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ctx->servers = apr_pstrdup(p, arg);
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t socache_mc_init(ap_socache_instance_t *ctx,
Packit 90a5c9
                                    const char *namespace,
Packit 90a5c9
                                    const struct ap_socache_hints *hints,
Packit 90a5c9
                                    server_rec *s, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    int thread_limit = 0;
Packit 90a5c9
    apr_uint16_t nservers = 0;
Packit 90a5c9
    char *cache_config;
Packit 90a5c9
    char *split;
Packit 90a5c9
    char *tok;
Packit 90a5c9
Packit 90a5c9
    socache_mc_svr_cfg *sconf = ap_get_module_config(s->module_config,
Packit 90a5c9
                                                     &socache_memcache_module);
Packit 90a5c9
Packit 90a5c9
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
Packit 90a5c9
Packit 90a5c9
    /* Find all the servers in the first run to get a total count */
Packit 90a5c9
    cache_config = apr_pstrdup(p, ctx->servers);
Packit 90a5c9
    split = apr_strtok(cache_config, ",", &tok;;
Packit 90a5c9
    while (split) {
Packit 90a5c9
        nservers++;
Packit 90a5c9
        split = apr_strtok(NULL,",", &tok;;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    rv = apr_memcache_create(p, nservers, 0, &ctx->mc);
Packit 90a5c9
    if (rv != APR_SUCCESS) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00785)
Packit 90a5c9
                     "Failed to create Memcache Object of '%d' size.",
Packit 90a5c9
                     nservers);
Packit 90a5c9
        return rv;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Now add each server to the memcache */
Packit 90a5c9
    cache_config = apr_pstrdup(p, ctx->servers);
Packit 90a5c9
    split = apr_strtok(cache_config, ",", &tok;;
Packit 90a5c9
    while (split) {
Packit 90a5c9
        apr_memcache_server_t *st;
Packit 90a5c9
        char *host_str;
Packit 90a5c9
        char *scope_id;
Packit 90a5c9
        apr_port_t port;
Packit 90a5c9
Packit 90a5c9
        rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p);
Packit 90a5c9
        if (rv != APR_SUCCESS) {
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00786)
Packit 90a5c9
                         "Failed to Parse memcache Server: '%s'", split);
Packit 90a5c9
            return rv;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        if (host_str == NULL) {
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00787)
Packit 90a5c9
                         "Failed to Parse Server, "
Packit 90a5c9
                         "no hostname specified: '%s'", split);
Packit 90a5c9
            return APR_EINVAL;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        if (port == 0) {
Packit 90a5c9
            port = MC_DEFAULT_SERVER_PORT;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        rv = apr_memcache_server_create(p,
Packit 90a5c9
                                        host_str, port,
Packit 90a5c9
                                        MC_DEFAULT_SERVER_MIN,
Packit 90a5c9
                                        MC_DEFAULT_SERVER_SMAX,
Packit 90a5c9
                                        thread_limit,
Packit 90a5c9
                                        sconf->ttl,
Packit 90a5c9
                                        &st);
Packit 90a5c9
        if (rv != APR_SUCCESS) {
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00788)
Packit 90a5c9
                         "Failed to Create memcache Server: %s:%d",
Packit 90a5c9
                         host_str, port);
Packit 90a5c9
            return rv;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        rv = apr_memcache_add_server(ctx->mc, st);
Packit 90a5c9
        if (rv != APR_SUCCESS) {
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00789)
Packit 90a5c9
                         "Failed to Add memcache Server: %s:%d",
Packit 90a5c9
                         host_str, port);
Packit 90a5c9
            return rv;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        split = apr_strtok(NULL,",", &tok;;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ctx->tag = apr_pstrcat(p, namespace, ":", NULL);
Packit 90a5c9
    ctx->taglen = strlen(ctx->tag) + 1;
Packit 90a5c9
Packit 90a5c9
    /* socache API constraint: */
Packit 90a5c9
    AP_DEBUG_ASSERT(ctx->taglen <= 16);
Packit 90a5c9
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void socache_mc_destroy(ap_socache_instance_t *context, server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    /* noop. */
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Converts (binary) id into a key prefixed by the predetermined
Packit 90a5c9
 * namespace tag; writes output to key buffer.  Returns non-zero if
Packit 90a5c9
 * the id won't fit in the key buffer. */
Packit 90a5c9
static int socache_mc_id2key(ap_socache_instance_t *ctx,
Packit 90a5c9
                             const unsigned char *id, unsigned int idlen,
Packit 90a5c9
                             char *key, apr_size_t keylen)
Packit 90a5c9
{
Packit 90a5c9
    char *cp;
Packit 90a5c9
Packit 90a5c9
    if (idlen * 2 + ctx->taglen >= keylen)
Packit 90a5c9
        return 1;
Packit 90a5c9
Packit 90a5c9
    cp = apr_cpystrn(key, ctx->tag, ctx->taglen);
Packit 90a5c9
    ap_bin2hex(id, idlen, cp);
Packit 90a5c9
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t socache_mc_store(ap_socache_instance_t *ctx, server_rec *s,
Packit 90a5c9
                                     const unsigned char *id, unsigned int idlen,
Packit 90a5c9
                                     apr_time_t expiry,
Packit 90a5c9
                                     unsigned char *ucaData, unsigned int nData,
Packit 90a5c9
                                     apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    char buf[MC_KEY_LEN];
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
Packit 90a5c9
    if (socache_mc_id2key(ctx, id, idlen, buf, sizeof buf)) {
Packit 90a5c9
        return APR_EINVAL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* memcache needs time in seconds till expiry; fail if this is not
Packit 90a5c9
     * positive *before* casting to unsigned (apr_uint32_t). */
Packit 90a5c9
    expiry -= apr_time_now();
Packit 90a5c9
    if (apr_time_sec(expiry) <= 0) {
Packit 90a5c9
        return APR_EINVAL;
Packit 90a5c9
    }
Packit 90a5c9
    rv = apr_memcache_set(ctx->mc, buf, (char*)ucaData, nData,
Packit 90a5c9
                          apr_time_sec(expiry), 0);
Packit 90a5c9
Packit 90a5c9
    if (rv != APR_SUCCESS) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00790)
Packit 90a5c9
                     "scache_mc: error setting key '%s' "
Packit 90a5c9
                     "with %d bytes of data", buf, nData);
Packit 90a5c9
        return rv;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t socache_mc_retrieve(ap_socache_instance_t *ctx, server_rec *s,
Packit 90a5c9
                                        const unsigned char *id, unsigned int idlen,
Packit 90a5c9
                                        unsigned char *dest, unsigned int *destlen,
Packit 90a5c9
                                        apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    apr_size_t data_len;
Packit 90a5c9
    char buf[MC_KEY_LEN], *data;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
Packit 90a5c9
    if (socache_mc_id2key(ctx, id, idlen, buf, sizeof buf)) {
Packit 90a5c9
        return APR_EINVAL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* ### this could do with a subpool, but _getp looks like it will
Packit 90a5c9
     * eat memory like it's going out of fashion anyway. */
Packit 90a5c9
Packit 90a5c9
    rv = apr_memcache_getp(ctx->mc, p, buf, &data, &data_len, NULL);
Packit 90a5c9
    if (rv) {
Packit 90a5c9
        if (rv != APR_NOTFOUND) {
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00791)
Packit 90a5c9
                         "scache_mc: 'retrieve' FAIL");
Packit 90a5c9
        }
Packit 90a5c9
        return rv;
Packit 90a5c9
    }
Packit 90a5c9
    else if (data_len > *destlen) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00792)
Packit 90a5c9
                     "scache_mc: 'retrieve' OVERFLOW");
Packit 90a5c9
        return APR_ENOMEM;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    memcpy(dest, data, data_len);
Packit 90a5c9
    *destlen = data_len;
Packit 90a5c9
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t socache_mc_remove(ap_socache_instance_t *ctx, server_rec *s,
Packit 90a5c9
                                      const unsigned char *id,
Packit 90a5c9
                                      unsigned int idlen, apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    char buf[MC_KEY_LEN];
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
Packit 90a5c9
    if (socache_mc_id2key(ctx, id, idlen, buf, sizeof buf)) {
Packit 90a5c9
        return APR_EINVAL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    rv = apr_memcache_delete(ctx->mc, buf, 0);
Packit 90a5c9
Packit 90a5c9
    if (rv != APR_SUCCESS) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s, APLOGNO(00793)
Packit 90a5c9
                     "scache_mc: error deleting key '%s' ",
Packit 90a5c9
                     buf);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void socache_mc_status(ap_socache_instance_t *ctx, request_rec *r, int flags)
Packit 90a5c9
{
Packit 90a5c9
    apr_memcache_t *rc = ctx->mc;
Packit 90a5c9
    int i;
Packit 90a5c9
Packit 90a5c9
    for (i = 0; i < rc->ntotal; i++) {
Packit 90a5c9
        apr_memcache_server_t *ms;
Packit 90a5c9
        apr_memcache_stats_t *stats;
Packit 90a5c9
        apr_status_t rv;
Packit 90a5c9
        char *br = (!(flags & AP_STATUS_SHORT) ? "
" : "");
Packit 90a5c9
Packit 90a5c9
        ms = rc->live_servers[i];
Packit 90a5c9
Packit 90a5c9
        ap_rprintf(r, "Memcached server: %s:%d [%s]%s\n", ms->host, (int)ms->port,
Packit 90a5c9
                (ms->status == APR_MC_SERVER_LIVE) ? "Up" : "Down",
Packit 90a5c9
                br);
Packit 90a5c9
        rv = apr_memcache_stats(ms, r->pool, &stats);
Packit 90a5c9
        if (rv != APR_SUCCESS)
Packit 90a5c9
            continue;
Packit 90a5c9
        if (!(flags & AP_STATUS_SHORT)) {
Packit 90a5c9
            ap_rprintf(r, "Version: %s [%u bits], PID: %u, Uptime: %u hrs 
\n",
Packit 90a5c9
                    stats->version , stats->pointer_size, stats->pid, stats->uptime/3600);
Packit 90a5c9
            ap_rprintf(r, "Clients:: Structures: %u, Total: %u, Current: %u 
\n",
Packit 90a5c9
                    stats->connection_structures, stats->total_connections, stats->curr_connections);
Packit 90a5c9
            ap_rprintf(r, "Storage:: Total Items: %u, Current Items: %u, Bytes: %" APR_UINT64_T_FMT " 
\n",
Packit 90a5c9
                    stats->total_items, stats->curr_items, stats->bytes);
Packit 90a5c9
            ap_rprintf(r, "CPU:: System: %u, User: %u 
\n",
Packit 90a5c9
                    (unsigned)stats->rusage_system, (unsigned)stats->rusage_user );
Packit 90a5c9
            ap_rprintf(r, "Cache:: Gets: %u, Sets: %u, Hits: %u, Misses: %u 
\n",
Packit 90a5c9
                    stats->cmd_get, stats->cmd_set, stats->get_hits, stats->get_misses);
Packit 90a5c9
            ap_rprintf(r, "Net:: Input bytes: %" APR_UINT64_T_FMT ", Output bytes: %" APR_UINT64_T_FMT " 
\n",
Packit 90a5c9
                    stats->bytes_read, stats->bytes_written);
Packit 90a5c9
            ap_rprintf(r, "Misc:: Evictions: %" APR_UINT64_T_FMT ", MaxMem: %u, Threads: %u 
\n",
Packit 90a5c9
                    stats->evictions, stats->limit_maxbytes, stats->threads);
Packit 90a5c9
            ap_rputs("

\n", r);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ap_rprintf(r, "Version: %s [%u bits], PID: %u, Uptime: %u hrs %s\n",
Packit 90a5c9
                    stats->version , stats->pointer_size, stats->pid, stats->uptime/3600, br);
Packit 90a5c9
            ap_rprintf(r, "Clients:: Structures: %d, Total: %d, Current: %u %s\n",
Packit 90a5c9
                    stats->connection_structures, stats->total_connections, stats->curr_connections, br);
Packit 90a5c9
            ap_rprintf(r, "Storage:: Total Items: %u, Current Items: %u, Bytes: %" APR_UINT64_T_FMT " %s\n",
Packit 90a5c9
                    stats->total_items, stats->curr_items, stats->bytes, br);
Packit 90a5c9
            ap_rprintf(r, "CPU:: System: %u, User: %u %s\n",
Packit 90a5c9
                    (unsigned)stats->rusage_system, (unsigned)stats->rusage_user , br);
Packit 90a5c9
            ap_rprintf(r, "Cache:: Gets: %u, Sets: %u, Hits: %u, Misses: %u %s\n",
Packit 90a5c9
                    stats->cmd_get, stats->cmd_set, stats->get_hits, stats->get_misses, br);
Packit 90a5c9
            ap_rprintf(r, "Net:: Input bytes: %" APR_UINT64_T_FMT ", Output bytes: %" APR_UINT64_T_FMT " %s\n",
Packit 90a5c9
                    stats->bytes_read, stats->bytes_written, br);
Packit 90a5c9
            ap_rprintf(r, "Misc:: Evictions: %" APR_UINT64_T_FMT ", MaxMem: %u, Threads: %u %s\n",
Packit 90a5c9
                    stats->evictions, stats->limit_maxbytes, stats->threads, br);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t socache_mc_iterate(ap_socache_instance_t *instance,
Packit 90a5c9
                                       server_rec *s, void *userctx,
Packit 90a5c9
                                       ap_socache_iterator_t *iterator,
Packit 90a5c9
                                       apr_pool_t *pool)
Packit 90a5c9
{
Packit 90a5c9
    return APR_ENOTIMPL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const ap_socache_provider_t socache_mc = {
Packit 90a5c9
    "memcache",
Packit 90a5c9
    0,
Packit 90a5c9
    socache_mc_create,
Packit 90a5c9
    socache_mc_init,
Packit 90a5c9
    socache_mc_destroy,
Packit 90a5c9
    socache_mc_store,
Packit 90a5c9
    socache_mc_retrieve,
Packit 90a5c9
    socache_mc_remove,
Packit 90a5c9
    socache_mc_status,
Packit 90a5c9
    socache_mc_iterate
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
#endif /* HAVE_APU_MEMCACHE */
Packit 90a5c9
Packit 90a5c9
static void *create_server_config(apr_pool_t *p, server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    socache_mc_svr_cfg *sconf = apr_pcalloc(p, sizeof(socache_mc_svr_cfg));
Packit 90a5c9
    
Packit 90a5c9
    sconf->ttl = MC_DEFAULT_SERVER_TTL;
Packit 90a5c9
Packit 90a5c9
    return sconf;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *socache_mc_set_ttl(cmd_parms *cmd, void *dummy,
Packit 90a5c9
                                      const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    apr_interval_time_t ttl;
Packit 90a5c9
    socache_mc_svr_cfg *sconf = ap_get_module_config(cmd->server->module_config,
Packit 90a5c9
                                                     &socache_memcache_module);
Packit 90a5c9
Packit 90a5c9
    if (ap_timeout_parameter_parse(arg, &ttl, "s") != APR_SUCCESS) {
Packit 90a5c9
        return apr_pstrcat(cmd->pool, cmd->cmd->name,
Packit 90a5c9
                           " has wrong format", NULL);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if ((ttl < apr_time_from_sec(0)) || (ttl > apr_time_from_sec(3600))) {
Packit 90a5c9
        return apr_pstrcat(cmd->pool, cmd->cmd->name,
Packit 90a5c9
                           " can only be 0 or up to one hour.", NULL);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* apr_memcache_server_create needs a ttl in usec. */
Packit 90a5c9
    sconf->ttl = ttl;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void register_hooks(apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
#ifdef HAVE_APU_MEMCACHE
Packit 90a5c9
    ap_register_provider(p, AP_SOCACHE_PROVIDER_GROUP, "memcache",
Packit 90a5c9
                         AP_SOCACHE_PROVIDER_VERSION,
Packit 90a5c9
                         &socache_mc);
Packit 90a5c9
#endif
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const command_rec socache_memcache_cmds[] = {
Packit 90a5c9
    AP_INIT_TAKE1("MemcacheConnTTL", socache_mc_set_ttl, NULL, RSRC_CONF,
Packit 90a5c9
                  "TTL used for the connection with the memcache server(s)"),
Packit 90a5c9
    { NULL }
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
AP_DECLARE_MODULE(socache_memcache) = {
Packit 90a5c9
    STANDARD20_MODULE_STUFF,
Packit 90a5c9
    NULL,                     /* create per-dir    config structures */
Packit 90a5c9
    NULL,                     /* merge  per-dir    config structures */
Packit 90a5c9
    create_server_config,     /* create per-server config structures */
Packit 90a5c9
    NULL,                     /* merge  per-server config structures */
Packit 90a5c9
    socache_memcache_cmds,    /* table of config file commands       */
Packit 90a5c9
    register_hooks            /* register hooks                      */
Packit 90a5c9
};