Mercurial > hg > nginx-quic
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, |