The initial cache load caches whatever is in subprocess_env. On the next request, mod_cache discovers that the cache entry is stale, but by the time it has figured out that it needs to DECLINE the request, it has replaced r->subprocess_env with what was in the stale cache entry. Whatever is in the subprocess_env table when the quick handler DECLINES stays there and new entries are added by Apache during normal (uncached) file handling. The result is that when the cache_in_filter is run to cache the new response, subprocess_env contains the values out of the stale cache entry -and- the new values added by default_handling. When the new cache entry becomes stale, the cycle starts again and sunprocess_env grows more.
I really don't have much time to pursue this so here is a patch that:
1. saves some tables of interest from the request_rec at entry to the cache_handler. These value are restored if the cache_handler DECLINES
2. Hacks out a bunch of code that I cannot quite grok and that I am pretty sure is causing more problems that it is solving.
mod_cache needs some serious work before it is ready to come out of experimental.
Bill
RCS file: /cvs/phoenix/2.0.47/modules/experimental/mod_cache.c,v retrieving revision 1.2 diff -u -r1.2 mod_cache.c --- mod_cache.c 5 Mar 2004 02:33:46 -0000 1.2 +++ mod_cache.c 6 Mar 2004 21:11:23 -0000 @@ -57,6 +57,12 @@ cache_info *info = NULL; cache_request_rec *cache; cache_server_conf *conf; + /* Hack till we come up with a better solution */ + + apr_table_t *err_headers_out = r->err_headers_out; + apr_table_t *notes = r->notes; + apr_table_t *subprocess_env = r->subprocess_env; + apr_table_t *headers_out = r->headers_out;
conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, &cache_module); @@ -151,18 +157,7 @@ */
rv = cache_select_url(r, cache->types, url); - if (DECLINED == rv) { - if (!lookup) { - /* no existing cache file */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "cache: no cache - add cache_in filter and DECLINE"); - /* add cache_in filter to cache this request */ - ap_add_output_filter_handle(cache_in_filter_handle, NULL, r, - r->connection); - } - return DECLINED; - } - else if (OK == rv) { + if (OK == rv) { /* RFC2616 13.2 - Check cache object expiration */ cache->fresh = ap_cache_check_freshness(cache, r); if (cache->fresh) { @@ -174,127 +169,69 @@ return OK; } rv = ap_meets_conditions(r); - if (rv != OK) { + if (rv == OK) { + /* Meets conditions or is not conditional */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "cache: fresh cache - returning status %d", rv); - return rv; - } + "cache: fresh cache - add cache_out filter and " + "handle request");
- /* - * Not a conditionl request. Serve up the content - */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "cache: fresh cache - add cache_out filter and " - "handle request"); + /* We are in the quick handler hook, which means that no output + * filters have been set. So lets run the insert_filter hook. + */ + ap_run_insert_filter(r); + ap_add_output_filter_handle(cache_out_filter_handle, NULL, + r, r->connection);
- /* We are in the quick handler hook, which means that no output - * filters have been set. So lets run the insert_filter hook. - */ - ap_run_insert_filter(r); - ap_add_output_filter_handle(cache_out_filter_handle, NULL, - r, r->connection); - - /* kick off the filter stack */ - out = apr_brigade_create(r->pool, c->bucket_alloc); - if (APR_SUCCESS - != (rv = ap_pass_brigade(r->output_filters, out))) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "cache: error returned while trying to return %s " - "cached data", - cache->type); - return rv; + /* kick off the filter stack */ + out = apr_brigade_create(r->pool, c->bucket_alloc); + rv = ap_pass_brigade(r->output_filters, out); + + if (rv != APR_SUCCESS) { + /* Is this right??? Is rv returned to the client? That would be odd */ + ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, + "cache: error returned while trying to return %s " + "cached data", + cache->type); + return rv; + } + return OK; } - return OK; + /* If the cached entry does not meet conditions, DECLINE + * the request and give the origin server a shot at serving it. + * Do we want to remove the entry from the cache? + */ + ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, + "cache: cache object does not meet conditions"); } else { - if (!r->err_headers_out) { - r->err_headers_out = apr_table_make(r->pool, 3); - } - /* stale data available */ - if (lookup) { - return DECLINED; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "cache: stale cache - test conditional"); - /* if conditional request */ - if (ap_cache_request_is_conditional(r)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: conditional - add cache_in filter and " - "DECLINE"); - /* Why not add CACHE_CONDITIONAL? */ + /* + * We have a stale cache entry. Temporarily hack ... + * + * You can never be wrong declining to serve up stale bytes out of the + * cache (pretty sure anyway!) If the entry is stale, restore the + * request_rec to it's original state upon entry to this function and + * return DECLINE. We'll add the optimization to serve up conditionl + * stale bytes when we figure out how to do it right. + */ + if (!lookup) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, + "cache: cache object is stale. Reloading from origin server."); ap_add_output_filter_handle(cache_in_filter_handle, NULL, r, r->connection); - - return DECLINED; - } - /* else if non-conditional request */ - else { - /* Temporarily hack this to work the way it had been. Its broken, - * but its broken the way it was before. I'm working on figuring - * out why the filter add in the conditional filter doesn't work. pjr - * - * info = &(cache->handle->cache_obj->info); - * - * Uncomment the above when the code in cache_conditional_filter_handle - * is properly fixed... pjr - */ - - /* fudge response into a conditional */ - if (info && info->etag) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: nonconditional - fudge conditional " - "by etag"); - /* if we have a cached etag */ - apr_table_set(r->headers_in, "If-None-Match", info->etag); - } - else if (info && info->lastmods) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: nonconditional - fudge conditional " - "by lastmod"); - /* if we have a cached IMS */ - apr_table_set(r->headers_in, - "If-Modified-Since", - info->lastmods); - } - else { - /* something else - pretend there was no cache */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: nonconditional - no cached " - "etag/lastmods - add cache_in and DECLINE"); - - ap_add_output_filter_handle(cache_in_filter_handle, NULL, - r, r->connection); - - return DECLINED; - } - /* add cache_conditional filter */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: nonconditional - add cache_conditional " - "and DECLINE"); - ap_add_output_filter_handle(cache_conditional_filter_handle, - NULL, - r, - r->connection); - - return DECLINED; } } } - else { - /* error */ - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - r->server, - "cache: error returned while checking for cached file by " - "%s cache", - cache->type); - return DECLINED; - } + else if (rv == DECLINED) { + ap_add_output_filter_handle(cache_in_filter_handle, NULL, + r, r->connection); + } + /* Restore the request_rec back to it's original state */ + r->headers_out = headers_out; + r->err_headers_out = err_headers_out; + r->notes = notes; + r->subprocess_env = subprocess_env; + + return DECLINED; }
/*
? cache.tar ? mod_cache.old.c ? mod_cache.patch ? mod_mem_cache.old.c Index: mod_cache.c =================================================================== RCS file: /cvs/phoenix/2.0.47/modules/experimental/mod_cache.c,v retrieving revision 1.2 diff -u -r1.2 mod_cache.c --- mod_cache.c 5 Mar 2004 02:33:46 -0000 1.2 +++ mod_cache.c 6 Mar 2004 21:11:23 -0000 @@ -57,6 +57,12 @@ cache_info *info = NULL; cache_request_rec *cache; cache_server_conf *conf; + /* Hack till we come up with a better solution */ + + apr_table_t *err_headers_out = r->err_headers_out; + apr_table_t *notes = r->notes; + apr_table_t *subprocess_env = r->subprocess_env; + apr_table_t *headers_out = r->headers_out; conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, &cache_module); @@ -151,18 +157,7 @@ */ rv = cache_select_url(r, cache->types, url); - if (DECLINED == rv) { - if (!lookup) { - /* no existing cache file */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "cache: no cache - add cache_in filter and DECLINE"); - /* add cache_in filter to cache this request */ - ap_add_output_filter_handle(cache_in_filter_handle, NULL, r, - r->connection); - } - return DECLINED; - } - else if (OK == rv) { + if (OK == rv) { /* RFC2616 13.2 - Check cache object expiration */ cache->fresh = ap_cache_check_freshness(cache, r); if (cache->fresh) { @@ -174,127 +169,69 @@ return OK; } rv = ap_meets_conditions(r); - if (rv != OK) { + if (rv == OK) { + /* Meets conditions or is not conditional */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "cache: fresh cache - returning status %d", rv); - return rv; - } + "cache: fresh cache - add cache_out filter and " + "handle request"); - /* - * Not a conditionl request. Serve up the content - */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "cache: fresh cache - add cache_out filter and " - "handle request"); + /* We are in the quick handler hook, which means that no output + * filters have been set. So lets run the insert_filter hook. + */ + ap_run_insert_filter(r); + ap_add_output_filter_handle(cache_out_filter_handle, NULL, + r, r->connection); - /* We are in the quick handler hook, which means that no output - * filters have been set. So lets run the insert_filter hook. - */ - ap_run_insert_filter(r); - ap_add_output_filter_handle(cache_out_filter_handle, NULL, - r, r->connection); - - /* kick off the filter stack */ - out = apr_brigade_create(r->pool, c->bucket_alloc); - if (APR_SUCCESS - != (rv = ap_pass_brigade(r->output_filters, out))) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "cache: error returned while trying to return %s " - "cached data", - cache->type); - return rv; + /* kick off the filter stack */ + out = apr_brigade_create(r->pool, c->bucket_alloc); + rv = ap_pass_brigade(r->output_filters, out); + + if (rv != APR_SUCCESS) { + /* Is this right??? Is rv returned to the client? That would be odd */ + ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, + "cache: error returned while trying to return %s " + "cached data", + cache->type); + return rv; + } + return OK; } - return OK; + /* If the cached entry does not meet conditions, DECLINE + * the request and give the origin server a shot at serving it. + * Do we want to remove the entry from the cache? + */ + ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, + "cache: cache object does not meet conditions"); } else { - if (!r->err_headers_out) { - r->err_headers_out = apr_table_make(r->pool, 3); - } - /* stale data available */ - if (lookup) { - return DECLINED; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "cache: stale cache - test conditional"); - /* if conditional request */ - if (ap_cache_request_is_conditional(r)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: conditional - add cache_in filter and " - "DECLINE"); - /* Why not add CACHE_CONDITIONAL? */ + /* + * We have a stale cache entry. Temporarily hack ... + * + * You can never be wrong declining to serve up stale bytes out of the + * cache (pretty sure anyway!) If the entry is stale, restore the + * request_rec to it's original state upon entry to this function and + * return DECLINE. We'll add the optimization to serve up conditionl + * stale bytes when we figure out how to do it right. + */ + if (!lookup) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, + "cache: cache object is stale. Reloading from origin server."); ap_add_output_filter_handle(cache_in_filter_handle, NULL, r, r->connection); - - return DECLINED; - } - /* else if non-conditional request */ - else { - /* Temporarily hack this to work the way it had been. Its broken, - * but its broken the way it was before. I'm working on figuring - * out why the filter add in the conditional filter doesn't work. pjr - * - * info = &(cache->handle->cache_obj->info); - * - * Uncomment the above when the code in cache_conditional_filter_handle - * is properly fixed... pjr - */ - - /* fudge response into a conditional */ - if (info && info->etag) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: nonconditional - fudge conditional " - "by etag"); - /* if we have a cached etag */ - apr_table_set(r->headers_in, "If-None-Match", info->etag); - } - else if (info && info->lastmods) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: nonconditional - fudge conditional " - "by lastmod"); - /* if we have a cached IMS */ - apr_table_set(r->headers_in, - "If-Modified-Since", - info->lastmods); - } - else { - /* something else - pretend there was no cache */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: nonconditional - no cached " - "etag/lastmods - add cache_in and DECLINE"); - - ap_add_output_filter_handle(cache_in_filter_handle, NULL, - r, r->connection); - - return DECLINED; - } - /* add cache_conditional filter */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, - r->server, - "cache: nonconditional - add cache_conditional " - "and DECLINE"); - ap_add_output_filter_handle(cache_conditional_filter_handle, - NULL, - r, - r->connection); - - return DECLINED; } } } - else { - /* error */ - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - r->server, - "cache: error returned while checking for cached file by " - "%s cache", - cache->type); - return DECLINED; - } + else if (rv == DECLINED) { + ap_add_output_filter_handle(cache_in_filter_handle, NULL, + r, r->connection); + } + /* Restore the request_rec back to it's original state */ + r->headers_out = headers_out; + r->err_headers_out = err_headers_out; + r->notes = notes; + r->subprocess_env = subprocess_env; + + return DECLINED; } /*