From: William A. Rowe Jr Date: Tue, 9 Feb 2010 03:43:18 +0000 (+0000) Subject: distcache already demonstrates sub-second resolutions, but much more X-Git-Tag: 2.3.6~500 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3cc4b9db61db7261b9fb14ba383cdeb297e43eb5;p=apache distcache already demonstrates sub-second resolutions, but much more importantly, let us not introduce more Y2k38 bugs? Changes the ->store method to take expiry as an apr_time_t, and introduce a placeholder to implement provider-specific iterators of the current elements of an socache store. Cleans up confusion where expiry might be confused with a timeout-period. Finally clean up some hUngarian noteAtion. Someones' hands need to be slapped. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@907917 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/ap_mmn.h b/include/ap_mmn.h index c7d1c7d229..327a7f6641 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -214,15 +214,16 @@ * 20091230.2 (2.3.5-dev) add ap_get_server_name_for_url() * 20091230.3 (2.3.6-dev) add ap_parse_log_level() * 20091230.4 (2.3.6-dev) export ap_process_request_after_handler() for mod_serf + * 20100208.0 (2.3.6-dev) ap_socache_provider_t API changes to store and iterate * */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ #ifndef MODULE_MAGIC_NUMBER_MAJOR -#define MODULE_MAGIC_NUMBER_MAJOR 20091230 +#define MODULE_MAGIC_NUMBER_MAJOR 20100208 #endif -#define MODULE_MAGIC_NUMBER_MINOR 4 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/ap_socache.h b/include/ap_socache.h index ceb26bb2c1..99812e30ea 100644 --- a/include/ap_socache.h +++ b/include/ap_socache.h @@ -29,6 +29,7 @@ #include "httpd.h" #include "ap_provider.h" #include "apr_pools.h" +#include "apr_time.h" #ifdef __cplusplus extern "C" { @@ -37,7 +38,10 @@ extern "C" { /** If this flag is set, the store/retrieve/remove/status interfaces * of the provider are NOT safe to be called concurrently from * multiple processes or threads, and an external global mutex must be - * used to serialize access to the provider. */ + * used to serialize access to the provider. + * XXX: Even if store/retrieve/remove is atomic, isn't it useful to note + * independently that status and iterate may or may not be? + */ #define AP_SOCACHE_FLAG_NOTMPSAFE (0x0001) /** A cache instance. */ @@ -50,11 +54,31 @@ struct ap_socache_hints { apr_size_t avg_id_len; /** Approximate average size of objects: */ apr_size_t avg_obj_size; - /** Interval (in seconds) after which an expiry run is + /** Interval after which an expiry run is * necessary. */ - time_t expiry_interval; + apr_interval_time_t expiry_interval; }; +/** + * Iterator callback prototype for the ap_socache_provider_t->iterate() method + * @param instance The cache instance (passed through) + * @param s Associated server structure (passed through) + * @param id Unique ID for the object; binary blob + * @param idlen Length of id blob + * @param data Output buffer to place retrievd data (binary blob) + * @param datalen Length of data buffer + * @param pool Pool for temporary allocations (passed through) + * @return APR status value; return APR_SUCCESS or the iteration will halt; + * this value is returned to the ap_socache_provider_t->iterate() caller + */ +typedef apr_status_t (*ap_socache_iterator_t)(ap_socache_instance_t *instance, + server_rec *s, + const unsigned char *id, + unsigned int idlen, + unsigned char *data, + unsigned int *datalen, + apr_pool_t *pool); + /** A socache provider structure. socache providers are registered * with the ap_provider.h interface using the AP_SOCACHE_PROVIDER_* * constants. */ @@ -121,7 +145,7 @@ typedef struct ap_socache_provider_t { */ apr_status_t (*store)(ap_socache_instance_t *instance, server_rec *s, const unsigned char *id, unsigned int idlen, - time_t expiry, + apr_time_t expiry, unsigned char *data, unsigned int datalen, apr_pool_t *pool); @@ -156,12 +180,28 @@ typedef struct ap_socache_provider_t { /** Dump the status of a cache instance for mod_status. Will use * the ap_r* interfaces to produce appropriate status output. + * XXX: apr_r* are deprecated, bad dogfood * * @param instance The cache instance * @param r The request structure * @param flags The AP_STATUS_* constants used (see mod_status.h) */ void (*status)(ap_socache_instance_t *instance, request_rec *r, int flags); + + /** + * Dump all cached objects through an iterator callback. + * @param instance The cache instance + * @param s Associated server structure (for logging purposes) + * @param iterator The user provided callback which will receive + * individual calls for each unexpired id/data pair + * @param pool Pool for temporary allocations. + * @return APR status value; APR_NOTFOUND if the object was not + * found + */ + apr_status_t (*iterate)(ap_socache_instance_t *instance, server_rec *s, + ap_socache_iterator_t *iterator, + apr_pool_t *pool); + } ap_socache_provider_t; /** The provider group used to register socache providers. */ diff --git a/modules/cache/mod_socache_dbm.c b/modules/cache/mod_socache_dbm.c index 63dece307d..d569c99ca7 100644 --- a/modules/cache/mod_socache_dbm.c +++ b/modules/cache/mod_socache_dbm.c @@ -44,8 +44,8 @@ struct ap_socache_instance_t { const char *data_file; /* Pool must only be used with the mutex held. */ apr_pool_t *pool; - time_t last_expiry; - time_t expiry_interval; + apr_time_t last_expiry; + apr_interval_time_t expiry_interval; }; /** @@ -136,7 +136,7 @@ static apr_status_t socache_dbm_init(ap_socache_instance_t *ctx, apr_dbm_close(dbm); ctx->expiry_interval = (hints && hints->expiry_interval - ? hints->expiry_interval : 30); + ? hints->expiry_interval : apr_time_from_sec(30)); #if AP_NEED_SET_MUTEX_PERMS /* @@ -183,7 +183,7 @@ static void socache_dbm_kill(ap_socache_instance_t *ctx, server_rec *s) static apr_status_t socache_dbm_store(ap_socache_instance_t *ctx, server_rec *s, const unsigned char *id, - unsigned int idlen, time_t expiry, + unsigned int idlen, apr_time_t expiry, unsigned char *ucaData, unsigned int nData, apr_pool_t *pool) { @@ -196,14 +196,14 @@ static apr_status_t socache_dbm_store(ap_socache_instance_t *ctx, #ifdef PAIRMAX if ((idlen + nData) >= PAIRMAX) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "data size too large for DBM session cache: %d >= %d", + "data size too large for DBM socache: %d >= %d", (idlen + nData), PAIRMAX); return APR_ENOSPC; } #else if ((idlen + nData) >= 950 /* at least less than approx. 1KB */) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "data size too large for DBM session cache: %d >= %d", + "data size too large for DBM socache: %d >= %d", (idlen + nData), 950); return APR_ENOSPC; } @@ -214,15 +214,15 @@ static apr_status_t socache_dbm_store(ap_socache_instance_t *ctx, dbmkey.dsize = idlen; /* create DBM value */ - dbmval.dsize = sizeof(time_t) + nData; + dbmval.dsize = sizeof(apr_time_t) + nData; dbmval.dptr = (char *)malloc(dbmval.dsize); if (dbmval.dptr == NULL) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "malloc error creating DBM value"); return APR_ENOMEM; } - memcpy((char *)dbmval.dptr, &expiry, sizeof(time_t)); - memcpy((char *)dbmval.dptr+sizeof(time_t), ucaData, nData); + memcpy((char *)dbmval.dptr, &expiry, sizeof(apr_time_t)); + memcpy((char *)dbmval.dptr+sizeof(apr_time_t), ucaData, nData); /* and store it to the DBM file */ apr_pool_clear(ctx->pool); @@ -264,8 +264,8 @@ static apr_status_t socache_dbm_retrieve(ap_socache_instance_t *ctx, server_rec apr_datum_t dbmkey; apr_datum_t dbmval; unsigned int nData; - time_t expiry; - time_t now; + apr_time_t expiry; + apr_time_t now; apr_status_t rc; /* allow the regular expiring to occur */ @@ -293,26 +293,26 @@ static apr_status_t socache_dbm_retrieve(ap_socache_instance_t *ctx, server_rec apr_dbm_close(dbm); return rc; } - if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(time_t)) { + if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(apr_time_t)) { apr_dbm_close(dbm); return APR_EGENERAL; } /* parse resulting data */ - nData = dbmval.dsize-sizeof(time_t); + nData = dbmval.dsize-sizeof(apr_time_t); if (nData > *destlen) { apr_dbm_close(dbm); return APR_ENOSPC; } *destlen = nData; - memcpy(&expiry, dbmval.dptr, sizeof(time_t)); - memcpy(dest, (char *)dbmval.dptr + sizeof(time_t), nData); + memcpy(&expiry, dbmval.dptr, sizeof(apr_time_t)); + memcpy(dest, (char *)dbmval.dptr + sizeof(apr_time_t), nData); apr_dbm_close(dbm); /* make sure the stuff is still not expired */ - now = time(NULL); + now = apr_time_now(); if (expiry <= now) { socache_dbm_remove(ctx, s, id, idlen, p); return APR_NOTFOUND; @@ -355,27 +355,27 @@ static void socache_dbm_expire(ap_socache_instance_t *ctx, server_rec *s) apr_dbm_t *dbm; apr_datum_t dbmkey; apr_datum_t dbmval; - time_t tExpiresAt; - int nElements = 0; - int nDeleted = 0; - int bDelete; + apr_time_t expiry; + int elts = 0; + int deleted = 0; + int expired; apr_datum_t *keylist; int keyidx; int i; - time_t tNow; + apr_time_t now; apr_status_t rv; /* - * make sure the expiration for still not-accessed session - * cache entries is done only from time to time + * make sure the expiration for still not-accessed + * socache entries is done only from time to time */ - tNow = time(NULL); + now = time(NULL); - if (tNow < ctx->last_expiry + ctx->expiry_interval) { + if (now < ctx->last_expiry + ctx->expiry_interval) { return; } - ctx->last_expiry = tNow; + ctx->last_expiry = now; /* * Here we have to be very carefully: Not all DBM libraries are @@ -410,17 +410,17 @@ static void socache_dbm_expire(ap_socache_instance_t *ctx, server_rec *s) } apr_dbm_firstkey(dbm, &dbmkey); while (dbmkey.dptr != NULL) { - nElements++; - bDelete = FALSE; + elts++; + expired = FALSE; apr_dbm_fetch(dbm, dbmkey, &dbmval); - if (dbmval.dsize <= sizeof(time_t) || dbmval.dptr == NULL) - bDelete = TRUE; + if (dbmval.dsize <= sizeof(apr_time_t) || dbmval.dptr == NULL) + expired = TRUE; else { - memcpy(&tExpiresAt, dbmval.dptr, sizeof(time_t)); - if (tExpiresAt <= tNow) - bDelete = TRUE; + memcpy(&expiry, dbmval.dptr, sizeof(apr_time_t)); + if (expiry <= now) + expired = TRUE; } - if (bDelete) { + if (expired) { if ((keylist[keyidx].dptr = apr_pmemdup(ctx->pool, dbmkey.dptr, dbmkey.dsize)) != NULL) { keylist[keyidx].dsize = dbmkey.dsize; keyidx++; @@ -443,7 +443,7 @@ static void socache_dbm_expire(ap_socache_instance_t *ctx, server_rec *s) } for (i = 0; i < keyidx; i++) { apr_dbm_delete(dbm, keylist[i]); - nDeleted++; + deleted++; } apr_dbm_close(dbm); @@ -454,7 +454,7 @@ static void socache_dbm_expire(ap_socache_instance_t *ctx, server_rec *s) ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Inter-Process Session Cache (DBM) Expiry: " "old: %d, new: %d, removed: %d", - nElements, nElements-nDeleted, nDeleted); + elts, elts-deleted, deleted); } static void socache_dbm_status(ap_socache_instance_t *ctx, request_rec *r, @@ -463,13 +463,13 @@ static void socache_dbm_status(ap_socache_instance_t *ctx, request_rec *r, apr_dbm_t *dbm; apr_datum_t dbmkey; apr_datum_t dbmval; - int nElem; - int nSize; - int nAverage; + int elts; + long size; + int avg; apr_status_t rv; - nElem = 0; - nSize = 0; + elts = 0; + size = 0; apr_pool_clear(ctx->pool); if ((rv = apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE, @@ -488,20 +488,28 @@ static void socache_dbm_status(ap_socache_instance_t *ctx, request_rec *r, apr_dbm_fetch(dbm, dbmkey, &dbmval); if (dbmval.dptr == NULL) continue; - nElem += 1; - nSize += dbmval.dsize; + elts += 1; + size += dbmval.dsize; } apr_dbm_close(dbm); - if (nSize > 0 && nElem > 0) - nAverage = nSize / nElem; + if (size > 0 && elts > 0) + avg = (int)(size / (long)elts); else - nAverage = 0; + avg = 0; ap_rprintf(r, "cache type: DBM, maximum size: unlimited
"); - ap_rprintf(r, "current sessions: %d, current size: %d bytes
", nElem, nSize); - ap_rprintf(r, "average session size: %d bytes
", nAverage); + ap_rprintf(r, "current entries: %d, current size: %ld bytes
", elts, size); + ap_rprintf(r, "average entry size: %d bytes
", avg); return; } +apr_status_t socache_dbm_iterate(ap_socache_instance_t *instance, + server_rec *s, + ap_socache_iterator_t *iterator, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + static const ap_socache_provider_t socache_dbm = { "dbm", AP_SOCACHE_FLAG_NOTMPSAFE, @@ -511,7 +519,8 @@ static const ap_socache_provider_t socache_dbm = { socache_dbm_store, socache_dbm_retrieve, socache_dbm_remove, - socache_dbm_status + socache_dbm_status, + socache_dbm_iterate }; static void register_hooks(apr_pool_t *p) diff --git a/modules/cache/mod_socache_dc.c b/modules/cache/mod_socache_dc.c index f7d78645a4..91056cc854 100644 --- a/modules/cache/mod_socache_dc.c +++ b/modules/cache/mod_socache_dc.c @@ -92,15 +92,18 @@ static void socache_dc_kill(ap_socache_instance_t *ctx, server_rec *s) static apr_status_t socache_dc_store(ap_socache_instance_t *ctx, server_rec *s, const unsigned char *id, unsigned int idlen, - time_t timeout, + time_t expiry, unsigned char *der, unsigned int der_len, apr_pool_t *p) { - /* !@#$%^ - why do we deal with *absolute* time anyway??? */ - timeout -= time(NULL); + /* !@#$%^ - why do we deal with *absolute* time anyway??? + * Uhm - because most things expire things at a specific time? + * Were the API were thought out expiry - r->request_time is a good approximation + */ + expiry -= apr_time_t(NULL); /* Send the serialised session to the distributed cache context */ if (!DC_CTX_add_session(ctx->dc, id, idlen, der, der_len, - (unsigned long)timeout * 1000)) { + apr_time_in_msec(expiry)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache 'add_session' failed"); return APR_EGENERAL; } @@ -151,6 +154,14 @@ static void socache_dc_status(ap_socache_instance_t *ctx, request_rec *r, int fl " target: %s
", ctx->target); } +apr_status_t socache_dc_iterate(ap_socache_instance_t *instance, + server_rec *s, + ap_socache_iterator_t *iterator, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + static const ap_socache_provider_t socache_dc = { "distcache", 0, @@ -160,7 +171,8 @@ static const ap_socache_provider_t socache_dc = { socache_dc_store, socache_dc_retrieve, socache_dc_remove, - socache_dc_status + socache_dc_status, + socache_dc_iterate }; static void register_hooks(apr_pool_t *p) diff --git a/modules/cache/mod_socache_memcache.c b/modules/cache/mod_socache_memcache.c index e1511cd35a..f51c7f6831 100644 --- a/modules/cache/mod_socache_memcache.c +++ b/modules/cache/mod_socache_memcache.c @@ -200,7 +200,7 @@ static int socache_mc_id2key(ap_socache_instance_t *ctx, static apr_status_t socache_mc_store(ap_socache_instance_t *ctx, server_rec *s, const unsigned char *id, unsigned int idlen, - time_t timeout, + apr_time_t expiry, unsigned char *ucaData, unsigned int nData, apr_pool_t *p) { @@ -211,7 +211,8 @@ static apr_status_t socache_mc_store(ap_socache_instance_t *ctx, server_rec *s, return APR_EINVAL; } - rv = apr_memcache_set(ctx->mc, buf, (char*)ucaData, nData, timeout, 0); + /* In APR-util - unclear what 'timeout' is, as it was not implemented */ + rv = apr_memcache_set(ctx->mc, buf, (char*)ucaData, nData, 0, 0); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, @@ -286,6 +287,14 @@ static void socache_mc_status(ap_socache_instance_t *ctx, request_rec *r, int fl /* TODO: Make a mod_status handler. meh. */ } +apr_status_t socache_mc_iterate(ap_socache_instance_t *instance, + server_rec *s, + ap_socache_iterator_t *iterator, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + static const ap_socache_provider_t socache_mc = { "memcache", 0, @@ -295,7 +304,8 @@ static const ap_socache_provider_t socache_mc = { socache_mc_store, socache_mc_retrieve, socache_mc_remove, - socache_mc_status + socache_mc_status, + socache_mc_iterate }; #endif /* HAVE_APU_MEMCACHE */ diff --git a/modules/cache/mod_socache_shmcb.c b/modules/cache/mod_socache_shmcb.c index 4000939ec2..94ee400296 100644 --- a/modules/cache/mod_socache_shmcb.c +++ b/modules/cache/mod_socache_shmcb.c @@ -80,14 +80,14 @@ typedef struct { */ typedef struct { /* absolute time this entry expires */ - time_t expires; + apr_time_t expires; /* location within the subcache's data area */ unsigned int data_pos; /* size (most logic ignores this, we keep it only to minimise memcpy) */ unsigned int data_used; /* length of the used data which contains the id */ unsigned int id_len; - /* Used to mark explicitly-removed sessions */ + /* Used to mark explicitly-removed socache entries */ unsigned char removed; } SHMCBIndex; @@ -147,7 +147,7 @@ struct ap_socache_instance_t { sizeof(SHMCBHeader) + \ (num) * ((pHeader)->subcache_size)) -/* This macro takes a pointer to the header and a session id and returns a +/* This macro takes a pointer to the header and an id and returns a * pointer to the corresponding subcache. */ #define SHMCB_MASK(pHeader, id) \ SHMCB_SUBCACHE((pHeader), *(id) & ((pHeader)->subcache_num - 1)) @@ -239,13 +239,14 @@ static int shmcb_cyclic_memcmp(unsigned int buf_size, unsigned char *data, /* Prototypes for low-level subcache operations */ -static void shmcb_subcache_expire(server_rec *, SHMCBHeader *, SHMCBSubcache *); +static void shmcb_subcache_expire(server_rec *, SHMCBHeader *, SHMCBSubcache *, + apr_time_t); /* Returns zero on success, non-zero on failure. */ static int shmcb_subcache_store(server_rec *s, SHMCBHeader *header, SHMCBSubcache *subcache, unsigned char *data, unsigned int data_len, const unsigned char *id, unsigned int id_len, - time_t expiry); + apr_time_t expiry); /* Returns zero on success, non-zero on failure. */ static int shmcb_subcache_retrieve(server_rec *, SHMCBHeader *, SHMCBSubcache *, const unsigned char *id, unsigned int idlen, @@ -437,7 +438,7 @@ static apr_status_t socache_shmcb_init(ap_socache_instance_t *ctx, subcache->data_pos = subcache->data_used = 0; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "Shared memory session cache initialised"); + "Shared memory socache initialised"); /* Success ... */ return APR_SUCCESS; @@ -453,7 +454,7 @@ static void socache_shmcb_kill(ap_socache_instance_t *ctx, server_rec *s) static apr_status_t socache_shmcb_store(ap_socache_instance_t *ctx, server_rec *s, const unsigned char *id, - unsigned int idlen, time_t timeout, + unsigned int idlen, apr_time_t expiry, unsigned char *encoded, unsigned int len_encoded, apr_pool_t *p) @@ -464,15 +465,16 @@ static apr_status_t socache_shmcb_store(ap_socache_instance_t *ctx, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "socache_shmcb_store (0x%02x -> subcache %d)", SHMCB_MASK_DBG(header, id)); + /* XXX: Says who? Why shouldn't this be acceptable, or padded if not? */ if (idlen < 4) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short id provided " "(%u bytes)", idlen); return APR_EINVAL; } if (shmcb_subcache_store(s, header, subcache, encoded, - len_encoded, id, idlen, timeout)) { + len_encoded, id, idlen, expiry)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "can't store a session!"); + "can't store an socache entry!"); return APR_ENOSPC; } header->stat_stores++; @@ -495,7 +497,7 @@ static apr_status_t socache_shmcb_retrieve(ap_socache_instance_t *ctx, "socache_shmcb_retrieve (0x%02x -> subcache %d)", SHMCB_MASK_DBG(header, id)); - /* Get the session corresponding to the session_id, if it exists. */ + /* Get the entry corresponding to the id, if it exists. */ rv = shmcb_subcache_retrieve(s, header, subcache, id, idlen, dest, destlen); if (rv == 0) @@ -520,7 +522,7 @@ static apr_status_t socache_shmcb_remove(ap_socache_instance_t *ctx, "socache_shmcb_remove (0x%02x -> subcache %d)", SHMCB_MASK_DBG(header, id)); if (idlen < 4) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short id provided " "(%u bytes)", idlen); return APR_EINVAL; } @@ -543,8 +545,8 @@ static void socache_shmcb_status(ap_socache_instance_t *ctx, server_rec *s = r->server; SHMCBHeader *header = ctx->header; unsigned int loop, total = 0, cache_total = 0, non_empty_subcaches = 0; - time_t idx_expiry, min_expiry = 0, max_expiry = 0, average_expiry = 0; - time_t now = time(NULL); + apr_time_t idx_expiry, min_expiry = 0, max_expiry = 0, average_expiry = 0; + apr_time_t now = apr_time_now(); double expiry_total = 0; int index_pct, cache_pct; @@ -555,7 +557,7 @@ static void socache_shmcb_status(ap_socache_instance_t *ctx, /* Iterate over the subcaches */ for (loop = 0; loop < header->subcache_num; loop++) { SHMCBSubcache *subcache = SHMCB_SUBCACHE(header, loop); - shmcb_subcache_expire(s, header, subcache); + shmcb_subcache_expire(s, header, subcache, now); total += subcache->idx_used; cache_total += subcache->data_used; if (subcache->idx_used) { @@ -576,29 +578,29 @@ static void socache_shmcb_status(ap_socache_instance_t *ctx, header->subcache_num); /* Generate HTML */ ap_rprintf(r, "cache type: SHMCB, shared memory: %" APR_SIZE_T_FMT " " - "bytes, current sessions: %d
", + "bytes, current entries: %d
", ctx->shm_size, total); ap_rprintf(r, "subcaches: %d, indexes per subcache: %d
", header->subcache_num, header->index_num); if (non_empty_subcaches) { - average_expiry = (time_t)(expiry_total / (double)non_empty_subcaches); + average_expiry = (apr_time_t)(expiry_total / (double)non_empty_subcaches); ap_rprintf(r, "time left on oldest entries' objects: "); if (now < average_expiry) ap_rprintf(r, "avg: %d seconds, (range: %d...%d)
", - (int)(average_expiry - now), - (int)(min_expiry - now), - (int)(max_expiry - now)); + (int)apr_time_sec(average_expiry - now), + (int)apr_time_sec(min_expiry - now), + (int)apr_time_sec(max_expiry - now)); else ap_rprintf(r, "expiry_threshold: Calculation error!
"); } ap_rprintf(r, "index usage: %d%%, cache usage: %d%%
", index_pct, cache_pct); - ap_rprintf(r, "total sessions stored since starting: %lu
", + ap_rprintf(r, "total entries stored since starting: %lu
", header->stat_stores); - ap_rprintf(r, "total sessions expired since starting: %lu
", + ap_rprintf(r, "total entries expired since starting: %lu
", header->stat_expiries); - ap_rprintf(r, "total (pre-expiry) sessions scrolled out of the cache: " + ap_rprintf(r, "total (pre-expiry) entries scrolled out of the cache: " "%lu
", header->stat_scrolled); ap_rprintf(r, "total retrieves since starting: %lu hit, " "%lu miss
", header->stat_retrieves_hit, @@ -614,9 +616,8 @@ static void socache_shmcb_status(ap_socache_instance_t *ctx, */ static void shmcb_subcache_expire(server_rec *s, SHMCBHeader *header, - SHMCBSubcache *subcache) + SHMCBSubcache *subcache, apr_time_t now) { - time_t now = time(NULL); unsigned int loop = 0; unsigned int new_idx_pos = subcache->idx_pos; SHMCBIndex *idx = NULL; @@ -633,7 +634,7 @@ static void shmcb_subcache_expire(server_rec *s, SHMCBHeader *header, /* Nothing to do */ return; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "will be expiring %u sessions", loop); + "will be expiring %u socache entries", loop); if (loop == subcache->idx_used) { /* We're expiring everything, piece of cake */ subcache->idx_used = 0; @@ -652,14 +653,56 @@ static void shmcb_subcache_expire(server_rec *s, SHMCBHeader *header, } header->stat_expiries += loop; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "we now have %u sessions", subcache->idx_used); + "we now have %u socache entries", subcache->idx_used); +} + +static void shmcb_subcache_iterate(server_rec *s, SHMCBHeader *header, + SHMCBSubcache *subcache) +{ + apr_time_t now = apr_time_now(); + unsigned int loop = 0; + unsigned int new_idx_pos = subcache->idx_pos; + SHMCBIndex *idx = NULL; + + while (loop < subcache->idx_used) { + idx = SHMCB_INDEX(subcache, new_idx_pos); + if (idx->expires > now) + /* it hasn't expired yet, we're done iterating */ + break; + loop++; + new_idx_pos = SHMCB_CYCLIC_INCREMENT(new_idx_pos, 1, header->index_num); + } + if (!loop) + /* Nothing to do */ + return; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "will be expiring %u socache entries", loop); + if (loop == subcache->idx_used) { + /* We're expiring everything, piece of cake */ + subcache->idx_used = 0; + subcache->data_used = 0; + } else { + /* There remain other indexes, so we can use idx to adjust 'data' */ + unsigned int diff = SHMCB_CYCLIC_SPACE(subcache->data_pos, + idx->data_pos, + header->subcache_data_size); + /* Adjust the indexes */ + subcache->idx_used -= loop; + subcache->idx_pos = new_idx_pos; + /* Adjust the data area */ + subcache->data_used -= diff; + subcache->data_pos = idx->data_pos; + } + header->stat_expiries += loop; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "we now have %u socache entries", subcache->idx_used); } static int shmcb_subcache_store(server_rec *s, SHMCBHeader *header, SHMCBSubcache *subcache, unsigned char *data, unsigned int data_len, const unsigned char *id, unsigned int id_len, - time_t expiry) + apr_time_t expiry) { unsigned int data_offset, new_idx, id_offset; SHMCBIndex *idx; @@ -668,13 +711,13 @@ static int shmcb_subcache_store(server_rec *s, SHMCBHeader *header, /* Sanity check the input */ if (total_len > header->subcache_data_size) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "inserting session larger (%d) than subcache data area (%d)", + "inserting socache entry larger (%d) than subcache data area (%d)", total_len, header->subcache_data_size); return -1; } /* If there are entries to expire, ditch them first. */ - shmcb_subcache_expire(s, header, subcache); + shmcb_subcache_expire(s, header, subcache, apr_time_now()); /* Loop until there is enough space to insert */ if (header->subcache_data_size - subcache->data_used < total_len @@ -718,11 +761,15 @@ static int shmcb_subcache_store(server_rec *s, SHMCBHeader *header, * CHECKING WHETHER IT SHOULD BE GENUINELY "INSERTED" SOMEWHERE. * * We either fix that, or find out at a "higher" (read "mod_ssl") - * level whether it is possible to have distinct session caches for - * any attempted tomfoolery to do with different session timeouts. - * Knowing in advance that we can have a cache-wide constant timeout + * level whether it is possible to have distinct socaches for + * any attempted tomfoolery to do with different socache entry expirys. + * Knowing in advance that we can have a cache-wide constant expiry * would make this stuff *MUCH* more efficient. Mind you, it's very * efficient right now because I'm ignoring this problem!!! + * + * XXX: Author didn't consider that httpd doesn't promise to perform + * any processing in date order (c.f. FAQ "My log entries are not in + * date order!") */ /* Insert the id */ id_offset = SHMCB_CYCLIC_INCREMENT(subcache->data_pos, subcache->data_used, @@ -767,8 +814,11 @@ static int shmcb_subcache_retrieve(server_rec *s, SHMCBHeader *header, unsigned int pos; unsigned int loop = 0; - /* If there are entries to expire, ditch them first. */ - shmcb_subcache_expire(s, header, subcache); + /* If there are entries to expire, ditch them first. + * XXX: Horribly inefficient to double the work, why not simply + * upon store when free space might be useful? + */ + shmcb_subcache_expire(s, header, subcache, apr_time_now()); pos = subcache->idx_pos; while (loop < subcache->idx_used) { @@ -823,7 +873,7 @@ static int shmcb_subcache_remove(server_rec *s, SHMCBHeader *header, * consistent statistics where a "remove" operation may actually be the * higher layer spotting an expiry issue prior to us. Our caller is * handling stats, so a failure return would be inconsistent if the - * intended session was in fact removed by an expiry run. */ + * intended socache entry was in fact removed by an expiry run. */ pos = subcache->idx_pos; while (loop < subcache->idx_used) { @@ -837,10 +887,10 @@ static int shmcb_subcache_remove(server_rec *s, SHMCBHeader *header, idx->data_pos, id, idx->id_len) == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "possible match at idx=%d, data=%d", pos, idx->data_pos); - /* Found the matching session, remove it quietly. */ + /* Found the matching entry, remove it quietly. */ idx->removed = 1; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "shmcb_subcache_remove removing matching session"); + "shmcb_subcache_remove removing matching entry"); return 0; } /* Increment */ @@ -851,6 +901,14 @@ static int shmcb_subcache_remove(server_rec *s, SHMCBHeader *header, return -1; /* failure */ } +apr_status_t socache_shmcb_iterate(ap_socache_instance_t *instance, + server_rec *s, + ap_socache_iterator_t *iterator, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + static const ap_socache_provider_t socache_shmcb = { "shmcb", AP_SOCACHE_FLAG_NOTMPSAFE, @@ -860,7 +918,8 @@ static const ap_socache_provider_t socache_shmcb = { socache_shmcb_store, socache_shmcb_retrieve, socache_shmcb_remove, - socache_shmcb_status + socache_shmcb_status, + socache_shmcb_iterate }; static void register_hooks(apr_pool_t *p)