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;
};
/**
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
/*
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)
{
#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;
}
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);
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 */
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;
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
}
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++;
}
for (i = 0; i < keyidx; i++) {
apr_dbm_delete(dbm, keylist[i]);
- nDeleted++;
+ deleted++;
}
apr_dbm_close(dbm);
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,
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,
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: <b>DBM</b>, maximum size: <b>unlimited</b><br>");
- ap_rprintf(r, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize);
- ap_rprintf(r, "average session size: <b>%d</b> bytes<br>", nAverage);
+ ap_rprintf(r, "current entries: <b>%d</b>, current size: <b>%ld</b> bytes<br>", elts, size);
+ ap_rprintf(r, "average entry size: <b>%d</b> bytes<br>", 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,
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)
*/
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;
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))
/* 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,
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;
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)
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++;
"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)
"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;
}
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;
/* 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) {
header->subcache_num);
/* Generate HTML */
ap_rprintf(r, "cache type: <b>SHMCB</b>, shared memory: <b>%" APR_SIZE_T_FMT "</b> "
- "bytes, current sessions: <b>%d</b><br>",
+ "bytes, current entries: <b>%d</b><br>",
ctx->shm_size, total);
ap_rprintf(r, "subcaches: <b>%d</b>, indexes per subcache: <b>%d</b><br>",
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: <b>%d</b> seconds, (range: %d...%d)<br>",
- (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: <b>Calculation error!</b><br>");
}
ap_rprintf(r, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b><br>",
index_pct, cache_pct);
- ap_rprintf(r, "total sessions stored since starting: <b>%lu</b><br>",
+ ap_rprintf(r, "total entries stored since starting: <b>%lu</b><br>",
header->stat_stores);
- ap_rprintf(r, "total sessions expired since starting: <b>%lu</b><br>",
+ ap_rprintf(r, "total entries expired since starting: <b>%lu</b><br>",
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: "
"<b>%lu</b><br>", header->stat_scrolled);
ap_rprintf(r, "total retrieves since starting: <b>%lu</b> hit, "
"<b>%lu</b> miss<br>", header->stat_retrieves_hit,
*/
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;
/* 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;
}
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;
/* 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
* 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,
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) {
* 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) {
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 */
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,
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)