I finally developed some time to look into this. mod_cache doesn't
behave very nicely when the cache area fills. Of course administators
should make sure it doesn't fill in the first place, but nevertheless a
few people have hit this bug (me included) and I think mod_cache should
handle the problem gracefully.
Anyway, the problem occurs when the cache is unwritable, and mod_cache
needs to revalidate a cached entity. cache_select_url handles this by
rewriting headers_in to become a conditional request. However the code
in cache_save_filter which turns the request back into its original
(possibly unconditional) format is itself conditional on store_headers()
working.
The patch I've attached should be reasonably self-documenting, any
questions - just ask.
--
Colm MacCárthaigh Public Key: [EMAIL PROTECTED]
Index: mod_cache.c
===================================================================
--- mod_cache.c (revision 230608)
+++ mod_cache.c (working copy)
@@ -666,7 +666,13 @@
ap_cache_accept_headers(cache->handle, r, 1);
}
- /* Write away header information to cache. */
+ /* Write away header information to cache. It is possible that we are
+ * trying to update headers for an entity which has already been cached.
+ *
+ * This may fail, due to an unwritable cache area. E.g. filesystem full,
+ * permissions problems or a read-only (re)mount. This must be handled
+ * later.
+ */
rv = cache->provider->store_headers(cache->handle, r, info);
/* Did we just update the cached headers on a revalidated response?
@@ -675,7 +681,7 @@
* the same way as with a regular response, but conditions are now checked
* against the cached or merged response headers.
*/
- if (rv == APR_SUCCESS && cache->stale_handle) {
+ if (cache->stale_handle) {
apr_bucket_brigade *bb;
apr_bucket *bkt;
int status;
@@ -699,12 +705,42 @@
}
cache->block_response = 1;
+
+ /* Before returning we need to handle the possible case of an
+ * unwritable cache. Rather than leaving the entity in the cache
+ * and having it constantly re-validated, now that we have recalled
+ * the body it is safe to try and remove the url from the cache.
+ */
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
+ "cache: updating headers with store_headers failed. "
+ "Removing cached url.");
+
+ if (cache->provider->remove_url(url) != OK) {
+ /* Probably a mod_disk_cache cache area has been (re)mounted
+ * read-only, or that there is a permissions problem.
+ *
+ * XXX: right now mod_disk_cache's remove_url doesn't do
+ * anything and always returns OK. Once it does, this codepath
+ * will make more sense.
+ */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
+ "cache: attempt to remove url from cache unsuccessful.");
+ }
+ }
+
return ap_pass_brigade(f->next, bb);
}
+
+ if(rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
+ "cache: store_headers failed");
+ ap_remove_output_filter(f);
- if (rv == APR_SUCCESS) {
- rv = cache->provider->store_body(cache->handle, r, in);
+ return ap_pass_brigade(f->next, in);
}
+
+ rv = cache->provider->store_body(cache->handle, r, in);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
"cache: store_body failed");