comparison src/http/ngx_http_file_cache.c @ 665:0b460e61bdcd default tip

Merge with nginx 1.0.0.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 25 Apr 2011 04:22:17 +0400
parents b4dcae568a2a
children
comparison
equal deleted inserted replaced
572:06419a2298a9 665:0b460e61bdcd
9 #include <ngx_http.h> 9 #include <ngx_http.h>
10 #include <ngx_md5.h> 10 #include <ngx_md5.h>
11 11
12 12
13 static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, 13 static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
14 ngx_http_cache_t *c);
15 static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r,
14 ngx_http_cache_t *c); 16 ngx_http_cache_t *c);
15 #if (NGX_HAVE_FILE_AIO) 17 #if (NGX_HAVE_FILE_AIO)
16 static void ngx_http_cache_aio_event_handler(ngx_event_t *ev); 18 static void ngx_http_cache_aio_event_handler(ngx_event_t *ev);
17 #endif 19 #endif
18 static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, 20 static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
19 ngx_http_cache_t *c); 21 ngx_http_cache_t *c);
22 static ngx_int_t ngx_http_file_cache_name(ngx_http_request_t *r,
23 ngx_path_t *path);
20 static ngx_http_file_cache_node_t * 24 static ngx_http_file_cache_node_t *
21 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); 25 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
22 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, 26 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
23 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); 27 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
24 static void ngx_http_file_cache_cleanup(void *data); 28 static void ngx_http_file_cache_cleanup(void *data);
40 ngx_str_t *path); 44 ngx_str_t *path);
41 45
42 46
43 ngx_str_t ngx_http_cache_status[] = { 47 ngx_str_t ngx_http_cache_status[] = {
44 ngx_string("MISS"), 48 ngx_string("MISS"),
49 ngx_string("BYPASS"),
45 ngx_string("EXPIRED"), 50 ngx_string("EXPIRED"),
46 ngx_string("STALE"), 51 ngx_string("STALE"),
47 ngx_string("UPDATING"), 52 ngx_string("UPDATING"),
48 ngx_string("HIT") 53 ngx_string("HIT")
49 }; 54 };
138 143
139 return NGX_OK; 144 return NGX_OK;
140 } 145 }
141 146
142 147
148 ngx_int_t
149 ngx_http_file_cache_new(ngx_http_request_t *r)
150 {
151 ngx_http_cache_t *c;
152
153 c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
154 if (c == NULL) {
155 return NGX_ERROR;
156 }
157
158 if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
159 return NGX_ERROR;
160 }
161
162 r->cache = c;
163 c->file.log = r->connection->log;
164 c->file.fd = NGX_INVALID_FILE;
165
166 return NGX_OK;
167 }
168
169
170 ngx_int_t
171 ngx_http_file_cache_create(ngx_http_request_t *r)
172 {
173 ngx_http_cache_t *c;
174 ngx_pool_cleanup_t *cln;
175 ngx_http_file_cache_t *cache;
176
177 ngx_http_file_cache_create_key(r);
178
179 c = r->cache;
180 cache = c->file_cache;
181
182 cln = ngx_pool_cleanup_add(r->pool, 0);
183 if (cln == NULL) {
184 return NGX_ERROR;
185 }
186
187 if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) {
188 return NGX_ERROR;
189 }
190
191 cln->handler = ngx_http_file_cache_cleanup;
192 cln->data = c;
193
194 if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
195 return NGX_ERROR;
196 }
197
198 return NGX_OK;
199 }
200
201
143 void 202 void
144 ngx_http_file_cache_create_key(ngx_http_request_t *r) 203 ngx_http_file_cache_create_key(ngx_http_request_t *r)
145 { 204 {
146 size_t len; 205 size_t len;
147 ngx_str_t *key; 206 ngx_str_t *key;
176 235
177 236
178 ngx_int_t 237 ngx_int_t
179 ngx_http_file_cache_open(ngx_http_request_t *r) 238 ngx_http_file_cache_open(ngx_http_request_t *r)
180 { 239 {
181 u_char *p;
182 ngx_int_t rc, rv; 240 ngx_int_t rc, rv;
183 ngx_uint_t cold, test; 241 ngx_uint_t cold, test;
184 ngx_path_t *path;
185 ngx_http_cache_t *c; 242 ngx_http_cache_t *c;
186 ngx_pool_cleanup_t *cln; 243 ngx_pool_cleanup_t *cln;
187 ngx_open_file_info_t of; 244 ngx_open_file_info_t of;
188 ngx_http_file_cache_t *cache; 245 ngx_http_file_cache_t *cache;
189 ngx_http_core_loc_conf_t *clcf; 246 ngx_http_core_loc_conf_t *clcf;
245 test = cold ? 1 : 0; 302 test = cold ? 1 : 0;
246 rv = NGX_DECLINED; 303 rv = NGX_DECLINED;
247 } 304 }
248 } 305 }
249 306
250 path = cache->path; 307 if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
251
252 c->file.name.len = path->name.len + 1 + path->len
253 + 2 * NGX_HTTP_CACHE_KEY_LEN;
254
255 c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1);
256 if (c->file.name.data == NULL) {
257 return NGX_ERROR; 308 return NGX_ERROR;
258 } 309 }
259
260 ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
261
262 p = c->file.name.data + path->name.len + 1 + path->len;
263 p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN);
264 *p = '\0';
265
266 ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len);
267
268 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
269 "cache file: \"%s\"", c->file.name.data);
270 310
271 if (!test) { 311 if (!test) {
272 return NGX_DECLINED; 312 return NGX_DECLINED;
273 } 313 }
274 314
279 of.uniq = c->uniq; 319 of.uniq = c->uniq;
280 of.valid = clcf->open_file_cache_valid; 320 of.valid = clcf->open_file_cache_valid;
281 of.min_uses = clcf->open_file_cache_min_uses; 321 of.min_uses = clcf->open_file_cache_min_uses;
282 of.events = clcf->open_file_cache_events; 322 of.events = clcf->open_file_cache_events;
283 of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; 323 of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
324 of.read_ahead = clcf->read_ahead;
284 325
285 if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) 326 if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool)
286 != NGX_OK) 327 != NGX_OK)
287 { 328 {
288 switch (of.err) { 329 switch (of.err) {
325 ssize_t n; 366 ssize_t n;
326 ngx_int_t rc; 367 ngx_int_t rc;
327 ngx_http_file_cache_t *cache; 368 ngx_http_file_cache_t *cache;
328 ngx_http_file_cache_header_t *h; 369 ngx_http_file_cache_header_t *h;
329 370
330 c = r->cache; 371 n = ngx_http_file_cache_aio_read(r, c);
331 372
332 #if (NGX_HAVE_FILE_AIO) 373 if (n < 0) {
333 {
334 ngx_http_core_loc_conf_t *clcf;
335
336 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
337
338 if (clcf->aio) {
339 n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
340
341 if (n == NGX_AGAIN) {
342 c->file.aio->data = r;
343 c->file.aio->handler = ngx_http_cache_aio_event_handler;
344
345 r->main->blocked++;
346 r->aio = 1;
347
348 return NGX_AGAIN;
349 }
350
351 } else {
352 n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
353 }
354 }
355 #else
356
357 n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
358
359 #endif
360
361 if (n == NGX_ERROR) {
362 return n; 374 return n;
363 } 375 }
364 376
365 if ((size_t) n <= c->header_start) { 377 if ((size_t) n < c->header_start) {
366 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, 378 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
367 "cache file \"%s\" is too small", c->file.name.data); 379 "cache file \"%s\" is too small", c->file.name.data);
368 return NGX_ERROR; 380 return NGX_ERROR;
369 } 381 }
370 382
371 h = (ngx_http_file_cache_header_t *) c->buf->pos; 383 h = (ngx_http_file_cache_header_t *) c->buf->pos;
372 384
373 if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) { 385 if (h->crc32 != c->crc32) {
374 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, 386 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
375 "cache file \"%s\" has md5 collision", c->file.name.data); 387 "cache file \"%s\" has md5 collision", c->file.name.data);
376 return NGX_DECLINED; 388 return NGX_DECLINED;
377 } 389 }
378 390
380 392
381 c->valid_sec = h->valid_sec; 393 c->valid_sec = h->valid_sec;
382 c->last_modified = h->last_modified; 394 c->last_modified = h->last_modified;
383 c->date = h->date; 395 c->date = h->date;
384 c->valid_msec = h->valid_msec; 396 c->valid_msec = h->valid_msec;
397 c->header_start = h->header_start;
385 c->body_start = h->body_start; 398 c->body_start = h->body_start;
386 399
387 r->cached = 1; 400 r->cached = 1;
388 401
389 cache = c->file_cache; 402 cache = c->file_cache;
413 if (c->node->updating) { 426 if (c->node->updating) {
414 rc = NGX_HTTP_CACHE_UPDATING; 427 rc = NGX_HTTP_CACHE_UPDATING;
415 428
416 } else { 429 } else {
417 c->node->updating = 1; 430 c->node->updating = 1;
431 c->updating = 1;
418 rc = NGX_HTTP_CACHE_STALE; 432 rc = NGX_HTTP_CACHE_STALE;
419 } 433 }
420 434
421 ngx_shmtx_unlock(&cache->shpool->mutex); 435 ngx_shmtx_unlock(&cache->shpool->mutex);
422 436
429 443
430 return NGX_OK; 444 return NGX_OK;
431 } 445 }
432 446
433 447
448 static ssize_t
449 ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c)
450 {
434 #if (NGX_HAVE_FILE_AIO) 451 #if (NGX_HAVE_FILE_AIO)
435 452 ssize_t n;
453 ngx_http_core_loc_conf_t *clcf;
454
455 if (!ngx_file_aio) {
456 goto noaio;
457 }
458
459 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
460
461 if (!clcf->aio) {
462 goto noaio;
463 }
464
465 n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
466
467 if (n != NGX_AGAIN) {
468 return n;
469 }
470
471 c->file.aio->data = r;
472 c->file.aio->handler = ngx_http_cache_aio_event_handler;
473
474 r->main->blocked++;
475 r->aio = 1;
476
477 return NGX_AGAIN;
478
479 noaio:
480
481 #endif
482
483 return ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
484 }
485
486
487 #if (NGX_HAVE_FILE_AIO)
436 488
437 static void 489 static void
438 ngx_http_cache_aio_event_handler(ngx_event_t *ev) 490 ngx_http_cache_aio_event_handler(ngx_event_t *ev)
439 { 491 {
440 ngx_event_aio_t *aio; 492 ngx_event_aio_t *aio;
462 514
463 fcn = ngx_http_file_cache_lookup(cache, c->key); 515 fcn = ngx_http_file_cache_lookup(cache, c->key);
464 516
465 if (fcn) { 517 if (fcn) {
466 ngx_queue_remove(&fcn->queue); 518 ngx_queue_remove(&fcn->queue);
519
520 fcn->uses++;
521 fcn->count++;
467 522
468 if (fcn->error) { 523 if (fcn->error) {
469 524
470 if (fcn->valid_sec < ngx_time()) { 525 if (fcn->valid_sec < ngx_time()) {
471 goto renew; 526 goto renew;
473 528
474 rc = NGX_OK; 529 rc = NGX_OK;
475 530
476 goto done; 531 goto done;
477 } 532 }
478
479 fcn->uses++;
480 fcn->count++;
481 533
482 if (fcn->exists) { 534 if (fcn->exists) {
483 535
484 c->exists = fcn->exists; 536 c->exists = fcn->exists;
485 c->body_start = fcn->body_start; 537 c->body_start = fcn->body_start;
525 ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], 577 ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
526 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); 578 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
527 579
528 ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node); 580 ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
529 581
530 renew:
531
532 rc = NGX_DECLINED;
533
534 fcn->uses = 1; 582 fcn->uses = 1;
535 fcn->count = 1; 583 fcn->count = 1;
584 fcn->updating = 0;
585 fcn->deleting = 0;
586
587 renew:
588
589 rc = NGX_DECLINED;
590
536 fcn->valid_msec = 0; 591 fcn->valid_msec = 0;
537 fcn->error = 0; 592 fcn->error = 0;
538 fcn->exists = 0; 593 fcn->exists = 0;
539 fcn->valid_sec = 0; 594 fcn->valid_sec = 0;
540 fcn->uniq = 0; 595 fcn->uniq = 0;
557 612
558 return rc; 613 return rc;
559 } 614 }
560 615
561 616
617 static ngx_int_t
618 ngx_http_file_cache_name(ngx_http_request_t *r, ngx_path_t *path)
619 {
620 u_char *p;
621 ngx_http_cache_t *c;
622
623 c = r->cache;
624
625 c->file.name.len = path->name.len + 1 + path->len
626 + 2 * NGX_HTTP_CACHE_KEY_LEN;
627
628 c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1);
629 if (c->file.name.data == NULL) {
630 return NGX_ERROR;
631 }
632
633 ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
634
635 p = c->file.name.data + path->name.len + 1 + path->len;
636 p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN);
637 *p = '\0';
638
639 ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len);
640
641 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
642 "cache file: \"%s\"", c->file.name.data);
643
644 return NGX_OK;
645 }
646
647
562 static ngx_http_file_cache_node_t * 648 static ngx_http_file_cache_node_t *
563 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key) 649 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key)
564 { 650 {
565 ngx_int_t rc; 651 ngx_int_t rc;
566 ngx_rbtree_key_t node_key; 652 ngx_rbtree_key_t node_key;
689 775
690 776
691 void 777 void
692 ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) 778 ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
693 { 779 {
694 off_t size; 780 off_t size, length;
695 ngx_int_t rc; 781 ngx_int_t rc;
696 ngx_file_uniq_t uniq; 782 ngx_file_uniq_t uniq;
697 ngx_file_info_t fi; 783 ngx_file_info_t fi;
698 ngx_http_cache_t *c; 784 ngx_http_cache_t *c;
699 ngx_ext_rename_file_t ext; 785 ngx_ext_rename_file_t ext;
707 793
708 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 794 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
709 "http file cache update"); 795 "http file cache update");
710 796
711 c->updated = 1; 797 c->updated = 1;
798 c->updating = 0;
712 799
713 cache = c->file_cache; 800 cache = c->file_cache;
714 801
715 uniq = 0; 802 uniq = 0;
803 length = 0;
716 804
717 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 805 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
718 "http file cache rename: \"%s\" to \"%s\"", 806 "http file cache rename: \"%s\" to \"%s\"",
719 tf->file.name.data, c->file.name.data); 807 tf->file.name.data, c->file.name.data);
720 808
735 823
736 rc = NGX_ERROR; 824 rc = NGX_ERROR;
737 825
738 } else { 826 } else {
739 uniq = ngx_file_uniq(&fi); 827 uniq = ngx_file_uniq(&fi);
740 } 828 length = ngx_file_size(&fi);
741 } 829 }
742 830 }
743 size = (c->length + cache->bsize - 1) / cache->bsize; 831
832 size = (length + cache->bsize - 1) / cache->bsize;
744 833
745 ngx_shmtx_lock(&cache->shpool->mutex); 834 ngx_shmtx_lock(&cache->shpool->mutex);
746 835
747 c->node->count--; 836 c->node->count--;
748 c->node->uniq = uniq; 837 c->node->uniq = uniq;
749 c->node->body_start = c->body_start; 838 c->node->body_start = c->body_start;
750 839
751 size = size - (c->node->length + cache->bsize - 1) / cache->bsize; 840 size = size - (c->node->length + cache->bsize - 1) / cache->bsize;
752 841
753 c->node->length = c->length; 842 c->node->length = length;
754 843
755 cache->sh->size += size; 844 cache->sh->size += size;
756 845
757 if (rc == NGX_OK) { 846 if (rc == NGX_OK) {
758 c->node->exists = 1; 847 c->node->exists = 1;
765 854
766 855
767 ngx_int_t 856 ngx_int_t
768 ngx_http_cache_send(ngx_http_request_t *r) 857 ngx_http_cache_send(ngx_http_request_t *r)
769 { 858 {
770 off_t size;
771 ngx_int_t rc; 859 ngx_int_t rc;
772 ngx_buf_t *b; 860 ngx_buf_t *b;
773 ngx_chain_t out; 861 ngx_chain_t out;
774 ngx_http_cache_t *c; 862 ngx_http_cache_t *c;
775 863
788 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); 876 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
789 if (b->file == NULL) { 877 if (b->file == NULL) {
790 return NGX_HTTP_INTERNAL_SERVER_ERROR; 878 return NGX_HTTP_INTERNAL_SERVER_ERROR;
791 } 879 }
792 880
881 r->header_only = (c->length - c->body_start) == 0;
882
793 rc = ngx_http_send_header(r); 883 rc = ngx_http_send_header(r);
794 884
795 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 885 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
796 return rc; 886 return rc;
797 } 887 }
798 888
799 size = c->length - c->body_start;
800 if (size == 0) {
801 return rc;
802 }
803
804 b->file_pos = c->body_start; 889 b->file_pos = c->body_start;
805 b->file_last = c->length; 890 b->file_last = c->length;
806 891
807 b->in_file = size ? 1: 0; 892 b->in_file = 1;
808 b->last_buf = (r == r->main) ? 1: 0; 893 b->last_buf = (r == r->main) ? 1: 0;
809 b->last_in_chain = 1; 894 b->last_in_chain = 1;
810 895
811 b->file->fd = c->file.fd; 896 b->file->fd = c->file.fd;
812 b->file->name = c->file.name; 897 b->file->name = c->file.name;
818 return ngx_http_output_filter(r, &out); 903 return ngx_http_output_filter(r, &out);
819 } 904 }
820 905
821 906
822 void 907 void
823 ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf) 908 ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf)
824 { 909 {
825 ngx_http_cache_t *c; 910 ngx_http_file_cache_t *cache;
826 ngx_http_file_cache_t *cache; 911 ngx_http_file_cache_node_t *fcn;
827
828 c = r->cache;
829 912
830 if (c->updated) { 913 if (c->updated) {
831 return; 914 return;
832 } 915 }
833 916
917 cache = c->file_cache;
918
919 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
920 "http file cache free, fd: %d", c->file.fd);
921
922 ngx_shmtx_lock(&cache->shpool->mutex);
923
924 fcn = c->node;
925 fcn->count--;
926
927 if (c->updating) {
928 fcn->updating = 0;
929 }
930
931 if (c->error) {
932 fcn->error = c->error;
933
934 if (c->valid_sec) {
935 fcn->valid_sec = c->valid_sec;
936 fcn->valid_msec = c->valid_msec;
937 }
938
939 } else if (!fcn->exists && fcn->count == 0 && c->min_uses == 1) {
940 ngx_queue_remove(&fcn->queue);
941 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
942 ngx_slab_free_locked(cache->shpool, fcn);
943 c->node = NULL;
944 }
945
946 ngx_shmtx_unlock(&cache->shpool->mutex);
947
834 c->updated = 1; 948 c->updated = 1;
835 949 c->updating = 0;
836 cache = c->file_cache;
837
838 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
839 "http file cache free");
840
841 ngx_shmtx_lock(&cache->shpool->mutex);
842
843 c->node->count--;
844
845 if (c->error) {
846 c->node->valid_sec = c->valid_sec;
847 c->node->valid_msec = c->valid_msec;
848 c->node->error = c->error;
849 }
850
851 c->node->updating = 0;
852
853 ngx_shmtx_unlock(&cache->shpool->mutex);
854 950
855 if (c->temp_file) { 951 if (c->temp_file) {
856 if (tf && tf->file.fd != NGX_INVALID_FILE) { 952 if (tf && tf->file.fd != NGX_INVALID_FILE) {
857 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 953 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
858 "http file cache incomplete: \"%s\"", 954 "http file cache incomplete: \"%s\"",
859 tf->file.name.data); 955 tf->file.name.data);
860 956
861 if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) { 957 if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
862 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, 958 ngx_log_error(NGX_LOG_CRIT, c->file.log, ngx_errno,
863 ngx_delete_file_n " \"%s\" failed", 959 ngx_delete_file_n " \"%s\" failed",
864 tf->file.name.data); 960 tf->file.name.data);
865 } 961 }
866 } 962 }
867 } 963 }
871 static void 967 static void
872 ngx_http_file_cache_cleanup(void *data) 968 ngx_http_file_cache_cleanup(void *data)
873 { 969 {
874 ngx_http_cache_t *c = data; 970 ngx_http_cache_t *c = data;
875 971
876 ngx_http_file_cache_t *cache;
877
878 if (c->updated) { 972 if (c->updated) {
879 return; 973 return;
880 } 974 }
881 975
882 c->updated = 1;
883
884 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0, 976 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
885 "http file cache cleanup"); 977 "http file cache cleanup");
886 978
887 if (c->error) { 979 if (c->updating) {
888 return; 980 ngx_log_error(NGX_LOG_ALERT, c->file.log, 0,
889 } 981 "stalled cache updating, error:%ui", c->error);
890 982 }
891 cache = c->file_cache; 983
892 984 ngx_http_file_cache_free(c, NULL);
893 ngx_shmtx_lock(&cache->shpool->mutex);
894
895 c->node->count--;
896
897 ngx_shmtx_unlock(&cache->shpool->mutex);
898 } 985 }
899 986
900 987
901 static time_t 988 static time_t
902 ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) 989 ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache)
921 } 1008 }
922 1009
923 ngx_memcpy(name, path->name.data, path->name.len); 1010 ngx_memcpy(name, path->name.data, path->name.len);
924 1011
925 wait = 10; 1012 wait = 10;
926 tries = 0; 1013 tries = 20;
927 1014
928 ngx_shmtx_lock(&cache->shpool->mutex); 1015 ngx_shmtx_lock(&cache->shpool->mutex);
929 1016
930 for (q = ngx_queue_last(&cache->sh->queue); 1017 for (q = ngx_queue_last(&cache->sh->queue);
931 q != ngx_queue_sentinel(&cache->sh->queue); 1018 q != ngx_queue_sentinel(&cache->sh->queue);
936 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, 1023 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
937 "http file cache forced expire: #%d %d %02xd%02xd%02xd%02xd", 1024 "http file cache forced expire: #%d %d %02xd%02xd%02xd%02xd",
938 fcn->count, fcn->exists, 1025 fcn->count, fcn->exists,
939 fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); 1026 fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
940 1027
941 if (fcn->count) { 1028 if (fcn->count == 0) {
942 1029 ngx_http_file_cache_delete(cache, q, name);
943 if (tries++ < 20) { 1030 wait = 0;
1031
1032 } else {
1033 if (--tries) {
944 continue; 1034 continue;
945 } 1035 }
946 1036
947 wait = 1; 1037 wait = 1;
948 1038 }
949 break;
950 }
951
952 if (!fcn->exists) {
953
954 ngx_queue_remove(q);
955 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
956 ngx_slab_free_locked(cache->shpool, fcn);
957
958 break;
959 }
960
961 ngx_http_file_cache_delete(cache, q, name);
962 1039
963 break; 1040 break;
964 } 1041 }
965 1042
966 ngx_shmtx_unlock(&cache->shpool->mutex); 1043 ngx_shmtx_unlock(&cache->shpool->mutex);
1020 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, 1097 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1021 "http file cache expire: #%d %d %02xd%02xd%02xd%02xd", 1098 "http file cache expire: #%d %d %02xd%02xd%02xd%02xd",
1022 fcn->count, fcn->exists, 1099 fcn->count, fcn->exists,
1023 fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); 1100 fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
1024 1101
1025 if (fcn->count) { 1102 if (fcn->count == 0) {
1026 1103 ngx_http_file_cache_delete(cache, q, name);
1027 p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
1028 sizeof(ngx_rbtree_key_t));
1029
1030 len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
1031 (void) ngx_hex_dump(p, fcn->key, len);
1032
1033 /*
1034 * abnormally exited workers may leave locked cache entries,
1035 * and although it may be safe to remove them completely,
1036 * we prefer to remove them from inactive queue and rbtree
1037 * only, and to allow other leaks
1038 */
1039
1040 ngx_queue_remove(q);
1041 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1042
1043 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
1044 "ignore long locked inactive cache entry %*s, count:%d",
1045 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count);
1046
1047 continue; 1104 continue;
1048 } 1105 }
1049 1106
1050 if (!fcn->exists) { 1107 if (fcn->deleting) {
1051
1052 ngx_queue_remove(q);
1053 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1054 ngx_slab_free_locked(cache->shpool, fcn);
1055
1056 continue; 1108 continue;
1057 } 1109 }
1058 1110
1059 ngx_http_file_cache_delete(cache, q, name); 1111 p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
1112 sizeof(ngx_rbtree_key_t));
1113 len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
1114 (void) ngx_hex_dump(p, fcn->key, len);
1115
1116 /*
1117 * abnormally exited workers may leave locked cache entries,
1118 * and although it may be safe to remove them completely,
1119 * we prefer to remove them from inactive queue and rbtree
1120 * only, and to allow other leaks
1121 */
1122
1123 ngx_queue_remove(q);
1124 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1125
1126 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
1127 "ignore long locked inactive cache entry %*s, count:%d",
1128 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count);
1060 } 1129 }
1061 1130
1062 ngx_shmtx_unlock(&cache->shpool->mutex); 1131 ngx_shmtx_unlock(&cache->shpool->mutex);
1063 1132
1064 ngx_free(name); 1133 ngx_free(name);
1076 ngx_path_t *path; 1145 ngx_path_t *path;
1077 ngx_http_file_cache_node_t *fcn; 1146 ngx_http_file_cache_node_t *fcn;
1078 1147
1079 fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); 1148 fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
1080 1149
1081 cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize; 1150 if (fcn->exists) {
1082 1151 cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
1083 path = cache->path; 1152
1084 1153 path = cache->path;
1085 p = name + path->name.len + 1 + path->len; 1154 p = name + path->name.len + 1 + path->len;
1086 1155 p = ngx_hex_dump(p, (u_char *) &fcn->node.key,
1087 p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); 1156 sizeof(ngx_rbtree_key_t));
1088 1157 len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
1089 len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); 1158 p = ngx_hex_dump(p, fcn->key, len);
1090 p = ngx_hex_dump(p, fcn->key, len); 1159 *p = '\0';
1091 *p = '\0'; 1160
1092 1161 fcn->count++;
1093 ngx_queue_remove(q); 1162 fcn->deleting = 1;
1094 1163 ngx_shmtx_unlock(&cache->shpool->mutex);
1095 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); 1164
1096 1165 len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
1097 ngx_slab_free_locked(cache->shpool, fcn); 1166 ngx_create_hashed_filename(path, name, len);
1098 1167
1099 ngx_shmtx_unlock(&cache->shpool->mutex); 1168 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1100 1169 "http file cache expire: \"%s\"", name);
1101 len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; 1170
1102 1171 if (ngx_delete_file(name) == NGX_FILE_ERROR) {
1103 ngx_create_hashed_filename(path, name, len); 1172 ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
1104 1173 ngx_delete_file_n " \"%s\" failed", name);
1105 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, 1174 }
1106 "http file cache expire: \"%s\"", name); 1175
1107 1176 ngx_shmtx_lock(&cache->shpool->mutex);
1108 if (ngx_delete_file(name) == NGX_FILE_ERROR) { 1177 fcn->count--;
1109 ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, 1178 fcn->deleting = 0;
1110 ngx_delete_file_n " \"%s\" failed", name); 1179 }
1111 } 1180
1112 1181 if (fcn->count == 0) {
1113 ngx_shmtx_lock(&cache->shpool->mutex); 1182 ngx_queue_remove(q);
1183 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1184 ngx_slab_free_locked(cache->shpool, fcn);
1185 }
1114 } 1186 }
1115 1187
1116 1188
1117 static time_t 1189 static time_t
1118 ngx_http_file_cache_manager(void *data) 1190 ngx_http_file_cache_manager(void *data)
1119 { 1191 {
1120 ngx_http_file_cache_t *cache = data; 1192 ngx_http_file_cache_t *cache = data;
1121 1193
1122 off_t size; 1194 off_t size;
1123 time_t next; 1195 time_t next, wait;
1124 1196
1125 next = ngx_http_file_cache_expire(cache); 1197 next = ngx_http_file_cache_expire(cache);
1126 1198
1127 cache->last = ngx_current_msec; 1199 cache->last = ngx_current_msec;
1128 cache->files = 0; 1200 cache->files = 0;
1139 1211
1140 if (size < cache->max_size) { 1212 if (size < cache->max_size) {
1141 return next; 1213 return next;
1142 } 1214 }
1143 1215
1144 next = ngx_http_file_cache_forced_expire(cache); 1216 wait = ngx_http_file_cache_forced_expire(cache);
1217
1218 if (wait > 0) {
1219 return wait;
1220 }
1145 1221
1146 if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) { 1222 if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) {
1147 return next; 1223 return next;
1148 } 1224 }
1149 } 1225 }
1201 { 1277 {
1202 ngx_msec_t elapsed; 1278 ngx_msec_t elapsed;
1203 1279
1204 if (cache->files++ > 100) { 1280 if (cache->files++ > 100) {
1205 1281
1206 ngx_time_update(0, 0); 1282 ngx_time_update();
1207 1283
1208 elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); 1284 elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));
1209 1285
1210 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, 1286 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1211 "http file cache manager time: %M", elapsed); 1287 "http file cache manager time: %M", elapsed);
1218 * therefore sleep 200ms 1294 * therefore sleep 200ms
1219 */ 1295 */
1220 1296
1221 ngx_msleep(200); 1297 ngx_msleep(200);
1222 1298
1223 ngx_time_update(0, 0); 1299 ngx_time_update();
1224 } 1300 }
1225 1301
1226 cache->last = ngx_current_msec; 1302 cache->last = ngx_current_msec;
1227 cache->files = 0; 1303 cache->files = 0;
1228 } 1304 }
1364 fcn->uses = 1; 1440 fcn->uses = 1;
1365 fcn->count = 0; 1441 fcn->count = 0;
1366 fcn->valid_msec = c->valid_msec; 1442 fcn->valid_msec = c->valid_msec;
1367 fcn->error = 0; 1443 fcn->error = 0;
1368 fcn->exists = 1; 1444 fcn->exists = 1;
1445 fcn->updating = 0;
1446 fcn->deleting = 0;
1369 fcn->uniq = c->uniq; 1447 fcn->uniq = c->uniq;
1370 fcn->valid_sec = c->valid_sec; 1448 fcn->valid_sec = c->valid_sec;
1371 fcn->body_start = c->body_start; 1449 fcn->body_start = c->body_start;
1372 fcn->length = c->length; 1450 fcn->length = c->length;
1373 1451
1677 v->valid = valid; 1755 v->valid = valid;
1678 } 1756 }
1679 1757
1680 return NGX_CONF_OK; 1758 return NGX_CONF_OK;
1681 } 1759 }
1760
1761
1762 ngx_int_t
1763 ngx_http_cache(ngx_http_request_t *r, ngx_array_t *no_cache)
1764 {
1765 ngx_str_t val;
1766 ngx_uint_t i;
1767 ngx_http_complex_value_t *cv;
1768
1769 cv = no_cache->elts;
1770
1771 for (i = 0; i < no_cache->nelts; i++) {
1772 if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
1773 return NGX_ERROR;
1774 }
1775
1776 if (val.len && val.data[0] != '0') {
1777 return NGX_DECLINED;
1778 }
1779 }
1780
1781 return NGX_OK;
1782 }
1783
1784
1785 char *
1786 ngx_http_no_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1787 {
1788 char *p = conf;
1789
1790 ngx_str_t *value;
1791 ngx_uint_t i;
1792 ngx_array_t **a;
1793 ngx_http_complex_value_t *cv;
1794 ngx_http_compile_complex_value_t ccv;
1795
1796 a = (ngx_array_t **) (p + cmd->offset);
1797
1798 if (*a == NGX_CONF_UNSET_PTR) {
1799 *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
1800 if (*a == NULL) {
1801 return NGX_CONF_ERROR;
1802 }
1803 }
1804
1805 value = cf->args->elts;
1806
1807 for (i = 1; i < cf->args->nelts; i++) {
1808 cv = ngx_array_push(*a);
1809 if (cv == NULL) {
1810 return NGX_CONF_ERROR;
1811 }
1812
1813 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
1814
1815 ccv.cf = cf;
1816 ccv.value = &value[i];
1817 ccv.complex_value = cv;
1818
1819 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
1820 return NGX_CONF_ERROR;
1821 }
1822 }
1823
1824 return NGX_CONF_OK;
1825 }