1
0
mirror of https://github.com/apache/httpd.git synced 2026-01-26 19:01:35 +03:00

Introduce the notion of a multi part cache object. Part of the cache_object

is common across any cache implementation, the other part is private to
the particular implementation (eg, mem_cache_object_t/mod_mem_cache).
Use a cache_handle_t allocated out of the request pool to hold references
to the callback functions and common cache object.

The cache_handle_t contains implementation specific callback functions and
a reference to a common cache_object_t.  The cache_object_t contains
a reference to an implementation specific cache object extension (mem_cache_object_t
for example).

All this simplifies managing the callback function pointers (don't want to
save them in each cache entry) and collections of cache_object_t keyed
to a single url.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@90994 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Bill Stoddard
2001-09-10 18:09:56 +00:00
parent defe8c69a8
commit dbfc30e197
4 changed files with 149 additions and 153 deletions

View File

@@ -101,7 +101,7 @@ int cache_remove_url(request_rec *r, const char *types, char *url)
*/
int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t size)
{
cache_handle *h;
cache_handle_t *h = apr_pcalloc(r->pool, sizeof(h));
const char *next = types;
const char *type;
apr_status_t rv;
@@ -111,7 +111,7 @@ int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t
/* for each specified cache type, delete the URL */
while (next) {
type = ap_cache_tokstr(r->pool, next, &next);
switch (rv = cache_run_create_entity(&h, type, url, size)) {
switch (rv = cache_run_create_entity(h, type, url, size)) {
case OK: {
cache->handle = h;
return OK;
@@ -134,7 +134,7 @@ int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t
* from the cache, and the cache_handle is closed.
*/
/* XXX Don't think we need to pass in request_rec or types ... */
int cache_remove_entity(request_rec *r, const char *types, cache_handle *h)
int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h)
{
h->remove_entity(h);
return 1;
@@ -160,17 +160,25 @@ int cache_select_url(request_rec *r, const char *types, char *url)
&cache_module);
/* go through the cache types till we get a match */
cache->handle = apr_palloc(r->pool, sizeof(cache_handle));
cache->handle = apr_palloc(r->pool, sizeof(cache_handle_t));
while (next) {
type = ap_cache_tokstr(r->pool, next, &next);
switch ((rv = cache_run_open_entity(cache->handle, type, url))) {
case OK: {
/* cool bananas! */
/*** loop through returned entities */
/*** do freshness calculation here */
cache->fresh = 1;
/*** do content negotiation here */
/* XXX:
* Handle being returned a collection of entities.
*/
/* Has the cache entry expired? */
#if 0
if (r->request_time > cache->handle... need to get info out of the cache... info.expire)
cache->fresh = 0;
else
#endif
cache->fresh = 1;
/*** do content negotiation here */
return OK;
}
case DECLINED: {
@@ -188,13 +196,13 @@ int cache_select_url(request_rec *r, const char *types, char *url)
return DECLINED;
}
apr_status_t cache_write_entity_headers(cache_handle *h, request_rec *r, cache_info *info,
apr_status_t cache_write_entity_headers(cache_handle_t *h, request_rec *r, cache_info *info,
apr_table_t *headers)
{
h->write_headers(h, r, info, headers);
return APR_SUCCESS;
}
apr_status_t cache_write_entity_body(cache_handle *h, apr_bucket_brigade *b)
apr_status_t cache_write_entity_body(cache_handle_t *h, apr_bucket_brigade *b)
{
apr_status_t rv = APR_SUCCESS;
if (h->write_body(h, b) != OK) {
@@ -202,29 +210,27 @@ apr_status_t cache_write_entity_body(cache_handle *h, apr_bucket_brigade *b)
return rv;
}
apr_status_t cache_read_entity_headers(cache_handle *h, request_rec *r,
apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r,
apr_table_t **headers)
{
cache_info *info;
/* Build the header table from info in the info struct */
*headers = apr_table_make(r->pool, 15);
h->read_headers(h, r, &info, *headers);
h->read_headers(h, r, *headers);
return APR_SUCCESS;
}
apr_status_t cache_read_entity_body(cache_handle *h, apr_bucket_brigade *b)
apr_status_t cache_read_entity_body(cache_handle_t *h, apr_bucket_brigade *b)
{
h->read_body(h, b);
return APR_SUCCESS;
}
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, create_entity,
(cache_handle **hp, const char *type,
char *url, apr_size_t len),(hp,type,url,len),DECLINED)
(cache_handle_t *h, const char *type,
char *url, apr_size_t len),(h,type,url,len),DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, open_entity,
(cache_handle *h, const char *type,
(cache_handle_t *h, const char *type,
char *url),(h,type,url),DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, remove_url,
(const char *type, char *url),(type,url),OK,DECLINED)

View File

@@ -186,13 +186,13 @@ int ap_url_cache_handler(request_rec *r)
/* We are in the quick handler hook, which means that no output
* filters have been set. So lets run the insert_filter hook.
* Humm... Probably should not go through most of these hooks
* for a proxy request, so take out all but the basics.
* XXX - Should we be inserting filters in the output stream
* for proxy requests? Certainly we need the core filters
* (byterange, chunking, etc.). I can also see the need to
* conditionally insert tag processing filters (e.g. INCLUDES).
*/
ap_run_insert_filter(r);
if (r->proxyreq) {
ap_cache_reset_output_filters(r);
}
/* Now add the cache_out filter. cache_out is a FTYPE_CONTENT
* which means it will be inserted first in the stream, which
* is exactly what we need.

View File

@@ -146,7 +146,6 @@ typedef struct {
int factor_set;
int complete; /* Force cache completion after this point */
int complete_set;
} cache_server_conf;
/* cache info information */
@@ -165,21 +164,24 @@ struct cache_info {
};
/* cache handle information */
typedef struct cache_handle cache_handle;
struct cache_handle {
cache_info *info;
cache_handle *next;
void *cache_obj; /* Pointer to cache specific object */
typedef struct cache_object cache_object_t;
struct cache_object {
char *key;
cache_object_t *next;
cache_info info;
void *vobj; /* Opaque portion (specific to the cache implementation) of the cache object */
apr_size_t count; /* Number of body bytes written to the cache so far */
int complete;
};
/* Cache call back functions */
int (*remove_entity) (cache_handle *h);
int (*write_headers)(cache_handle *h, request_rec *r, cache_info *i, apr_table_t *headers);
int (*write_body)(cache_handle *h, apr_bucket_brigade *b);
int (*read_headers) (cache_handle *h, request_rec *r, cache_info **i, apr_table_t *headers);
int (*read_body) (cache_handle *h, apr_bucket_brigade *bb);
typedef struct cache_handle cache_handle_t;
struct cache_handle {
cache_object_t *cache_obj;
int (*remove_entity) (cache_handle_t *h);
int (*write_headers)(cache_handle_t *h, request_rec *r, cache_info *i, apr_table_t *headers);
int (*write_body)(cache_handle_t *h, apr_bucket_brigade *b);
int (*read_headers) (cache_handle_t *h, request_rec *r, apr_table_t *headers);
int (*read_body) (cache_handle_t *h, apr_bucket_brigade *bb);
};
/* per request cache information */
@@ -187,7 +189,7 @@ typedef struct {
const char *types; /* the types of caches allowed */
const char *type; /* the type of cache selected */
int fresh; /* is the entitey fresh? */
cache_handle *handle; /* current cache handle */
cache_handle_t *handle; /* current cache handle */
int in_checked; /* CACHE_IN must cache the entity */
} cache_request_rec;
@@ -204,15 +206,15 @@ const char *ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str);
*/
int cache_remove_url(request_rec *r, const char *types, char *url);
int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t size);
int cache_remove_entity(request_rec *r, const char *types, cache_handle *h);
int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h);
int cache_select_url(request_rec *r, const char *types, char *url);
apr_status_t cache_write_entity_headers(cache_handle *h, request_rec *r, cache_info *info,
apr_status_t cache_write_entity_headers(cache_handle_t *h, request_rec *r, cache_info *info,
apr_table_t *headers);
apr_status_t cache_write_entity_body(cache_handle *h, apr_bucket_brigade *bb);
apr_status_t cache_write_entity_body(cache_handle_t *h, apr_bucket_brigade *bb);
apr_status_t cache_read_entity_headers(cache_handle *h, request_rec *r, apr_table_t **headers);
apr_status_t cache_read_entity_body(cache_handle *h, apr_bucket_brigade *bb);
apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r, apr_table_t **headers);
apr_status_t cache_read_entity_body(cache_handle_t *h, apr_bucket_brigade *bb);
/* hooks */
@@ -239,10 +241,10 @@ apr_status_t cache_read_entity_body(cache_handle *h, apr_bucket_brigade *bb);
#endif
APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, create_entity,
(cache_handle **hp, const char *type,
(cache_handle_t *h, const char *type,
char *url, apr_size_t len))
APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, open_entity,
(cache_handle *h, const char *type,
(cache_handle_t *h, const char *type,
char *url))
APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, remove_url,
(const char *type, char *url))

View File

@@ -85,16 +85,13 @@ typedef struct {
char* val;
} cache_header_tbl_t;
typedef struct {
typedef struct mem_cache_object {
cache_type_e type;
char *key;
apr_ssize_t num_headers;
cache_header_tbl_t *tbl;
apr_size_t m_len;
void *m;
cache_info info;
int complete;
} cache_object_t;
} mem_cache_object_t;
typedef struct {
apr_lock_t *lock;
@@ -109,16 +106,17 @@ static mem_cache_conf *sconf;
#define CACHEFILE_LEN 20
/* Forward declarations */
static int remove_entity(cache_handle *h);
static int write_headers(cache_handle *h, request_rec *r, cache_info *i,
static int remove_entity(cache_handle_t *h);
static int write_headers(cache_handle_t *h, request_rec *r, cache_info *i,
apr_table_t *headers);
static int write_body(cache_handle *h, apr_bucket_brigade *b);
static int read_headers(cache_handle *h, request_rec *r, cache_info **info,
apr_table_t *headers);
static int read_body(cache_handle *h, apr_bucket_brigade *bb);
static int write_body(cache_handle_t *h, apr_bucket_brigade *b);
static int read_headers(cache_handle_t *h, request_rec *r, apr_table_t *headers);
static int read_body(cache_handle_t *h, apr_bucket_brigade *bb);
static void cleanup_cache_object(cache_object_t *obj)
{
mem_cache_object_t *mobj = obj->vobj;
/* The cache object has been removed from the cache. Now clean
* it up, freeing any storage, closing file descriptors, etc.
*/
@@ -149,18 +147,25 @@ static void cleanup_cache_object(cache_object_t *obj)
}
*/
if (obj->info.content_type)
free((char*) obj->info.content_type);
if (obj->key)
/* Cleanup the cache_object_t */
if (obj->key) {
free(obj->key);
if (obj->m)
free(obj->m);
/* XXX Cleanup the headers */
if (obj->num_headers) {
}
free(obj);
/* Cleanup the mem_cache_object_t */
if (!mobj) {
return;
}
if (mobj->m) {
free(mobj->m);
}
/* XXX Cleanup the headers */
if (mobj->num_headers) {
}
free(mobj);
}
static apr_status_t cleanup_cache_mem(void *sconfv)
@@ -203,100 +208,88 @@ static void *create_cache_config(apr_pool_t *p, server_rec *s)
return sconf;
}
static int create_entity(cache_handle **hp, const char *type, char *key, apr_size_t len)
static int create_entity(cache_handle_t *h, const char *type, char *key, apr_size_t len)
{
cache_object_t *obj, *eobj = NULL;
cache_handle *h;
cache_object_t *obj, *tmp_obj;
mem_cache_object_t *mobj;
/* Create the cache handle and begin populating it.
*/
if (strcasecmp(type, "mem")) {
return DECLINED;
}
/* Check len to see if it is withing acceptable bounds
* XXX max cache check should be configurable variable.
/* XXX Check len to see if it is withing acceptable bounds
* max cache check should be configurable variable.
*/
if (len < 0 || len > MAX_CACHE) {
return DECLINED;
}
/* Check total cache size and number of entries. Are they within the
/* XXX Check total cache size and number of entries. Are they within the
* configured limits? If not, kick off garbage collection thread.
*/
/* Allocate the cache_handle and set up call back functions specific to
* this cache handler.
*/
h = malloc(sizeof(cache_handle));
*hp = h;
if (!h) {
/* handle the error */
return DECLINED;
}
h->read_body = &read_body;
h->read_headers = &read_headers;
h->write_body = &write_body;
h->write_headers = &write_headers;
/* Allocate and initialize the cache object. The cache object is
* unique to this implementation.
*/
/* Allocate and initialize cache_object_t */
obj = malloc(sizeof(*obj));
if (!obj) {
/* Handle ther error */
free(h);
return DECLINED;
}
memset(obj,'\0', sizeof(*obj));
obj->key = malloc(strlen(key) + 1);
if (!obj->key) {
/* XXX Uuugh, there has got to be a better way to manage memory.
*/
free(h);
free(obj);
return DECLINED;
}
obj->m_len = len; /* One of these len fields can go */
obj->info.len = len;
strncpy(obj->key, key, strlen(key) + 1);
h->cache_obj = (void *) obj;
/* Mark the cache object as incomplete and put it into the cache */
obj->complete = 0;
obj->info.len = len;
obj->complete = 0; /* Cache object is not complete */
/* XXX Need a way to insert into the cache w/o such coarse grained locking */
/* Allocate and init mem_cache_object_t */
mobj = malloc(sizeof(*mobj));
if (!mobj) {
/* XXX: Cleanup */
cleanup_cache_object(obj);
}
memset(mobj,'\0', sizeof(*mobj));
obj->vobj = mobj; /* Reference the mem_cache_object_t out of cache_object_t */
mobj->m_len = len; /* Duplicates info in cache_object_t info */
/* Place the cache_object_t into the hash table
* XXX Need a way to insert into the cache w/o such coarse grained locking
* XXX Need to enable caching multiple cache objects (representing different
* views of the same content) under a single search key
*/
if (sconf->lock) {
apr_lock_acquire(sconf->lock);
}
/* Do not allow the new cache object to replace an existing cache object.
* We should find eobj only when another thread is in the process of
* caching the same object as this thread. If we hit this case, decline
* the request.
*/
eobj = (cache_object_t *) apr_hash_get(sconf->cacheht, key, APR_HASH_KEY_STRING);
if (!eobj) {
tmp_obj = (cache_object_t *) apr_hash_get(sconf->cacheht, key, APR_HASH_KEY_STRING);
if (!tmp_obj) {
apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), obj);
}
if (sconf->lock) {
apr_lock_release(sconf->lock);
}
if (eobj) {
if (tmp_obj) {
/* This thread collided with another thread loading the same object
* into the cache at the same time. Defer to the other thread which
* is further along.
*/
cleanup_cache_object(obj);
free(h);
*hp = NULL;
return DECLINED;
}
/* Populate the cache handle */
h->cache_obj = obj;
h->read_body = &read_body;
h->read_headers = &read_headers;
h->write_body = &write_body;
h->write_headers = &write_headers;
return OK;
}
static int open_entity(cache_handle *h, const char *type, char *key)
static int open_entity(cache_handle_t *h, const char *type, char *key)
{
cache_object_t *obj;
@@ -322,15 +315,13 @@ static int open_entity(cache_handle *h, const char *type, char *key)
h->write_body = &write_body;
h->write_headers = &write_headers;
h->cache_obj = obj;
if (!obj || !(obj->complete)) {
return DECLINED;
}
return OK;
}
static int remove_entity(cache_handle *h)
static int remove_entity(cache_handle_t *h)
{
cache_object_t *obj = (cache_object_t *) h->cache_obj;
cache_object_t *obj = h->cache_obj;
if (sconf->lock) {
apr_lock_acquire(sconf->lock);
@@ -342,9 +333,6 @@ static int remove_entity(cache_handle *h)
cleanup_cache_object(obj);
/* Reinit the cache_handle fields? */
h->cache_obj = NULL;
return OK;
}
@@ -390,26 +378,24 @@ static int remove_url(const char *type, char *key)
return OK;
}
static int read_headers(cache_handle *h, request_rec *r, cache_info **info,
apr_table_t *headers)
static int read_headers(cache_handle_t *h, request_rec *r, apr_table_t *headers)
{
cache_object_t *obj = (cache_object_t*) h->cache_obj;
mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
int i;
for (i = 0; i < obj->num_headers; ++i) {
apr_table_setn(headers, obj->tbl[i].hdr, obj->tbl[i].val);
for (i = 0; i < mobj->num_headers; ++i) {
apr_table_setn(headers, mobj->tbl[i].hdr, mobj->tbl[i].val);
}
*info = &(obj->info);
return OK;
}
static int read_body(cache_handle *h, apr_bucket_brigade *bb)
static int read_body(cache_handle_t *h, apr_bucket_brigade *bb)
{
apr_bucket *b;
cache_object_t *obj = h->cache_obj;
mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
b = apr_bucket_immortal_create(obj->m, obj->m_len);
b = apr_bucket_immortal_create(mobj->m, mobj->m_len);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_eos_create();
APR_BRIGADE_INSERT_TAIL(bb, b);
@@ -417,9 +403,9 @@ static int read_body(cache_handle *h, apr_bucket_brigade *bb)
return OK;
}
static int write_headers(cache_handle *h, request_rec *r, cache_info *info, apr_table_t *headers)
static int write_headers(cache_handle_t *h, request_rec *r, cache_info *info, apr_table_t *headers)
{
cache_object_t *obj = (cache_object_t*) h->cache_obj;
mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
apr_table_entry_t *elts = (apr_table_entry_t *) headers->a.elts;
apr_ssize_t i;
apr_size_t len = 0;
@@ -427,8 +413,9 @@ static int write_headers(cache_handle *h, request_rec *r, cache_info *info, apr_
char *buf;
/* Precompute how much storage we need to hold the headers */
obj->tbl = malloc(sizeof(cache_header_tbl_t) * headers->a.nelts);
if (NULL == obj->tbl) {
mobj->tbl = malloc(sizeof(cache_header_tbl_t) * headers->a.nelts);
if (NULL == mobj->tbl) {
/* cleanup_cache_obj(h->cache_obj); */
return DECLINED;
}
for (i = 0; i < headers->a.nelts; ++i) {
@@ -440,18 +427,19 @@ static int write_headers(cache_handle *h, request_rec *r, cache_info *info, apr_
/* Transfer the headers into a contiguous memory block */
buf = malloc(len);
if (!buf) {
free(obj->tbl);
obj->tbl = NULL;
free(mobj->tbl);
mobj->tbl = NULL;
/* cleanup_cache_obj(h->cache_obj); */
return DECLINED;
}
obj->num_headers = headers->a.nelts;
for (i = 0; i < obj->num_headers; ++i) {
obj->tbl[i].hdr = &buf[idx];
mobj->num_headers = headers->a.nelts;
for (i = 0; i < mobj->num_headers; ++i) {
mobj->tbl[i].hdr = &buf[idx];
len = strlen(elts[i].key) + 1; /* Include NULL terminator */
strncpy(&buf[idx], elts[i].key, len);
idx+=len;
obj->tbl[i].val = &buf[idx];
mobj->tbl[i].val = &buf[idx];
len = strlen(elts[i].val) + 1;
strncpy(&buf[idx], elts[i].val, len);
idx+=len;
@@ -476,10 +464,10 @@ static int write_headers(cache_handle *h, request_rec *r, cache_info *info, apr_
return OK;
}
static int write_body(cache_handle *h, apr_bucket_brigade *b)
static int write_body(cache_handle_t *h, apr_bucket_brigade *b)
{
apr_status_t rv;
cache_object_t *obj = (cache_object_t *) h->cache_obj;
mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
apr_read_type_e eblock = APR_BLOCK_READ;
apr_bucket *e;
char *cur;
@@ -488,15 +476,15 @@ static int write_body(cache_handle *h, apr_bucket_brigade *b)
* Enable this decision to be configured....
* XXX cache buckets...
*/
if (obj->m == NULL) {
obj->m = malloc(obj->m_len);
if (obj->m == NULL) {
if (mobj->m == NULL) {
mobj->m = malloc(mobj->m_len);
if (mobj->m == NULL) {
/* Cleanup cache entry and return */
}
obj->type = CACHE_TYPE_HEAP;
h->count = 0;
mobj->type = CACHE_TYPE_HEAP;
h->cache_obj->count = 0;
}
cur = (char*) obj->m + h->count;
cur = (char*) mobj->m + h->cache_obj->count;
/* Iterate accross the brigade and populate the cache storage */
APR_BRIGADE_FOREACH(e, b) {
@@ -504,7 +492,7 @@ static int write_body(cache_handle *h, apr_bucket_brigade *b)
apr_size_t len;
if (APR_BUCKET_IS_EOS(e)) {
obj->complete = 1;
h->cache_obj->complete = 1;
break;
}
rv = apr_bucket_read(e, &s, &len, eblock);
@@ -515,12 +503,12 @@ static int write_body(cache_handle *h, apr_bucket_brigade *b)
if (len ) {
memcpy(cur, s, len);
cur+=len;
h->count+=len;
h->cache_obj->count+=len;
}
/* This should not happen, but if it does, we are in BIG trouble
* cause we just stomped all over the heap.
*/
AP_DEBUG_ASSERT(h->count > obj->m_len);
AP_DEBUG_ASSERT(h->cache_object->count > mobj->m_len);
}
return OK;