Mercurial > hg > nginx-vendor-current
comparison src/http/ngx_http_file_cache.c @ 468:56baf312c1b5 NGINX_0_7_46
nginx 0.7.46
*) Bugfix: the previous release tarball was incorrect.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 30 Mar 2009 00:00:00 +0400 |
parents | 9eda3153223b |
children | 6866b490272e |
comparison
equal
deleted
inserted
replaced
467:d46142e61c30 | 468:56baf312c1b5 |
---|---|
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
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_exists(ngx_http_request_t *r, | 13 static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, |
14 ngx_http_file_cache_t *cache); | 14 ngx_http_cache_t *c); |
15 static ngx_http_file_cache_node_t * | 15 static ngx_http_file_cache_node_t * |
16 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); | 16 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); |
17 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, | 17 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, |
18 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); | 18 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); |
19 static void ngx_http_file_cache_cleanup(void *data); | 19 static void ngx_http_file_cache_cleanup(void *data); |
20 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache, | 20 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache); |
21 ngx_uint_t force); | 21 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache); |
22 static ngx_int_t ngx_http_file_cache_clean_noop(ngx_tree_ctx_t *ctx, | 22 static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, |
23 ngx_queue_t *q, u_char *name); | |
24 static ngx_int_t | |
25 ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache); | |
26 static ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, | |
23 ngx_str_t *path); | 27 ngx_str_t *path); |
24 static ngx_int_t ngx_http_file_cache_clean_file(ngx_tree_ctx_t *ctx, | 28 static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, |
29 ngx_str_t *path); | |
30 static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, | |
31 ngx_str_t *path); | |
32 static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache, | |
33 ngx_http_cache_t *c); | |
34 static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, | |
25 ngx_str_t *path); | 35 ngx_str_t *path); |
26 | 36 |
27 | 37 |
28 static u_char ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' }; | 38 static u_char ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' }; |
29 | 39 |
31 static ngx_int_t | 41 static ngx_int_t |
32 ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) | 42 ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) |
33 { | 43 { |
34 ngx_http_file_cache_t *ocache = data; | 44 ngx_http_file_cache_t *ocache = data; |
35 | 45 |
46 size_t len; | |
36 ngx_rbtree_node_t *sentinel; | 47 ngx_rbtree_node_t *sentinel; |
37 ngx_http_file_cache_t *cache; | 48 ngx_http_file_cache_t *cache; |
38 | 49 |
39 cache = shm_zone->data; | 50 cache = shm_zone->data; |
40 | 51 |
50 } | 61 } |
51 | 62 |
52 cache->rbtree = ocache->rbtree; | 63 cache->rbtree = ocache->rbtree; |
53 cache->queue = ocache->queue; | 64 cache->queue = ocache->queue; |
54 cache->shpool = ocache->shpool; | 65 cache->shpool = ocache->shpool; |
55 cache->created = ocache->created; | 66 cache->cold = ocache->cold; |
67 cache->size = ocache->size; | |
68 cache->bsize = ocache->bsize; | |
69 | |
70 cache->max_size /= cache->bsize; | |
56 | 71 |
57 return NGX_OK; | 72 return NGX_OK; |
58 } | 73 } |
59 | 74 |
60 cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; | 75 cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; |
77 return NGX_ERROR; | 92 return NGX_ERROR; |
78 } | 93 } |
79 | 94 |
80 ngx_queue_init(cache->queue); | 95 ngx_queue_init(cache->queue); |
81 | 96 |
82 cache->created = ngx_time(); | 97 cache->cold = ngx_slab_alloc(cache->shpool, sizeof(ngx_atomic_t)); |
98 if (cache->cold == NULL) { | |
99 return NGX_ERROR; | |
100 } | |
101 | |
102 *cache->cold = 1; | |
103 | |
104 cache->size = ngx_slab_alloc(cache->shpool, sizeof(off_t)); | |
105 if (cache->size == NULL) { | |
106 return NGX_ERROR; | |
107 } | |
108 | |
109 *cache->size = 0; | |
110 | |
111 cache->bsize = ngx_fs_bsize(cache->path->name.data); | |
112 | |
113 cache->max_size /= cache->bsize; | |
114 | |
115 len = sizeof(" in cache keys zone \"\"") + shm_zone->name.len; | |
116 | |
117 cache->shpool->log_ctx = ngx_slab_alloc(cache->shpool, len); | |
118 if (cache->shpool->log_ctx == NULL) { | |
119 return NGX_ERROR; | |
120 } | |
121 | |
122 ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z", | |
123 &shm_zone->name); | |
83 | 124 |
84 return NGX_OK; | 125 return NGX_OK; |
85 } | 126 } |
86 | 127 |
87 | 128 |
142 cln = ngx_pool_cleanup_add(r->pool, 0); | 183 cln = ngx_pool_cleanup_add(r->pool, 0); |
143 if (cln == NULL) { | 184 if (cln == NULL) { |
144 return NGX_ERROR; | 185 return NGX_ERROR; |
145 } | 186 } |
146 | 187 |
147 rc = ngx_http_file_cache_exists(r, cache); | 188 rc = ngx_http_file_cache_exists(cache, c); |
148 | 189 |
149 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 190 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
150 "http file cache exists: %i u:%ui e:%d", | 191 "http file cache exists: %i u:%ui e:%d", |
151 rc, c->uses, c->exists); | 192 rc, c->uses, c->exists); |
152 | 193 |
159 | 200 |
160 if (rc == NGX_AGAIN) { | 201 if (rc == NGX_AGAIN) { |
161 return rc; | 202 return rc; |
162 } | 203 } |
163 | 204 |
164 now = ngx_time(); | 205 cold = *cache->cold; |
165 | |
166 cold = (now - cache->created < cache->inactive) ? 1 : 0; | |
167 | 206 |
168 if (rc == NGX_OK) { | 207 if (rc == NGX_OK) { |
169 | 208 |
170 if (c->error) { | 209 if (c->error) { |
171 return c->error; | 210 return c->error; |
291 | 330 |
292 if (cold) { | 331 if (cold) { |
293 | 332 |
294 ngx_shmtx_lock(&cache->shpool->mutex); | 333 ngx_shmtx_lock(&cache->shpool->mutex); |
295 | 334 |
296 c->node->uses = c->min_uses; | 335 if (!c->node->exists) { |
297 c->node->body_start = c->body_start; | 336 c->node->uses = 1; |
298 c->node->exists = 1; | 337 c->node->body_start = c->body_start; |
338 c->node->exists = 1; | |
339 | |
340 *cache->size += (c->length + cache->bsize - 1) / cache->bsize; | |
341 } | |
299 | 342 |
300 ngx_shmtx_unlock(&cache->shpool->mutex); | 343 ngx_shmtx_unlock(&cache->shpool->mutex); |
301 } | 344 } |
345 | |
346 now = ngx_time(); | |
302 | 347 |
303 if (c->valid_sec < now) { | 348 if (c->valid_sec < now) { |
304 | 349 |
305 c->uses = c->min_uses; | 350 c->uses = c->min_uses; |
306 | 351 |
315 return NGX_OK; | 360 return NGX_OK; |
316 } | 361 } |
317 | 362 |
318 | 363 |
319 static ngx_int_t | 364 static ngx_int_t |
320 ngx_http_file_cache_exists(ngx_http_request_t *r, ngx_http_file_cache_t *cache) | 365 ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) |
321 { | 366 { |
322 ngx_int_t rc; | 367 ngx_int_t rc; |
323 ngx_http_file_cache_node_t *fcn; | 368 ngx_http_file_cache_node_t *fcn; |
324 | 369 |
325 ngx_shmtx_lock(&cache->shpool->mutex); | 370 ngx_shmtx_lock(&cache->shpool->mutex); |
326 | 371 |
327 fcn = ngx_http_file_cache_lookup(cache, r->cache->key); | 372 fcn = ngx_http_file_cache_lookup(cache, c->key); |
328 | 373 |
329 if (fcn) { | 374 if (fcn) { |
330 ngx_queue_remove(&fcn->queue); | 375 ngx_queue_remove(&fcn->queue); |
331 | 376 |
332 if (fcn->error) { | 377 if (fcn->error) { |
343 fcn->uses++; | 388 fcn->uses++; |
344 fcn->count++; | 389 fcn->count++; |
345 | 390 |
346 if (fcn->exists) { | 391 if (fcn->exists) { |
347 | 392 |
348 r->cache->exists = fcn->exists; | 393 c->exists = fcn->exists; |
349 r->cache->body_start = fcn->body_start; | 394 c->body_start = fcn->body_start; |
350 | 395 |
351 rc = NGX_OK; | 396 rc = NGX_OK; |
352 | 397 |
353 goto done; | 398 goto done; |
354 } | 399 } |
355 | 400 |
356 if (fcn->uses >= r->cache->min_uses) { | 401 if (fcn->uses >= c->min_uses) { |
357 | 402 |
358 r->cache->exists = fcn->exists; | 403 c->exists = fcn->exists; |
359 r->cache->body_start = fcn->body_start; | 404 c->body_start = fcn->body_start; |
360 | 405 |
361 rc = NGX_OK; | 406 rc = NGX_OK; |
362 | 407 |
363 } else { | 408 } else { |
364 rc = NGX_AGAIN; | 409 rc = NGX_AGAIN; |
370 fcn = ngx_slab_alloc_locked(cache->shpool, | 415 fcn = ngx_slab_alloc_locked(cache->shpool, |
371 sizeof(ngx_http_file_cache_node_t)); | 416 sizeof(ngx_http_file_cache_node_t)); |
372 if (fcn == NULL) { | 417 if (fcn == NULL) { |
373 ngx_shmtx_unlock(&cache->shpool->mutex); | 418 ngx_shmtx_unlock(&cache->shpool->mutex); |
374 | 419 |
375 (void) ngx_http_file_cache_expire(cache, 1); | 420 ngx_http_file_cache_forced_expire(cache); |
376 | 421 |
377 ngx_shmtx_lock(&cache->shpool->mutex); | 422 ngx_shmtx_lock(&cache->shpool->mutex); |
378 | 423 |
379 fcn = ngx_slab_alloc_locked(cache->shpool, | 424 fcn = ngx_slab_alloc_locked(cache->shpool, |
380 sizeof(ngx_http_file_cache_node_t)); | 425 sizeof(ngx_http_file_cache_node_t)); |
382 rc = NGX_ERROR; | 427 rc = NGX_ERROR; |
383 goto failed; | 428 goto failed; |
384 } | 429 } |
385 } | 430 } |
386 | 431 |
387 ngx_memcpy((u_char *) &fcn->node.key, r->cache->key, | 432 ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); |
388 sizeof(ngx_rbtree_key_t)); | 433 |
389 | 434 ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], |
390 ngx_memcpy(fcn->key, &r->cache->key[sizeof(ngx_rbtree_key_t)], | |
391 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); | 435 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); |
392 | 436 |
393 ngx_rbtree_insert(cache->rbtree, &fcn->node); | 437 ngx_rbtree_insert(cache->rbtree, &fcn->node); |
394 | 438 |
395 renew: | 439 renew: |
409 | 453 |
410 fcn->expire = ngx_time() + cache->inactive; | 454 fcn->expire = ngx_time() + cache->inactive; |
411 | 455 |
412 ngx_queue_insert_head(cache->queue, &fcn->queue); | 456 ngx_queue_insert_head(cache->queue, &fcn->queue); |
413 | 457 |
414 r->cache->uniq = fcn->uniq; | 458 c->uniq = fcn->uniq; |
415 r->cache->uses = fcn->uses; | 459 c->uses = fcn->uses; |
416 r->cache->error = fcn->error; | 460 c->error = fcn->error; |
417 r->cache->node = fcn; | 461 c->node = fcn; |
418 | 462 |
419 failed: | 463 failed: |
420 | 464 |
421 ngx_shmtx_unlock(&cache->shpool->mutex); | 465 ngx_shmtx_unlock(&cache->shpool->mutex); |
422 | 466 |
554 | 598 |
555 | 599 |
556 void | 600 void |
557 ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) | 601 ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) |
558 { | 602 { |
603 off_t size; | |
559 ngx_int_t rc; | 604 ngx_int_t rc; |
560 ngx_file_uniq_t uniq; | 605 ngx_file_uniq_t uniq; |
561 ngx_file_info_t fi; | 606 ngx_file_info_t fi; |
562 ngx_http_cache_t *c; | 607 ngx_http_cache_t *c; |
563 ngx_ext_rename_file_t ext; | 608 ngx_ext_rename_file_t ext; |
603 } else { | 648 } else { |
604 uniq = ngx_file_uniq(&fi); | 649 uniq = ngx_file_uniq(&fi); |
605 } | 650 } |
606 } | 651 } |
607 | 652 |
653 size = (c->length + cache->bsize - 1) / cache->bsize; | |
654 | |
608 ngx_shmtx_lock(&cache->shpool->mutex); | 655 ngx_shmtx_lock(&cache->shpool->mutex); |
609 | 656 |
610 c->node->count--; | 657 c->node->count--; |
611 c->node->uniq = uniq; | 658 c->node->uniq = uniq; |
612 c->node->body_start = c->body_start; | 659 c->node->body_start = c->body_start; |
660 | |
661 size = size - (c->node->length + cache->bsize - 1) / cache->bsize; | |
662 | |
663 c->node->length = c->length; | |
664 | |
665 *cache->size += size; | |
613 | 666 |
614 if (rc == NGX_OK) { | 667 if (rc == NGX_OK) { |
615 c->node->exists = 1; | 668 c->node->exists = 1; |
616 } | 669 } |
617 | 670 |
744 ngx_shmtx_unlock(&cache->shpool->mutex); | 797 ngx_shmtx_unlock(&cache->shpool->mutex); |
745 } | 798 } |
746 | 799 |
747 | 800 |
748 static time_t | 801 static time_t |
749 ngx_http_file_cache_expire(ngx_http_file_cache_t *cache, ngx_uint_t forced) | 802 ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) |
750 { | 803 { |
751 u_char *name, *p; | 804 u_char *name; |
752 size_t len; | 805 size_t len; |
753 time_t now, wait; | 806 time_t wait; |
754 ngx_uint_t tries; | 807 ngx_uint_t tries; |
755 ngx_path_t *path; | 808 ngx_path_t *path; |
756 ngx_queue_t *q; | 809 ngx_queue_t *q; |
757 ngx_http_file_cache_node_t *fcn; | 810 ngx_http_file_cache_node_t *fcn; |
811 | |
812 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, | |
813 "http file cache forced expire"); | |
814 | |
815 path = cache->path; | |
816 len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; | |
817 | |
818 name = ngx_alloc(len + 1, ngx_cycle->log); | |
819 if (name == NULL) { | |
820 return 60; | |
821 } | |
822 | |
823 ngx_memcpy(name, path->name.data, path->name.len); | |
824 | |
825 wait = 60; | |
826 tries = 0; | |
827 | |
828 ngx_shmtx_lock(&cache->shpool->mutex); | |
829 | |
830 for (q = ngx_queue_last(cache->queue); | |
831 q != ngx_queue_sentinel(cache->queue); | |
832 q = ngx_queue_prev(q)) | |
833 { | |
834 fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); | |
835 | |
836 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, | |
837 "http file cache forced expire: #%d %d %02xd%02xd%02xd%02xd", | |
838 fcn->count, fcn->exists, | |
839 fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); | |
840 | |
841 if (fcn->count) { | |
842 | |
843 if (tries++ < 20) { | |
844 continue; | |
845 } | |
846 | |
847 wait = 1; | |
848 | |
849 break; | |
850 } | |
851 | |
852 if (!fcn->exists) { | |
853 | |
854 ngx_queue_remove(q); | |
855 ngx_rbtree_delete(cache->rbtree, &fcn->node); | |
856 ngx_slab_free_locked(cache->shpool, fcn); | |
857 | |
858 break; | |
859 } | |
860 | |
861 ngx_http_file_cache_delete(cache, q, name); | |
862 | |
863 break; | |
864 } | |
865 | |
866 ngx_shmtx_unlock(&cache->shpool->mutex); | |
867 | |
868 ngx_free(name); | |
869 | |
870 return wait; | |
871 } | |
872 | |
873 | |
874 static time_t | |
875 ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) | |
876 { | |
877 u_char *name, *p; | |
878 size_t len; | |
879 time_t now, wait; | |
880 ngx_path_t *path; | |
881 ngx_queue_t *q; | |
882 ngx_http_file_cache_node_t *fcn; | |
758 u_char key[2 * NGX_HTTP_CACHE_KEY_LEN]; | 883 u_char key[2 * NGX_HTTP_CACHE_KEY_LEN]; |
759 | 884 |
760 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, | 885 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, |
761 "http file cache expire"); | 886 "http file cache expire"); |
762 | 887 |
763 path = cache->path; | 888 path = cache->path; |
764 len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; | 889 len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; |
765 | 890 |
891 name = ngx_alloc(len + 1, ngx_cycle->log); | |
892 if (name == NULL) { | |
893 return 60; | |
894 } | |
895 | |
896 ngx_memcpy(name, path->name.data, path->name.len); | |
897 | |
766 now = ngx_time(); | 898 now = ngx_time(); |
767 | 899 |
768 ngx_shmtx_lock(&cache->shpool->mutex); | 900 ngx_shmtx_lock(&cache->shpool->mutex); |
769 | 901 |
770 tries = 0; | |
771 | |
772 for ( ;; ) { | 902 for ( ;; ) { |
773 | 903 |
774 if (ngx_queue_empty(cache->queue)) { | 904 if (ngx_queue_empty(cache->queue)) { |
775 wait = cache->inactive; | 905 wait = 60; |
776 break; | 906 break; |
777 } | 907 } |
778 | 908 |
779 q = ngx_queue_last(cache->queue); | 909 q = ngx_queue_last(cache->queue); |
780 | 910 |
781 fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); | 911 fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); |
782 | 912 |
783 if (!forced) { | 913 wait = fcn->expire - now; |
784 wait = fcn->expire - now; | 914 |
785 | 915 if (wait > 0) { |
786 if (wait > 0) { | 916 wait = wait > 60 ? 60 : wait; |
787 break; | 917 break; |
788 } | |
789 } | 918 } |
790 | 919 |
791 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, | 920 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, |
792 "http file cache expire: #%d %d %02xd%02xd%02xd%02xd", | 921 "http file cache expire: #%d %d %02xd%02xd%02xd%02xd", |
793 fcn->count, fcn->exists, | 922 fcn->count, fcn->exists, |
794 fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); | 923 fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); |
795 | 924 |
796 if (fcn->count) { | 925 if (fcn->count) { |
797 | 926 |
798 if (!forced) { | 927 p = ngx_hex_dump(key, (u_char *) &fcn->node.key, |
799 | 928 sizeof(ngx_rbtree_key_t)); |
800 p = ngx_hex_dump(key, (u_char *) &fcn->node.key, | 929 |
801 sizeof(ngx_rbtree_key_t)); | 930 len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); |
802 (void) ngx_hex_dump(p, fcn->key, | 931 (void) ngx_hex_dump(p, fcn->key, len); |
803 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); | 932 |
804 | 933 /* |
805 /* | 934 * abnormally exited workers may leave locked cache entries, |
806 * abnormally exited workers may leave locked cache entries, | 935 * and although it may be safe to remove them completely, |
807 * and although it may be safe to remove them completely, | 936 * we prefer to remove them from inactive queue and rbtree |
808 * we prefer to remove them from inactive queue and rbtree | 937 * only, and to allow other leaks |
809 * only, and to allow other leaks | 938 */ |
810 */ | 939 |
811 | 940 ngx_queue_remove(q); |
812 ngx_queue_remove(q); | 941 ngx_rbtree_delete(cache->rbtree, &fcn->node); |
813 | 942 |
814 ngx_rbtree_delete(cache->rbtree, &fcn->node); | 943 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, |
815 | |
816 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | |
817 "ignore long locked inactive cache entry %*s, count:%d", | 944 "ignore long locked inactive cache entry %*s, count:%d", |
818 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); | 945 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); |
819 } | 946 |
820 | 947 continue; |
821 if (tries++ < 10) { | 948 } |
822 continue; | |
823 } | |
824 | |
825 wait = 1; | |
826 break; | |
827 } | |
828 | |
829 forced = 0; | |
830 | 949 |
831 if (!fcn->exists) { | 950 if (!fcn->exists) { |
832 | 951 |
833 ngx_queue_remove(q); | 952 ngx_queue_remove(q); |
834 | |
835 ngx_rbtree_delete(cache->rbtree, &fcn->node); | 953 ngx_rbtree_delete(cache->rbtree, &fcn->node); |
836 | |
837 ngx_slab_free_locked(cache->shpool, fcn); | 954 ngx_slab_free_locked(cache->shpool, fcn); |
838 | 955 |
839 continue; | 956 continue; |
840 } | 957 } |
841 | 958 |
842 name = ngx_alloc(len + 1, ngx_cycle->log); | 959 ngx_http_file_cache_delete(cache, q, name); |
843 if (name == NULL) { | |
844 wait = 60; | |
845 break; | |
846 } | |
847 | |
848 ngx_memcpy(name, path->name.data, path->name.len); | |
849 | |
850 p = name + path->name.len + 1 + path->len; | |
851 p = ngx_hex_dump(p, (u_char *) &fcn->node.key, | |
852 sizeof(ngx_rbtree_key_t)); | |
853 p = ngx_hex_dump(p, fcn->key, | |
854 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); | |
855 *p = '\0'; | |
856 | |
857 ngx_queue_remove(q); | |
858 | |
859 ngx_rbtree_delete(cache->rbtree, &fcn->node); | |
860 | |
861 ngx_slab_free_locked(cache->shpool, fcn); | |
862 | |
863 ngx_shmtx_unlock(&cache->shpool->mutex); | |
864 | |
865 ngx_create_hashed_filename(path, name, len); | |
866 | |
867 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, | |
868 "http file cache expire: \"%s\"", name); | |
869 | |
870 if (ngx_delete_file(name) == NGX_FILE_ERROR) { | |
871 ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, | |
872 ngx_delete_file_n " \"%s\" failed", name); | |
873 } | |
874 | |
875 ngx_free(name); | |
876 | |
877 ngx_shmtx_lock(&cache->shpool->mutex); | |
878 } | 960 } |
879 | 961 |
880 ngx_shmtx_unlock(&cache->shpool->mutex); | 962 ngx_shmtx_unlock(&cache->shpool->mutex); |
881 | 963 |
964 ngx_free(name); | |
965 | |
882 return wait; | 966 return wait; |
883 } | 967 } |
884 | 968 |
885 | 969 |
886 time_t | 970 static void |
887 ngx_http_file_cache_cleaner(void *data) | 971 ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q, |
972 u_char *name) | |
973 { | |
974 u_char *p; | |
975 size_t len; | |
976 ngx_path_t *path; | |
977 ngx_http_file_cache_node_t *fcn; | |
978 | |
979 fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); | |
980 | |
981 *cache->size -= (fcn->length + cache->bsize - 1) / cache->bsize; | |
982 | |
983 path = cache->path; | |
984 | |
985 p = name + path->name.len + 1 + path->len; | |
986 | |
987 p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); | |
988 | |
989 len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); | |
990 p = ngx_hex_dump(p, fcn->key, len); | |
991 *p = '\0'; | |
992 | |
993 ngx_queue_remove(q); | |
994 | |
995 ngx_rbtree_delete(cache->rbtree, &fcn->node); | |
996 | |
997 ngx_slab_free_locked(cache->shpool, fcn); | |
998 | |
999 ngx_shmtx_unlock(&cache->shpool->mutex); | |
1000 | |
1001 len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; | |
1002 | |
1003 ngx_create_hashed_filename(path, name, len); | |
1004 | |
1005 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, | |
1006 "http file cache expire: \"%s\"", name); | |
1007 | |
1008 if (ngx_delete_file(name) == NGX_FILE_ERROR) { | |
1009 ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, | |
1010 ngx_delete_file_n " \"%s\" failed", name); | |
1011 } | |
1012 | |
1013 ngx_shmtx_lock(&cache->shpool->mutex); | |
1014 } | |
1015 | |
1016 | |
1017 static time_t | |
1018 ngx_http_file_cache_manager(void *data) | |
888 { | 1019 { |
889 ngx_http_file_cache_t *cache = data; | 1020 ngx_http_file_cache_t *cache = data; |
890 | 1021 |
891 time_t now, next; | 1022 off_t size; |
1023 time_t next; | |
892 ngx_tree_ctx_t tree; | 1024 ngx_tree_ctx_t tree; |
893 | 1025 |
894 now = ngx_time(); | 1026 if (*cache->cold) { |
895 | 1027 |
896 if (now >= cache->next_clean_time | 1028 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, |
897 && now >= cache->created + cache->inactive) | 1029 "http file cache manager update"); |
898 { | |
899 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, | |
900 "clean unused cache files"); | |
901 | 1030 |
902 tree.init_handler = NULL; | 1031 tree.init_handler = NULL; |
903 tree.file_handler = ngx_http_file_cache_clean_file; | 1032 tree.file_handler = ngx_http_file_cache_manage_file; |
904 tree.pre_tree_handler = ngx_http_file_cache_clean_noop; | 1033 tree.pre_tree_handler = ngx_http_file_cache_noop; |
905 tree.post_tree_handler = ngx_http_file_cache_clean_noop; | 1034 tree.post_tree_handler = ngx_http_file_cache_noop; |
906 tree.spec_handler = ngx_http_file_cache_clean_file; | 1035 tree.spec_handler = ngx_http_file_cache_delete_file; |
907 tree.data = cache; | 1036 tree.data = cache; |
908 tree.alloc = 0; | 1037 tree.alloc = 0; |
909 tree.log = ngx_cycle->log; | 1038 tree.log = ngx_cycle->log; |
910 | 1039 |
911 (void) ngx_walk_tree(&tree, &cache->path->name); | 1040 cache->last = ngx_current_msec; |
1041 cache->files = 0; | |
1042 | |
1043 if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) { | |
1044 return 60; | |
1045 } | |
1046 | |
1047 *cache->cold = 0; | |
1048 | |
1049 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, | |
1050 "http file cache: %V %.3fM, bsize: %uz", | |
1051 &cache->path->name, | |
1052 ((double) *cache->size * cache->bsize) / (1024 * 1024), | |
1053 cache->bsize); | |
1054 } | |
1055 | |
1056 next = ngx_http_file_cache_expire(cache); | |
1057 | |
1058 cache->last = ngx_current_msec; | |
1059 cache->files = 0; | |
1060 | |
1061 for ( ;; ) { | |
1062 ngx_shmtx_lock(&cache->shpool->mutex); | |
1063 | |
1064 size = *cache->size; | |
1065 | |
1066 ngx_shmtx_unlock(&cache->shpool->mutex); | |
1067 | |
1068 if (size < cache->max_size) { | |
1069 return next; | |
1070 } | |
1071 | |
1072 next = ngx_http_file_cache_forced_expire(cache); | |
1073 | |
1074 if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) { | |
1075 return next; | |
1076 } | |
1077 } | |
1078 } | |
1079 | |
1080 | |
1081 static ngx_int_t | |
1082 ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache) | |
1083 { | |
1084 ngx_msec_t elapsed; | |
1085 | |
1086 if (cache->files++ > 100) { | |
912 | 1087 |
913 ngx_time_update(0, 0); | 1088 ngx_time_update(0, 0); |
914 | 1089 |
915 next = ngx_next_time(cache->clean_time); | 1090 elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); |
916 | 1091 |
917 if (next == -1) { | 1092 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, |
918 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, | 1093 "http file cache manager time: %M", elapsed); |
919 ngx_next_time_n " failed"); | 1094 |
920 return 60; | 1095 if (elapsed > 200) { |
921 } | 1096 |
922 | 1097 /* |
923 cache->next_clean_time = next; | 1098 * if processing 100 files takes more than 200ms, |
924 } | 1099 * it seems that many operations require disk i/o, |
925 | 1100 * therefore sleep 200ms |
926 next = ngx_http_file_cache_expire(cache, 0); | 1101 */ |
927 | 1102 |
928 now = ngx_time(); | 1103 ngx_msleep(200); |
929 | 1104 |
930 return (now + next < cache->next_clean_time) ? next: | 1105 ngx_time_update(0, 0); |
931 cache->next_clean_time - now; | 1106 } |
1107 | |
1108 cache->last = ngx_current_msec; | |
1109 cache->files = 0; | |
1110 } | |
1111 | |
1112 return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK; | |
932 } | 1113 } |
933 | 1114 |
934 | 1115 |
935 static ngx_int_t | 1116 static ngx_int_t |
936 ngx_http_file_cache_clean_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) | 1117 ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) |
937 { | 1118 { |
938 return NGX_OK; | 1119 return NGX_OK; |
939 } | 1120 } |
940 | 1121 |
941 | 1122 |
942 static ngx_int_t | 1123 static ngx_int_t |
943 ngx_http_file_cache_clean_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) | 1124 ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) |
944 { | 1125 { |
945 u_char *p, key[2 * NGX_HTTP_CACHE_KEY_LEN]; | 1126 ngx_http_file_cache_t *cache; |
946 ngx_int_t n; | 1127 |
947 ngx_uint_t i; | 1128 cache = ctx->data; |
948 ngx_http_file_cache_t *cache; | 1129 |
949 ngx_http_file_cache_node_t *node; | 1130 if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) { |
950 | 1131 (void) ngx_http_file_cache_delete_file(ctx, path); |
951 if (path->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { | 1132 } |
952 goto clean; | 1133 |
953 } | 1134 return ngx_http_file_cache_manager_sleep(cache); |
954 | 1135 } |
955 p = &path->data[path->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; | 1136 |
1137 | |
1138 static ngx_int_t | |
1139 ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name) | |
1140 { | |
1141 u_char *p; | |
1142 ngx_fd_t fd; | |
1143 ngx_int_t n; | |
1144 ngx_uint_t i; | |
1145 ngx_file_info_t fi; | |
1146 ngx_http_cache_t c; | |
1147 ngx_http_file_cache_t *cache; | |
1148 ngx_http_file_cache_header_t h; | |
1149 | |
1150 if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { | |
1151 return NGX_ERROR; | |
1152 } | |
1153 | |
1154 ngx_memzero(&c, sizeof(ngx_http_cache_t)); | |
1155 | |
1156 fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); | |
1157 | |
1158 if (fd == NGX_INVALID_FILE) { | |
1159 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, | |
1160 ngx_open_file_n " \"%s\" failed", name->data); | |
1161 return NGX_ERROR; | |
1162 } | |
1163 | |
1164 c.file.fd = fd; | |
1165 c.file.name = *name; | |
1166 c.file.log = ctx->log; | |
1167 | |
1168 n = ngx_read_file(&c.file, (u_char *) &h, | |
1169 sizeof(ngx_http_file_cache_header_t), 0); | |
1170 if (n == NGX_ERROR) { | |
1171 return NGX_ERROR; | |
1172 } | |
1173 | |
1174 if ((size_t) n < sizeof(ngx_http_file_cache_header_t)) { | |
1175 ngx_log_error(NGX_LOG_CRIT, ctx->log, 0, | |
1176 "cache file \"%s\" is too small", name->data); | |
1177 return NGX_ERROR; | |
1178 } | |
1179 | |
1180 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { | |
1181 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, | |
1182 ngx_fd_info_n " \"%s\" failed", name->data); | |
1183 | |
1184 } else { | |
1185 c.uniq = ngx_file_uniq(&fi); | |
1186 c.valid_sec = h.valid_sec; | |
1187 c.valid_msec = h.valid_msec; | |
1188 c.body_start = h.body_start; | |
1189 c.length = ngx_file_size(&fi); | |
1190 } | |
1191 | |
1192 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
1193 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, | |
1194 ngx_close_file_n " \"%s\" failed", name->data); | |
1195 } | |
1196 | |
1197 if (c.body_start == 0) { | |
1198 return NGX_ERROR; | |
1199 } | |
1200 | |
1201 p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; | |
956 | 1202 |
957 for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { | 1203 for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { |
958 n = ngx_hextoi(p, 2); | 1204 n = ngx_hextoi(p, 2); |
959 | 1205 |
960 if (n == NGX_ERROR) { | 1206 if (n == NGX_ERROR) { |
961 goto clean; | 1207 return NGX_ERROR; |
962 } | 1208 } |
963 | 1209 |
964 p += 2; | 1210 p += 2; |
965 | 1211 |
966 key[i] = (u_char) n; | 1212 c.key[i] = (u_char) n; |
967 } | 1213 } |
968 | 1214 |
969 cache = ctx->data; | 1215 cache = ctx->data; |
970 | 1216 |
1217 return ngx_http_file_cache_add(cache, &c); | |
1218 } | |
1219 | |
1220 | |
1221 static ngx_int_t | |
1222 ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) | |
1223 { | |
1224 ngx_http_file_cache_node_t *fcn; | |
1225 | |
971 ngx_shmtx_lock(&cache->shpool->mutex); | 1226 ngx_shmtx_lock(&cache->shpool->mutex); |
972 | 1227 |
973 node = ngx_http_file_cache_lookup(cache, key); | 1228 fcn = ngx_http_file_cache_lookup(cache, c->key); |
1229 | |
1230 if (fcn == NULL) { | |
1231 | |
1232 fcn = ngx_slab_alloc_locked(cache->shpool, | |
1233 sizeof(ngx_http_file_cache_node_t)); | |
1234 if (fcn == NULL) { | |
1235 ngx_shmtx_unlock(&cache->shpool->mutex); | |
1236 return NGX_ERROR; | |
1237 } | |
1238 | |
1239 ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); | |
1240 | |
1241 ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], | |
1242 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); | |
1243 | |
1244 ngx_rbtree_insert(cache->rbtree, &fcn->node); | |
1245 | |
1246 fcn->uses = 1; | |
1247 fcn->count = 0; | |
1248 fcn->valid_msec = c->valid_msec; | |
1249 fcn->error = 0; | |
1250 fcn->exists = 1; | |
1251 fcn->uniq = c->uniq; | |
1252 fcn->valid_sec = c->valid_sec; | |
1253 fcn->body_start = c->body_start; | |
1254 fcn->length = c->length; | |
1255 | |
1256 *cache->size += (c->length + cache->bsize - 1) / cache->bsize; | |
1257 | |
1258 } else { | |
1259 ngx_queue_remove(&fcn->queue); | |
1260 } | |
1261 | |
1262 fcn->expire = ngx_time() + cache->inactive; | |
1263 | |
1264 ngx_queue_insert_head(cache->queue, &fcn->queue); | |
974 | 1265 |
975 ngx_shmtx_unlock(&cache->shpool->mutex); | 1266 ngx_shmtx_unlock(&cache->shpool->mutex); |
976 | 1267 |
977 if (node) { | 1268 return NGX_OK; |
978 return NGX_OK; | 1269 } |
979 } | 1270 |
980 | 1271 |
981 clean: | 1272 static ngx_int_t |
982 | 1273 ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) |
1274 { | |
983 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | 1275 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, |
984 "http file cache clean: \"%s\"", path->data); | 1276 "http file cache delete: \"%s\"", path->data); |
985 | 1277 |
986 if (ngx_delete_file(path->data) == NGX_FILE_ERROR) { | 1278 if (ngx_delete_file(path->data) == NGX_FILE_ERROR) { |
987 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, | 1279 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, |
988 ngx_delete_file_n " \"%s\" failed", path->data); | 1280 ngx_delete_file_n " \"%s\" failed", path->data); |
989 return NGX_ERROR; | |
990 } | 1281 } |
991 | 1282 |
992 return NGX_OK; | 1283 return NGX_OK; |
993 } | 1284 } |
994 | 1285 |
1016 | 1307 |
1017 | 1308 |
1018 char * | 1309 char * |
1019 ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 1310 ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
1020 { | 1311 { |
1312 off_t max_size; | |
1021 u_char *last, *p; | 1313 u_char *last, *p; |
1022 time_t inactive, clean_time, next; | 1314 time_t inactive; |
1023 ssize_t size; | 1315 ssize_t size; |
1024 ngx_str_t s, name, *value; | 1316 ngx_str_t s, name, *value; |
1025 ngx_uint_t i, n; | 1317 ngx_uint_t i, n; |
1026 ngx_http_file_cache_t *cache; | 1318 ngx_http_file_cache_t *cache; |
1027 | 1319 |
1034 if (cache->path == NULL) { | 1326 if (cache->path == NULL) { |
1035 return NGX_CONF_ERROR; | 1327 return NGX_CONF_ERROR; |
1036 } | 1328 } |
1037 | 1329 |
1038 inactive = 600; | 1330 inactive = 600; |
1039 clean_time = 5 * 60 * 60; | |
1040 | 1331 |
1041 name.len = 0; | 1332 name.len = 0; |
1042 size = 0; | 1333 size = 0; |
1334 max_size = NGX_MAX_OFF_T_VALUE; | |
1043 | 1335 |
1044 value = cf->args->elts; | 1336 value = cf->args->elts; |
1045 | 1337 |
1046 cache->path->name = value[1]; | 1338 cache->path->name = value[1]; |
1047 | 1339 |
1140 } | 1432 } |
1141 | 1433 |
1142 continue; | 1434 continue; |
1143 } | 1435 } |
1144 | 1436 |
1145 if (ngx_strncmp(value[i].data, "clean_time=", 11) == 0) { | 1437 if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) { |
1146 | 1438 |
1147 s.len = value[i].len - 11; | 1439 s.len = value[i].len - 9; |
1148 s.data = value[i].data + 11; | 1440 s.data = value[i].data + 9; |
1149 | 1441 |
1150 clean_time = ngx_parse_time(&s, 1); | 1442 max_size = ngx_parse_offset(&s); |
1151 if (clean_time < 0 || clean_time > 24 * 60 * 60) { | 1443 if (max_size < 0) { |
1152 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 1444 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1153 "invalid clean_time value \"%V\"", &value[i]); | 1445 "invalid max_size value \"%V\"", &value[i]); |
1154 return NGX_CONF_ERROR; | 1446 return NGX_CONF_ERROR; |
1155 } | 1447 } |
1156 | 1448 |
1157 continue; | 1449 continue; |
1158 } | 1450 } |
1167 "\"%V\" must have \"keys_zone\" parameter", | 1459 "\"%V\" must have \"keys_zone\" parameter", |
1168 &cmd->name); | 1460 &cmd->name); |
1169 return NGX_CONF_ERROR; | 1461 return NGX_CONF_ERROR; |
1170 } | 1462 } |
1171 | 1463 |
1172 cache->path->cleaner = ngx_http_file_cache_cleaner; | 1464 cache->path->manager = ngx_http_file_cache_manager; |
1173 cache->path->data = cache; | 1465 cache->path->data = cache; |
1174 | 1466 |
1175 if (ngx_add_path(cf, &cache->path) != NGX_OK) { | 1467 if (ngx_add_path(cf, &cache->path) != NGX_OK) { |
1176 return NGX_CONF_ERROR; | 1468 return NGX_CONF_ERROR; |
1177 } | 1469 } |
1185 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 1477 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1186 "duplicate zone \"%V\"", &name); | 1478 "duplicate zone \"%V\"", &name); |
1187 return NGX_CONF_ERROR; | 1479 return NGX_CONF_ERROR; |
1188 } | 1480 } |
1189 | 1481 |
1190 next = ngx_next_time(clean_time); | |
1191 | |
1192 if (next == -1) { | |
1193 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, | |
1194 ngx_next_time_n " failed"); | |
1195 return NGX_CONF_ERROR; | |
1196 } | |
1197 | 1482 |
1198 cache->shm_zone->init = ngx_http_file_cache_init; | 1483 cache->shm_zone->init = ngx_http_file_cache_init; |
1199 cache->shm_zone->data = cache; | 1484 cache->shm_zone->data = cache; |
1200 | 1485 |
1201 cache->inactive = inactive; | 1486 cache->inactive = inactive; |
1202 cache->clean_time = clean_time; | 1487 cache->max_size = max_size; |
1203 cache->next_clean_time = next; | |
1204 | 1488 |
1205 return NGX_CONF_OK; | 1489 return NGX_CONF_OK; |
1206 } | 1490 } |
1207 | 1491 |
1208 | 1492 |