Configure mod_mem_cache to cache files in mem, set CacheExpiresMax 1 then turn ab loose fetching a single cachable static file and watch what happens. You get exploding memory usage in the subprocess_env serialized headers.

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;
 }
 
 /*

Reply via email to