1
0
mirror of https://github.com/apache/httpd.git synced 2025-11-06 16:49:32 +03:00

Get a rid of the oversized cache.

The new map-cache consists of a simple two-tiered apr_hash structure.
cachep->maps contains entries for each map, which point to a hash with
the actual values (map->entries).

Each map->entries hash lives in a subpool of cachep->pool.
The mtime is stored per map and if the map expires, we just clear
map->pool and create a fresh map->entries hash structure.

This removes a big chunk of code from mod_rewrite, improves readability and
even the memory footprint of the cache.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@100801 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
André Malo
2003-07-27 22:12:49 +00:00
parent b863e3a2db
commit d4b1817c38

View File

@@ -192,12 +192,6 @@
#define OPTION_NONE 1<<0 #define OPTION_NONE 1<<0
#define OPTION_INHERIT 1<<1 #define OPTION_INHERIT 1<<1
#define CACHEMODE_TS 1<<0
#define CACHEMODE_TTL 1<<1
#define CACHE_TLB_ROWS 1024
#define CACHE_TLB_COLS 4
#ifndef RAND_MAX #ifndef RAND_MAX
#define RAND_MAX 32767 #define RAND_MAX 32767
#endif #endif
@@ -293,33 +287,25 @@ typedef struct {
} rewrite_request_conf; } rewrite_request_conf;
/* the cache structures, /* the (per-child) cache structures.
* a 4-way hash apr_table_t with LRU functionality
*/ */
typedef struct cacheentry {
apr_time_t time;
char *key;
char *value;
} cacheentry;
typedef struct tlbentry {
int t[CACHE_TLB_COLS];
} cachetlbentry;
typedef struct cachelist {
char *resource;
apr_array_header_t *entries;
apr_array_header_t *tlb;
} cachelist;
typedef struct cache { typedef struct cache {
apr_pool_t *pool; apr_pool_t *pool;
apr_array_header_t *lists; apr_hash_t *maps;
#if APR_HAS_THREADS #if APR_HAS_THREADS
apr_thread_mutex_t *lock; apr_thread_mutex_t *lock;
#endif #endif
} cache; } cache;
/* cached maps contain an mtime for the whole map and live in a subpool
* of the cachep->pool. That makes it easy to forget them if necessary.
*/
typedef struct {
apr_time_t mtime;
apr_pool_t *pool;
apr_hash_t *entries;
} cachedmap;
/* the regex structure for the /* the regex structure for the
* substitution of backreferences * substitution of backreferences
*/ */
@@ -933,223 +919,110 @@ static char *subst_prefix_path(request_rec *r, char *input, char *match,
* +-------------------------------------------------------+ * +-------------------------------------------------------+
*/ */
static int cache_tlb_hash(char *key) static void set_cache_value(const char *name, apr_time_t t, char *key,
char *val)
{ {
unsigned long n; cachedmap *map;
char *p;
n = 0;
for (p = key; *p != '\0'; p++) {
n = ((n << 5) + n) ^ (unsigned long)(*p++);
}
return n % CACHE_TLB_ROWS;
}
static cacheentry *cache_tlb_lookup(cachetlbentry *tlb, cacheentry *elt,
char *key)
{
int ix = cache_tlb_hash(key);
int i;
int j;
for (i=0; i < CACHE_TLB_COLS; ++i) {
j = tlb[ix].t[i];
if (j < 0)
return NULL;
if (strcmp(elt[j].key, key) == 0)
return &elt[j];
}
return NULL;
}
static void cache_tlb_replace(cachetlbentry *tlb, cacheentry *elt,
cacheentry *e)
{
int ix = cache_tlb_hash(e->key);
int i;
tlb = &tlb[ix];
for (i=1; i < CACHE_TLB_COLS; ++i)
tlb->t[i] = tlb->t[i-1];
tlb->t[0] = e - elt;
}
static cacheentry *retrieve_cache_string(cache *c, const char *res, char *key)
{
int i;
int j;
cachelist *l;
cacheentry *e;
if (cachep) {
#if APR_HAS_THREADS #if APR_HAS_THREADS
apr_thread_mutex_lock(c->lock); apr_thread_mutex_lock(cachep->lock);
#endif #endif
map = apr_hash_get(cachep->maps, name, APR_HASH_KEY_STRING);
for (i = 0; i < c->lists->nelts; i++) { if (!map) {
l = &(((cachelist *)c->lists->elts)[i]); apr_pool_t *p;
if (strcmp(l->resource, res) == 0) {
e = cache_tlb_lookup((cachetlbentry *)l->tlb->elts, if (apr_pool_create(&p, cachep->pool) != APR_SUCCESS) {
(cacheentry *)l->entries->elts, key);
if (e != NULL) {
#if APR_HAS_THREADS #if APR_HAS_THREADS
apr_thread_mutex_unlock(c->lock); apr_thread_mutex_unlock(cachep->lock);
#endif
return e;
}
for (j = 0; j < l->entries->nelts; j++) {
e = &(((cacheentry *)l->entries->elts)[j]);
if (strcmp(e->key, key) == 0) {
#if APR_HAS_THREADS
apr_thread_mutex_unlock(c->lock);
#endif
return e;
}
}
}
}
#if APR_HAS_THREADS
apr_thread_mutex_unlock(c->lock);
#endif
return NULL;
}
static void store_cache_string(cache *c, const char *res, cacheentry *ce)
{
int i;
int j;
cachelist *l;
cacheentry *e;
cachetlbentry *t;
int found_list;
#if APR_HAS_THREADS
apr_thread_mutex_lock(c->lock);
#endif
found_list = 0;
/* first try to edit an existing entry */
for (i = 0; i < c->lists->nelts; i++) {
l = &(((cachelist *)c->lists->elts)[i]);
if (strcmp(l->resource, res) == 0) {
found_list = 1;
e = cache_tlb_lookup((cachetlbentry *)l->tlb->elts,
(cacheentry *)l->entries->elts, ce->key);
if (e != NULL) {
e->time = ce->time;
e->value = apr_pstrdup(c->pool, ce->value);
#if APR_HAS_THREADS
apr_thread_mutex_unlock(c->lock);
#endif #endif
return; return;
} }
for (j = 0; j < l->entries->nelts; j++) { map = apr_palloc(cachep->pool, sizeof(cachedmap));
e = &(((cacheentry *)l->entries->elts)[j]); map->pool = p;
if (strcmp(e->key, ce->key) == 0) { map->entries = apr_hash_make(map->pool);
e->time = ce->time; map->mtime = t;
e->value = apr_pstrdup(c->pool, ce->value);
cache_tlb_replace((cachetlbentry *)l->tlb->elts, apr_hash_set(cachep->maps, name, APR_HASH_KEY_STRING, map);
(cacheentry *)l->entries->elts, e); }
else if (map->mtime != t) {
apr_pool_clear(map->pool);
map->entries = apr_hash_make(map->pool);
map->mtime = t;
}
/* Now we should have a valid map->entries hash, where we
* can store our value.
*
* We need to copy the key and the value into OUR pool,
* so that we don't leave it during the r->pool cleanup.
*/
apr_hash_set(map->entries,
apr_pstrdup(map->pool, key), APR_HASH_KEY_STRING,
apr_pstrdup(map->pool, val));
#if APR_HAS_THREADS #if APR_HAS_THREADS
apr_thread_mutex_unlock(c->lock); apr_thread_mutex_unlock(cachep->lock);
#endif #endif
return; }
return;
}
static char *get_cache_value(const char *name, apr_time_t t, char *key,
apr_pool_t *p)
{
cachedmap *map;
char *val = NULL;
if (cachep) {
#if APR_HAS_THREADS
apr_thread_mutex_lock(cachep->lock);
#endif
map = apr_hash_get(cachep->maps, name, APR_HASH_KEY_STRING);
if (map) {
/* if this map is outdated, forget it. */
if (map->mtime != t) {
apr_pool_clear(map->pool);
map->entries = apr_hash_make(map->pool);
map->mtime = t;
}
else {
val = apr_hash_get(map->entries, key, APR_HASH_KEY_STRING);
if (val) {
/* copy the cached value into the supplied pool,
* where it belongs (r->pool usually)
*/
val = apr_pstrdup(p, val);
} }
} }
} }
}
/* create a needed new list */
if (!found_list) {
l = apr_array_push(c->lists);
l->resource = apr_pstrdup(c->pool, res);
l->entries = apr_array_make(c->pool, 2, sizeof(cacheentry));
l->tlb = apr_array_make(c->pool, CACHE_TLB_ROWS,
sizeof(cachetlbentry));
for (i=0; i<CACHE_TLB_ROWS; ++i) {
t = &((cachetlbentry *)l->tlb->elts)[i];
for (j=0; j<CACHE_TLB_COLS; ++j)
t->t[j] = -1;
}
}
/* create the new entry */
for (i = 0; i < c->lists->nelts; i++) {
l = &(((cachelist *)c->lists->elts)[i]);
if (strcmp(l->resource, res) == 0) {
e = apr_array_push(l->entries);
e->time = ce->time;
e->key = apr_pstrdup(c->pool, ce->key);
e->value = apr_pstrdup(c->pool, ce->value);
cache_tlb_replace((cachetlbentry *)l->tlb->elts,
(cacheentry *)l->entries->elts, e);
#if APR_HAS_THREADS #if APR_HAS_THREADS
apr_thread_mutex_unlock(c->lock); apr_thread_mutex_unlock(cachep->lock);
#endif #endif
return;
}
} }
/* not reached, but when it is no problem... */ return val;
#if APR_HAS_THREADS
apr_thread_mutex_unlock(c->lock);
#endif
return;
} }
static void set_cache_string(cache *c, const char *res, int mode, apr_time_t t, static int init_cache(apr_pool_t *p)
char *key, char *value)
{ {
cacheentry ce; cachep = apr_palloc(p, sizeof(cache));
if (apr_pool_create(&cachep->pool, p) != APR_SUCCESS) {
ce.time = t; cachep = NULL; /* turns off cache */
ce.key = key; return 0;
ce.value = value;
store_cache_string(c, res, &ce);
return;
}
static char *get_cache_string(cache *c, const char *res, int mode,
apr_time_t t, char *key)
{
cacheentry *ce;
ce = retrieve_cache_string(c, res, key);
if (ce == NULL) {
return NULL;
} }
if (mode & CACHEMODE_TS) {
if (t != ce->time) {
return NULL;
}
}
else if (mode & CACHEMODE_TTL) {
if (t > ce->time) {
return NULL;
}
}
return apr_pstrdup(c->pool, ce->value);
}
static cache *init_cache(apr_pool_t *p) cachep->maps = apr_hash_make(cachep->pool);
{
cache *c;
c = (cache *)apr_palloc(p, sizeof(cache));
if (apr_pool_create(&c->pool, p) != APR_SUCCESS) {
return NULL;
}
c->lists = apr_array_make(c->pool, 2, sizeof(cachelist));
#if APR_HAS_THREADS #if APR_HAS_THREADS
(void)apr_thread_mutex_create(&(c->lock), APR_THREAD_MUTEX_DEFAULT, p); (void)apr_thread_mutex_create(&(cachep->lock), APR_THREAD_MUTEX_DEFAULT, p);
#endif #endif
return c;
return 1;
} }
@@ -1563,7 +1436,7 @@ static char *lookup_map(request_rec *r, char *name, char *key)
return NULL; return NULL;
} }
value = get_cache_string(cachep, name, CACHEMODE_TS, st.mtime, key); value = get_cache_value(name, st.mtime, key, r->pool);
if (!value) { if (!value) {
rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup"); rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup");
@@ -1571,13 +1444,13 @@ static char *lookup_map(request_rec *r, char *name, char *key)
if (!value) { if (!value) {
rewritelog(r, 5, "map lookup FAILED: map=%s[txt] key=%s", rewritelog(r, 5, "map lookup FAILED: map=%s[txt] key=%s",
name, key); name, key);
set_cache_string(cachep, name, CACHEMODE_TS, st.mtime, key, ""); set_cache_value(name, st.mtime, key, "");
return NULL; return NULL;
} }
rewritelog(r, 5, "map lookup OK: map=%s key=%s[txt] -> val=%s", rewritelog(r, 5, "map lookup OK: map=%s[txt] key=%s -> val=%s",
name, key, value); name, key, value);
set_cache_string(cachep, name, CACHEMODE_TS, st.mtime, key, value); set_cache_value(name, st.mtime, key, value);
} }
else { else {
rewritelog(r, 5, "cache lookup OK: map=%s[txt] key=%s -> val=%s", rewritelog(r, 5, "cache lookup OK: map=%s[txt] key=%s -> val=%s",
@@ -1604,7 +1477,7 @@ static char *lookup_map(request_rec *r, char *name, char *key)
return NULL; return NULL;
} }
value = get_cache_string(cachep, name, CACHEMODE_TS, st.mtime, key); value = get_cache_value(name, st.mtime, key, r->pool);
if (!value) { if (!value) {
rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup"); rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup");
@@ -1612,13 +1485,13 @@ static char *lookup_map(request_rec *r, char *name, char *key)
if (!value) { if (!value) {
rewritelog(r, 5, "map lookup FAILED: map=%s[dbm] key=%s", rewritelog(r, 5, "map lookup FAILED: map=%s[dbm] key=%s",
name, key); name, key);
set_cache_string(cachep, name, CACHEMODE_TS, st.mtime, key, ""); set_cache_value(name, st.mtime, key, "");
return NULL; return NULL;
} }
rewritelog(r, 5, "map lookup OK: map=%s[dbm] key=%s -> val=%s", rewritelog(r, 5, "map lookup OK: map=%s[dbm] key=%s -> val=%s",
name, key, value); name, key, value);
set_cache_string(cachep, name, CACHEMODE_TS, st.mtime, key, value); set_cache_value(name, st.mtime, key, value);
return value; return value;
} }
@@ -3945,7 +3818,10 @@ static void init_child(apr_pool_t *p, server_rec *s)
} }
/* create the lookup cache */ /* create the lookup cache */
cachep = init_cache(p); if (!init_cache(p)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
"mod_rewrite: could not init map cache in child");
}
} }