Return-Path: Delivered-To: apmail-httpd-cvs-archive@httpd.apache.org Received: (qmail 42063 invoked by uid 500); 10 Sep 2001 18:13:52 -0000 Mailing-List: contact cvs-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list cvs@httpd.apache.org Received: (qmail 42051 invoked by uid 500); 10 Sep 2001 18:13:52 -0000 Delivered-To: apmail-httpd-2.0-cvs@apache.org Date: 10 Sep 2001 18:09:57 -0000 Message-ID: <20010910180957.18215.qmail@icarus.apache.org> From: stoddard@apache.org To: httpd-2.0-cvs@apache.org Subject: cvs commit: httpd-2.0/modules/experimental cache_storage.c mod_cache.c mod_cache.h mod_mem_cache.c X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N stoddard 01/09/10 11:09:56 Modified: modules/experimental cache_storage.c mod_cache.c mod_cache.h mod_mem_cache.c Log: 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. Revision Changes Path 1.7 +25 -19 httpd-2.0/modules/experimental/cache_storage.c Index: cache_storage.c =================================================================== RCS file: /home/cvs/httpd-2.0/modules/experimental/cache_storage.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- cache_storage.c 2001/09/07 02:56:11 1.6 +++ cache_storage.c 2001/09/10 18:09:56 1.7 @@ -101,7 +101,7 @@ */ 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 @@ /* 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 @@ * 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 @@ &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 @@ 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 @@ 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) 1.15 +5 -5 httpd-2.0/modules/experimental/mod_cache.c Index: mod_cache.c =================================================================== RCS file: /home/cvs/httpd-2.0/modules/experimental/mod_cache.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- mod_cache.c 2001/09/07 13:54:25 1.14 +++ mod_cache.c 2001/09/10 18:09:56 1.15 @@ -186,13 +186,13 @@ /* 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. 1.10 +24 -22 httpd-2.0/modules/experimental/mod_cache.h Index: mod_cache.h =================================================================== RCS file: /home/cvs/httpd-2.0/modules/experimental/mod_cache.h,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- mod_cache.h 2001/09/07 02:56:11 1.9 +++ mod_cache.h 2001/09/10 18:09:56 1.10 @@ -146,7 +146,6 @@ int factor_set; int complete; /* Force cache completion after this point */ int complete_set; - } cache_server_conf; /* cache info information */ @@ -165,21 +164,24 @@ }; /* 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 */ - - /* 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); + int complete; +}; +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 @@ 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 @@ */ 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 @@ #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)) 1.7 +93 -105 httpd-2.0/modules/experimental/mod_mem_cache.c Index: mod_mem_cache.c =================================================================== RCS file: /home/cvs/httpd-2.0/modules/experimental/mod_mem_cache.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- mod_mem_cache.c 2001/09/07 02:56:11 1.6 +++ mod_mem_cache.c 2001/09/10 18:09:56 1.7 @@ -85,16 +85,13 @@ 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 @@ #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 @@ } */ - 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); + } + free(obj); + + /* Cleanup the mem_cache_object_t */ + if (!mobj) { + return; + } + if (mobj->m) { + free(mobj->m); + } /* XXX Cleanup the headers */ - if (obj->num_headers) { + if (mobj->num_headers) { } - free(obj); + free(mobj); } static apr_status_t cleanup_cache_mem(void *sconfv) @@ -203,100 +208,88 @@ 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 */ + + + /* 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 */ + - /* XXX Need a way to insert into the cache w/o such coarse grained locking */ + /* 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 @@ 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 @@ cleanup_cache_object(obj); - /* Reinit the cache_handle fields? */ - h->cache_obj = NULL; - return OK; } @@ -390,26 +378,24 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ * 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 @@ 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 @@ 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;