[nginx] Cache: multiple variants of a resource now can be stored.
Maxim Dounin
mdounin at mdounin.ru
Mon Oct 27 18:20:13 UTC 2014
details: http://hg.nginx.org/nginx/rev/78c49e243848
branches:
changeset: 5880:78c49e243848
user: Maxim Dounin <mdounin at mdounin.ru>
date: Mon Oct 27 21:14:10 2014 +0300
description:
Cache: multiple variants of a resource now can be stored.
If a variant stored can't be used to respond to a request, the variant
hash is used as a secondary key.
Additionally, if we previously switched to a secondary key, while storing
a response to cache we check if the variant hash still apply. If not, we
switch back to the original key, to handle cases when Vary changes.
diffstat:
src/http/ngx_http_cache.h | 2 +
src/http/ngx_http_file_cache.c | 80 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 79 insertions(+), 3 deletions(-)
diffs (154 lines):
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -65,6 +65,7 @@ struct ngx_http_cache_s {
ngx_array_t keys;
uint32_t crc32;
u_char key[NGX_HTTP_CACHE_KEY_LEN];
+ u_char main[NGX_HTTP_CACHE_KEY_LEN];
ngx_file_uniq_t uniq;
time_t valid_sec;
@@ -102,6 +103,7 @@ struct ngx_http_cache_s {
unsigned exists:1;
unsigned temp_file:1;
unsigned reading:1;
+ unsigned secondary:1;
};
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -33,6 +33,8 @@ static void ngx_http_file_cache_vary(ngx
size_t len, u_char *hash);
static void ngx_http_file_cache_vary_header(ngx_http_request_t *r,
ngx_md5_t *md5, ngx_str_t *name);
+static ngx_int_t ngx_http_file_cache_reopen(ngx_http_request_t *r,
+ ngx_http_cache_t *c);
static void ngx_http_file_cache_cleanup(void *data);
static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
@@ -239,6 +241,8 @@ ngx_http_file_cache_create_key(ngx_http_
ngx_crc32_final(c->crc32);
ngx_md5_final(c->key, &md5);
+
+ ngx_memcpy(c->main, c->key, NGX_HTTP_CACHE_KEY_LEN);
}
@@ -536,7 +540,7 @@ ngx_http_file_cache_read(ngx_http_reques
if (ngx_memcmp(c->variant, h->variant, NGX_HTTP_CACHE_KEY_LEN) != 0) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache vary mismatch");
- return NGX_DECLINED;
+ return ngx_http_file_cache_reopen(r, c);
}
}
@@ -907,6 +911,7 @@ ngx_http_file_cache_vary(ngx_http_reques
"http file cache vary: \"%*s\"", len, vary);
ngx_md5_init(&md5);
+ ngx_md5_update(&md5, r->cache->main, NGX_HTTP_CACHE_KEY_LEN);
ngx_strlow(buf, vary, len);
@@ -982,6 +987,40 @@ ngx_http_file_cache_vary_header(ngx_http
}
+static ngx_int_t
+ngx_http_file_cache_reopen(ngx_http_request_t *r, ngx_http_cache_t *c)
+{
+ ngx_http_file_cache_t *cache;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
+ "http file cache reopen");
+
+ if (c->secondary) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+ "cache file \"%s\" has incorrect vary hash",
+ c->file.name.data);
+ return NGX_DECLINED;
+ }
+
+ cache = c->file_cache;
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ c->node->count--;
+ c->node = NULL;
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ c->secondary = 1;
+ c->file.name.len = 0;
+ c->body_start = c->buf->end - c->buf->start;
+
+ ngx_memcpy(c->key, c->variant, NGX_HTTP_CACHE_KEY_LEN);
+
+ return ngx_http_file_cache_open(r);
+}
+
+
void
ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
{
@@ -1024,6 +1063,9 @@ ngx_http_file_cache_set_header(ngx_http_
ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant);
ngx_memcpy(h->variant, c->variant, NGX_HTTP_CACHE_KEY_LEN);
+
+ } else {
+ ngx_memzero(c->variant, NGX_HTTP_CACHE_KEY_LEN);
}
p = buf + sizeof(ngx_http_file_cache_header_t);
@@ -1059,11 +1101,43 @@ ngx_http_file_cache_update(ngx_http_requ
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache update");
+ cache = c->file_cache;
+
+ if (c->secondary
+ && ngx_memcmp(c->variant, c->key, NGX_HTTP_CACHE_KEY_LEN) != 0)
+ {
+ /*
+ * if the variant hash doesn't match one we used as a secondary
+ * cache key, switch back to the original key
+ */
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache main key");
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ c->node->count--;
+ c->node->updating = 0;
+ c->node = NULL;
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ c->file.name.len = 0;
+
+ ngx_memcpy(c->key, c->main, NGX_HTTP_CACHE_KEY_LEN);
+
+ if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) {
+ return;
+ }
+
+ if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
+ return;
+ }
+ }
+
c->updated = 1;
c->updating = 0;
- cache = c->file_cache;
-
uniq = 0;
fs_size = 0;
More information about the nginx-devel
mailing list