comparison src/http/ngx_http_file_cache.c @ 5880:78c49e243848

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.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 27 Oct 2014 21:14:10 +0300
parents c525c0454aa5
children ee9230cd4bda
comparison
equal deleted inserted replaced
5879:c525c0454aa5 5880:78c49e243848
31 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); 31 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
32 static void ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary, 32 static void ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary,
33 size_t len, u_char *hash); 33 size_t len, u_char *hash);
34 static void ngx_http_file_cache_vary_header(ngx_http_request_t *r, 34 static void ngx_http_file_cache_vary_header(ngx_http_request_t *r,
35 ngx_md5_t *md5, ngx_str_t *name); 35 ngx_md5_t *md5, ngx_str_t *name);
36 static ngx_int_t ngx_http_file_cache_reopen(ngx_http_request_t *r,
37 ngx_http_cache_t *c);
36 static void ngx_http_file_cache_cleanup(void *data); 38 static void ngx_http_file_cache_cleanup(void *data);
37 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache); 39 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
38 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache); 40 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
39 static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, 41 static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache,
40 ngx_queue_t *q, u_char *name); 42 ngx_queue_t *q, u_char *name);
237 c->header_start = sizeof(ngx_http_file_cache_header_t) 239 c->header_start = sizeof(ngx_http_file_cache_header_t)
238 + sizeof(ngx_http_file_cache_key) + len + 1; 240 + sizeof(ngx_http_file_cache_key) + len + 1;
239 241
240 ngx_crc32_final(c->crc32); 242 ngx_crc32_final(c->crc32);
241 ngx_md5_final(c->key, &md5); 243 ngx_md5_final(c->key, &md5);
244
245 ngx_memcpy(c->main, c->key, NGX_HTTP_CACHE_KEY_LEN);
242 } 246 }
243 247
244 248
245 ngx_int_t 249 ngx_int_t
246 ngx_http_file_cache_open(ngx_http_request_t *r) 250 ngx_http_file_cache_open(ngx_http_request_t *r)
534 ngx_http_file_cache_vary(r, h->vary, h->vary_len, c->variant); 538 ngx_http_file_cache_vary(r, h->vary, h->vary_len, c->variant);
535 539
536 if (ngx_memcmp(c->variant, h->variant, NGX_HTTP_CACHE_KEY_LEN) != 0) { 540 if (ngx_memcmp(c->variant, h->variant, NGX_HTTP_CACHE_KEY_LEN) != 0) {
537 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 541 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
538 "http file cache vary mismatch"); 542 "http file cache vary mismatch");
539 return NGX_DECLINED; 543 return ngx_http_file_cache_reopen(r, c);
540 } 544 }
541 } 545 }
542 546
543 c->buf->last += n; 547 c->buf->last += n;
544 548
905 909
906 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 910 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
907 "http file cache vary: \"%*s\"", len, vary); 911 "http file cache vary: \"%*s\"", len, vary);
908 912
909 ngx_md5_init(&md5); 913 ngx_md5_init(&md5);
914 ngx_md5_update(&md5, r->cache->main, NGX_HTTP_CACHE_KEY_LEN);
910 915
911 ngx_strlow(buf, vary, len); 916 ngx_strlow(buf, vary, len);
912 917
913 p = buf; 918 p = buf;
914 last = buf + len; 919 last = buf + len;
977 continue; 982 continue;
978 } 983 }
979 984
980 ngx_md5_update(md5, header[i].value.data, header[i].value.len); 985 ngx_md5_update(md5, header[i].value.data, header[i].value.len);
981 } 986 }
987 }
988
989
990 static ngx_int_t
991 ngx_http_file_cache_reopen(ngx_http_request_t *r, ngx_http_cache_t *c)
992 {
993 ngx_http_file_cache_t *cache;
994
995 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
996 "http file cache reopen");
997
998 if (c->secondary) {
999 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
1000 "cache file \"%s\" has incorrect vary hash",
1001 c->file.name.data);
1002 return NGX_DECLINED;
1003 }
1004
1005 cache = c->file_cache;
1006
1007 ngx_shmtx_lock(&cache->shpool->mutex);
1008
1009 c->node->count--;
1010 c->node = NULL;
1011
1012 ngx_shmtx_unlock(&cache->shpool->mutex);
1013
1014 c->secondary = 1;
1015 c->file.name.len = 0;
1016 c->body_start = c->buf->end - c->buf->start;
1017
1018 ngx_memcpy(c->key, c->variant, NGX_HTTP_CACHE_KEY_LEN);
1019
1020 return ngx_http_file_cache_open(r);
982 } 1021 }
983 1022
984 1023
985 void 1024 void
986 ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) 1025 ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
1022 h->vary_len = (u_char) c->vary.len; 1061 h->vary_len = (u_char) c->vary.len;
1023 ngx_memcpy(h->vary, c->vary.data, c->vary.len); 1062 ngx_memcpy(h->vary, c->vary.data, c->vary.len);
1024 1063
1025 ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant); 1064 ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant);
1026 ngx_memcpy(h->variant, c->variant, NGX_HTTP_CACHE_KEY_LEN); 1065 ngx_memcpy(h->variant, c->variant, NGX_HTTP_CACHE_KEY_LEN);
1066
1067 } else {
1068 ngx_memzero(c->variant, NGX_HTTP_CACHE_KEY_LEN);
1027 } 1069 }
1028 1070
1029 p = buf + sizeof(ngx_http_file_cache_header_t); 1071 p = buf + sizeof(ngx_http_file_cache_header_t);
1030 1072
1031 p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key)); 1073 p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key));
1057 } 1099 }
1058 1100
1059 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1101 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1060 "http file cache update"); 1102 "http file cache update");
1061 1103
1104 cache = c->file_cache;
1105
1106 if (c->secondary
1107 && ngx_memcmp(c->variant, c->key, NGX_HTTP_CACHE_KEY_LEN) != 0)
1108 {
1109 /*
1110 * if the variant hash doesn't match one we used as a secondary
1111 * cache key, switch back to the original key
1112 */
1113
1114 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1115 "http file cache main key");
1116
1117 ngx_shmtx_lock(&cache->shpool->mutex);
1118
1119 c->node->count--;
1120 c->node->updating = 0;
1121 c->node = NULL;
1122
1123 ngx_shmtx_unlock(&cache->shpool->mutex);
1124
1125 c->file.name.len = 0;
1126
1127 ngx_memcpy(c->key, c->main, NGX_HTTP_CACHE_KEY_LEN);
1128
1129 if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) {
1130 return;
1131 }
1132
1133 if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
1134 return;
1135 }
1136 }
1137
1062 c->updated = 1; 1138 c->updated = 1;
1063 c->updating = 0; 1139 c->updating = 0;
1064
1065 cache = c->file_cache;
1066 1140
1067 uniq = 0; 1141 uniq = 0;
1068 fs_size = 0; 1142 fs_size = 0;
1069 1143
1070 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1144 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,