3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
13 static ngx_int_t
ngx_http_file_cache_exists(ngx_http_request_t
*r
,
14 ngx_http_file_cache_t
*cache
);
15 static ngx_http_file_cache_node_t
*
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
,
18 ngx_rbtree_node_t
*node
, ngx_rbtree_node_t
*sentinel
);
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
,
22 static ngx_int_t
ngx_http_file_cache_clean_noop(ngx_tree_ctx_t
*ctx
,
24 static ngx_int_t
ngx_http_file_cache_clean_file(ngx_tree_ctx_t
*ctx
,
28 static u_char ngx_http_file_cache_key
[] = { LF
, 'K', 'E', 'Y', ':', ' ' };
32 ngx_http_file_cache_init(ngx_shm_zone_t
*shm_zone
, void *data
)
34 ngx_http_file_cache_t
*ocache
= data
;
36 ngx_rbtree_node_t
*sentinel
;
37 ngx_http_file_cache_t
*cache
;
39 cache
= shm_zone
->data
;
42 if (ngx_strcmp(cache
->path
->name
.data
, ocache
->path
->name
.data
) != 0) {
43 ngx_log_error(NGX_LOG_EMERG
, shm_zone
->shm
.log
, 0,
44 "cache \"%V\" uses the \"%V\" cache path "
45 "while previously it used the \"%V\" cache path",
46 &shm_zone
->name
, &cache
->path
->name
,
52 cache
->rbtree
= ocache
->rbtree
;
53 cache
->queue
= ocache
->queue
;
54 cache
->shpool
= ocache
->shpool
;
55 cache
->created
= ocache
->created
;
60 cache
->shpool
= (ngx_slab_pool_t
*) shm_zone
->shm
.addr
;
62 cache
->rbtree
= ngx_slab_alloc(cache
->shpool
, sizeof(ngx_rbtree_t
));
63 if (cache
->rbtree
== NULL
) {
67 sentinel
= ngx_slab_alloc(cache
->shpool
, sizeof(ngx_rbtree_node_t
));
68 if (sentinel
== NULL
) {
72 ngx_rbtree_init(cache
->rbtree
, sentinel
,
73 ngx_http_file_cache_rbtree_insert_value
);
75 cache
->queue
= ngx_slab_alloc(cache
->shpool
, sizeof(ngx_queue_t
));
76 if (cache
->queue
== NULL
) {
80 ngx_queue_init(cache
->queue
);
82 cache
->created
= ngx_time();
89 ngx_http_file_cache_create_key(ngx_http_request_t
*r
)
101 ngx_crc32_init(c
->crc32
);
105 for (i
= 0; i
< c
->keys
.nelts
; i
++) {
106 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
107 "http cache key: \"%V\"", &key
[i
]);
111 ngx_crc32_update(&c
->crc32
, key
[i
].data
, key
[i
].len
);
112 ngx_md5_update(&md5
, key
[i
].data
, key
[i
].len
);
115 c
->header_start
= sizeof(ngx_http_file_cache_header_t
)
116 + sizeof(ngx_http_file_cache_key
) + len
+ 1;
118 ngx_crc32_final(c
->crc32
);
119 ngx_md5_final(c
->key
, &md5
);
124 ngx_http_file_cache_open(ngx_http_request_t
*r
)
130 ngx_uint_t cold
, test
;
133 ngx_pool_cleanup_t
*cln
;
134 ngx_open_file_info_t of
;
135 ngx_http_file_cache_t
*cache
;
136 ngx_http_core_loc_conf_t
*clcf
;
137 ngx_http_file_cache_header_t
*h
;
140 cache
= c
->file_cache
;
142 cln
= ngx_pool_cleanup_add(r
->pool
, 0);
147 rc
= ngx_http_file_cache_exists(r
, cache
);
149 ngx_log_debug3(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
150 "http file cache exists: %i u:%ui e:%d",
151 rc
, c
->uses
, c
->exists
);
153 if (rc
== NGX_ERROR
) {
157 cln
->handler
= ngx_http_file_cache_cleanup
;
160 if (rc
== NGX_AGAIN
) {
166 cold
= (now
- cache
->created
< cache
->inactive
) ? 1 : 0;
175 test
= c
->exists
? 1 : 0;
178 } else { /* rc == NGX_DECLINED */
180 if (c
->min_uses
> 1) {
198 c
->file
.name
.len
= path
->name
.len
+ 1 + path
->len
199 + 2 * NGX_HTTP_CACHE_KEY_LEN
;
201 c
->file
.name
.data
= ngx_pnalloc(r
->pool
, c
->file
.name
.len
+ 1);
202 if (c
->file
.name
.data
== NULL
) {
206 ngx_memcpy(c
->file
.name
.data
, path
->name
.data
, path
->name
.len
);
208 p
= c
->file
.name
.data
+ path
->name
.len
+ 1 + path
->len
;
209 p
= ngx_hex_dump(p
, c
->key
, NGX_HTTP_CACHE_KEY_LEN
);
212 ngx_create_hashed_filename(path
, c
->file
.name
.data
, c
->file
.name
.len
);
214 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, ngx_cycle
->log
, 0,
215 "cache file: \"%s\"", c
->file
.name
.data
);
221 clcf
= ngx_http_get_module_loc_conf(r
, ngx_http_core_module
);
223 ngx_memzero(&of
, sizeof(ngx_open_file_info_t
));
226 of
.valid
= clcf
->open_file_cache_valid
;
227 of
.min_uses
= clcf
->open_file_cache_min_uses
;
228 of
.events
= clcf
->open_file_cache_events
;
229 of
.directio
= NGX_OPEN_FILE_DIRECTIO_OFF
;
231 if (ngx_open_cached_file(clcf
->open_file_cache
, &c
->file
.name
, &of
, r
->pool
)
244 ngx_log_error(NGX_LOG_CRIT
, r
->connection
->log
, of
.err
,
245 ngx_open_file_n
" \"%s\" failed", c
->file
.name
.data
);
250 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
251 "http file cache fd: %d", of
.fd
);
254 c
->file
.log
= r
->connection
->log
;
256 c
->buf
= ngx_create_temp_buf(r
->pool
, c
->body_start
);
257 if (c
->buf
== NULL
) {
261 n
= ngx_read_file(&c
->file
, c
->buf
->pos
, c
->body_start
, 0);
263 if (n
== NGX_ERROR
) {
267 if ((size_t) n
<= c
->header_start
) {
268 ngx_log_error(NGX_LOG_CRIT
, r
->connection
->log
, 0,
269 "cache file \"%s\" is too small", c
->file
.name
.data
);
273 h
= (ngx_http_file_cache_header_t
*) c
->buf
->pos
;
275 if (h
->crc32
!= c
->crc32
|| (size_t) h
->header_start
!= c
->header_start
) {
276 ngx_log_error(NGX_LOG_CRIT
, r
->connection
->log
, 0,
277 "cache file \"%s\" has md5 collision", c
->file
.name
.data
);
283 c
->valid_sec
= h
->valid_sec
;
284 c
->last_modified
= h
->last_modified
;
286 c
->valid_msec
= h
->valid_msec
;
288 c
->body_start
= h
->body_start
;
294 ngx_shmtx_lock(&cache
->shpool
->mutex
);
296 c
->node
->uses
= c
->min_uses
;
297 c
->node
->body_start
= c
->body_start
;
300 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
303 if (c
->valid_sec
< now
) {
305 c
->uses
= c
->min_uses
;
307 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
308 "http file cache expired: %T %T", c
->valid_sec
, now
);
310 return NGX_HTTP_CACHE_STALE
;
313 /* TODO: NGX_HTTP_CACHE_AGED */
320 ngx_http_file_cache_exists(ngx_http_request_t
*r
, ngx_http_file_cache_t
*cache
)
323 ngx_http_file_cache_node_t
*fcn
;
325 ngx_shmtx_lock(&cache
->shpool
->mutex
);
327 fcn
= ngx_http_file_cache_lookup(cache
, r
->cache
->key
);
330 ngx_queue_remove(&fcn
->queue
);
334 if (fcn
->valid_sec
< ngx_time()) {
348 r
->cache
->exists
= fcn
->exists
;
349 r
->cache
->body_start
= fcn
->body_start
;
356 if (fcn
->uses
>= r
->cache
->min_uses
) {
358 r
->cache
->exists
= fcn
->exists
;
359 r
->cache
->body_start
= fcn
->body_start
;
370 fcn
= ngx_slab_alloc_locked(cache
->shpool
,
371 sizeof(ngx_http_file_cache_node_t
));
373 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
375 (void) ngx_http_file_cache_expire(cache
, 1);
377 ngx_shmtx_lock(&cache
->shpool
->mutex
);
379 fcn
= ngx_slab_alloc_locked(cache
->shpool
,
380 sizeof(ngx_http_file_cache_node_t
));
387 ngx_memcpy((u_char
*) &fcn
->node
.key
, r
->cache
->key
,
388 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
));
393 ngx_rbtree_insert(cache
->rbtree
, &fcn
->node
);
410 fcn
->expire
= ngx_time() + cache
->inactive
;
412 ngx_queue_insert_head(cache
->queue
, &fcn
->queue
);
414 r
->cache
->uniq
= fcn
->uniq
;
415 r
->cache
->uses
= fcn
->uses
;
416 r
->cache
->error
= fcn
->error
;
417 r
->cache
->node
= fcn
;
421 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
427 static ngx_http_file_cache_node_t
*
428 ngx_http_file_cache_lookup(ngx_http_file_cache_t
*cache
, u_char
*key
)
431 ngx_rbtree_key_t node_key
;
432 ngx_rbtree_node_t
*node
, *sentinel
;
433 ngx_http_file_cache_node_t
*fcn
;
435 ngx_memcpy((u_char
*) &node_key
, key
, sizeof(ngx_rbtree_key_t
));
437 node
= cache
->rbtree
->root
;
438 sentinel
= cache
->rbtree
->sentinel
;
440 while (node
!= sentinel
) {
442 if (node_key
< node
->key
) {
447 if (node_key
> node
->key
) {
452 /* node_key == node->key */
455 fcn
= (ngx_http_file_cache_node_t
*) node
;
457 rc
= ngx_memcmp(&key
[sizeof(ngx_rbtree_key_t
)], fcn
->key
,
458 NGX_HTTP_CACHE_KEY_LEN
- sizeof(ngx_rbtree_key_t
));
464 node
= (rc
< 0) ? node
->left
: node
->right
;
466 } while (node
!= sentinel
&& node_key
== node
->key
);
478 ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t
*temp
,
479 ngx_rbtree_node_t
*node
, ngx_rbtree_node_t
*sentinel
)
481 ngx_rbtree_node_t
**p
;
482 ngx_http_file_cache_node_t
*cn
, *cnt
;
486 if (node
->key
< temp
->key
) {
490 } else if (node
->key
> temp
->key
) {
494 } else { /* node->key == temp->key */
496 cn
= (ngx_http_file_cache_node_t
*) node
;
497 cnt
= (ngx_http_file_cache_node_t
*) temp
;
499 p
= (ngx_memcmp(cn
->key
, cnt
->key
,
500 NGX_HTTP_CACHE_KEY_LEN
- sizeof(ngx_rbtree_key_t
))
502 ? &temp
->left
: &temp
->right
;
505 if (*p
== sentinel
) {
514 node
->left
= sentinel
;
515 node
->right
= sentinel
;
521 ngx_http_file_cache_set_header(ngx_http_request_t
*r
, u_char
*buf
)
523 ngx_http_file_cache_header_t
*h
= (ngx_http_file_cache_header_t
*) buf
;
530 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
531 "http file cache set header");
535 h
->valid_sec
= c
->valid_sec
;
536 h
->last_modified
= c
->last_modified
;
539 h
->valid_msec
= (u_short
) c
->valid_msec
;
540 h
->header_start
= (u_short
) c
->header_start
;
541 h
->body_start
= (u_short
) c
->body_start
;
543 p
= buf
+ sizeof(ngx_http_file_cache_header_t
);
545 p
= ngx_cpymem(p
, ngx_http_file_cache_key
, sizeof(ngx_http_file_cache_key
));
548 for (i
= 0; i
< c
->keys
.nelts
; i
++) {
549 p
= ngx_copy(p
, key
[i
].data
, key
[i
].len
);
557 ngx_http_file_cache_update(ngx_http_request_t
*r
, ngx_temp_file_t
*tf
)
560 ngx_file_uniq_t uniq
;
563 ngx_ext_rename_file_t ext
;
564 ngx_http_file_cache_t
*cache
;
572 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
573 "http file cache update");
577 cache
= c
->file_cache
;
581 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
582 "http file cache rename: \"%s\" to \"%s\"",
583 tf
->file
.name
.data
, c
->file
.name
.data
);
585 ext
.access
= NGX_FILE_OWNER_ACCESS
;
586 ext
.path_access
= NGX_FILE_OWNER_ACCESS
;
590 ext
.log_rename_error
= 1;
591 ext
.log
= r
->connection
->log
;
593 rc
= ngx_ext_rename_file(&tf
->file
.name
, &c
->file
.name
, &ext
);
597 if (ngx_fd_info(tf
->file
.fd
, &fi
) == NGX_FILE_ERROR
) {
598 ngx_log_error(NGX_LOG_CRIT
, r
->connection
->log
, ngx_errno
,
599 ngx_fd_info_n
" \"%s\" failed", tf
->file
.name
.data
);
604 uniq
= ngx_file_uniq(&fi
);
608 ngx_shmtx_lock(&cache
->shpool
->mutex
);
611 c
->node
->uniq
= uniq
;
612 c
->node
->body_start
= c
->body_start
;
618 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
623 ngx_http_cache_send(ngx_http_request_t
*r
)
632 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
633 "http file cache send: %s", c
->file
.name
.data
);
635 /* we need to allocate all before the header would be sent */
637 b
= ngx_pcalloc(r
->pool
, sizeof(ngx_buf_t
));
639 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
642 b
->file
= ngx_pcalloc(r
->pool
, sizeof(ngx_file_t
));
643 if (b
->file
== NULL
) {
644 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
647 rc
= ngx_http_send_header(r
);
649 if (rc
== NGX_ERROR
|| rc
> NGX_OK
|| r
->header_only
) {
653 b
->file_pos
= c
->body_start
;
654 b
->file_last
= c
->length
;
656 b
->in_file
= (c
->length
- c
->body_start
) ? 1: 0;
657 b
->last_buf
= (r
== r
->main
) ? 1: 0;
658 b
->last_in_chain
= 1;
660 b
->file
->fd
= c
->file
.fd
;
661 b
->file
->name
= c
->file
.name
;
662 b
->file
->log
= r
->connection
->log
;
667 return ngx_http_output_filter(r
, &out
);
672 ngx_http_file_cache_free(ngx_http_request_t
*r
, ngx_temp_file_t
*tf
)
675 ngx_http_file_cache_t
*cache
;
685 cache
= c
->file_cache
;
687 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
688 "http file cache free");
690 ngx_shmtx_lock(&cache
->shpool
->mutex
);
695 c
->node
->valid_sec
= c
->valid_sec
;
696 c
->node
->valid_msec
= c
->valid_msec
;
697 c
->node
->error
= c
->error
;
700 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
703 if (tf
&& tf
->file
.fd
!= NGX_INVALID_FILE
) {
704 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
705 "http file cache incomplete: \"%s\"",
708 if (ngx_delete_file(tf
->file
.name
.data
) == NGX_FILE_ERROR
) {
709 ngx_log_error(NGX_LOG_CRIT
, r
->connection
->log
, ngx_errno
,
710 ngx_delete_file_n
" \"%s\" failed",
719 ngx_http_file_cache_cleanup(void *data
)
721 ngx_http_cache_t
*c
= data
;
723 ngx_http_file_cache_t
*cache
;
731 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, c
->file
.log
, 0,
732 "http file cache cleanup");
738 cache
= c
->file_cache
;
740 ngx_shmtx_lock(&cache
->shpool
->mutex
);
744 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
749 ngx_http_file_cache_expire(ngx_http_file_cache_t
*cache
, ngx_uint_t forced
)
757 ngx_http_file_cache_node_t
*fcn
;
758 u_char key
[2 * NGX_HTTP_CACHE_KEY_LEN
];
760 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, ngx_cycle
->log
, 0,
761 "http file cache expire");
764 len
= path
->name
.len
+ 1 + path
->len
+ 2 * NGX_HTTP_CACHE_KEY_LEN
;
768 ngx_shmtx_lock(&cache
->shpool
->mutex
);
774 if (ngx_queue_empty(cache
->queue
)) {
775 wait
= cache
->inactive
;
779 q
= ngx_queue_last(cache
->queue
);
781 fcn
= ngx_queue_data(q
, ngx_http_file_cache_node_t
, queue
);
784 wait
= fcn
->expire
- now
;
791 ngx_log_debug6(NGX_LOG_DEBUG_HTTP
, ngx_cycle
->log
, 0,
792 "http file cache expire: #%d %d %02xd%02xd%02xd%02xd",
793 fcn
->count
, fcn
->exists
,
794 fcn
->key
[0], fcn
->key
[1], fcn
->key
[2], fcn
->key
[3]);
800 p
= ngx_hex_dump(key
, (u_char
*) &fcn
->node
.key
,
801 sizeof(ngx_rbtree_key_t
));
802 (void) ngx_hex_dump(p
, fcn
->key
,
803 NGX_HTTP_CACHE_KEY_LEN
- sizeof(ngx_rbtree_key_t
));
806 * abnormally exited workers may leave locked cache entries,
807 * and although it may be safe to remove them completely,
808 * we prefer to remove them from inactive queue and rbtree
809 * only, and to allow other leaks
814 ngx_rbtree_delete(cache
->rbtree
, &fcn
->node
);
816 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0,
817 "ignore long locked inactive cache entry %*s, count:%d",
818 2 * NGX_HTTP_CACHE_KEY_LEN
, key
, fcn
->count
);
835 ngx_rbtree_delete(cache
->rbtree
, &fcn
->node
);
837 ngx_slab_free_locked(cache
->shpool
, fcn
);
842 name
= ngx_alloc(len
+ 1, ngx_cycle
->log
);
848 ngx_memcpy(name
, path
->name
.data
, path
->name
.len
);
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
));
859 ngx_rbtree_delete(cache
->rbtree
, &fcn
->node
);
861 ngx_slab_free_locked(cache
->shpool
, fcn
);
863 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
865 ngx_create_hashed_filename(path
, name
, len
);
867 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, ngx_cycle
->log
, 0,
868 "http file cache expire: \"%s\"", name
);
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
);
877 ngx_shmtx_lock(&cache
->shpool
->mutex
);
880 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
887 ngx_http_file_cache_cleaner(void *data
)
889 ngx_http_file_cache_t
*cache
= data
;
896 if (now
>= cache
->next_clean_time
897 && now
>= cache
->created
+ cache
->inactive
)
899 ngx_log_error(NGX_LOG_NOTICE
, ngx_cycle
->log
, 0,
900 "clean unused cache files");
902 tree
.init_handler
= NULL
;
903 tree
.file_handler
= ngx_http_file_cache_clean_file
;
904 tree
.pre_tree_handler
= ngx_http_file_cache_clean_noop
;
905 tree
.post_tree_handler
= ngx_http_file_cache_clean_noop
;
906 tree
.spec_handler
= ngx_http_file_cache_clean_file
;
909 tree
.log
= ngx_cycle
->log
;
911 (void) ngx_walk_tree(&tree
, &cache
->path
->name
);
913 ngx_time_update(0, 0);
915 next
= ngx_next_time(cache
->clean_time
);
918 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, ngx_errno
,
919 ngx_next_time_n
" failed");
923 cache
->next_clean_time
= next
;
926 next
= ngx_http_file_cache_expire(cache
, 0);
930 return (now
+ next
< cache
->next_clean_time
) ? next
:
931 cache
->next_clean_time
- now
;
936 ngx_http_file_cache_clean_noop(ngx_tree_ctx_t
*ctx
, ngx_str_t
*path
)
943 ngx_http_file_cache_clean_file(ngx_tree_ctx_t
*ctx
, ngx_str_t
*path
)
945 u_char
*p
, key
[2 * NGX_HTTP_CACHE_KEY_LEN
];
948 ngx_http_file_cache_t
*cache
;
949 ngx_http_file_cache_node_t
*node
;
951 if (path
->len
< 2 * NGX_HTTP_CACHE_KEY_LEN
) {
955 p
= &path
->data
[path
->len
- 2 * NGX_HTTP_CACHE_KEY_LEN
];
957 for (i
= 0; i
< NGX_HTTP_CACHE_KEY_LEN
; i
++) {
958 n
= ngx_hextoi(p
, 2);
960 if (n
== NGX_ERROR
) {
971 ngx_shmtx_lock(&cache
->shpool
->mutex
);
973 node
= ngx_http_file_cache_lookup(cache
, key
);
975 ngx_shmtx_unlock(&cache
->shpool
->mutex
);
983 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, ctx
->log
, 0,
984 "http file cache clean: \"%s\"", path
->data
);
986 if (ngx_delete_file(path
->data
) == NGX_FILE_ERROR
) {
987 ngx_log_error(NGX_LOG_CRIT
, ctx
->log
, ngx_errno
,
988 ngx_delete_file_n
" \"%s\" failed", path
->data
);
997 ngx_http_file_cache_valid(ngx_array_t
*cache_valid
, ngx_uint_t status
)
1000 ngx_http_cache_valid_t
*valid
;
1002 valid
= cache_valid
->elts
;
1003 for (i
= 0; i
< cache_valid
->nelts
; i
++) {
1005 if (valid
[i
].status
== 0) {
1006 return valid
[i
].valid
;
1009 if (valid
[i
].status
== status
) {
1010 return valid
[i
].valid
;
1019 ngx_http_file_cache_set_slot(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
1022 time_t inactive
, clean_time
, next
;
1024 ngx_str_t s
, name
, *value
;
1026 ngx_http_file_cache_t
*cache
;
1028 cache
= ngx_pcalloc(cf
->pool
, sizeof(ngx_http_file_cache_t
));
1029 if (cache
== NULL
) {
1030 return NGX_CONF_ERROR
;
1033 cache
->path
= ngx_pcalloc(cf
->pool
, sizeof(ngx_path_t
));
1034 if (cache
->path
== NULL
) {
1035 return NGX_CONF_ERROR
;
1039 clean_time
= 5 * 60 * 60;
1044 value
= cf
->args
->elts
;
1046 cache
->path
->name
= value
[1];
1048 if (cache
->path
->name
.data
[cache
->path
->name
.len
- 1] == '/') {
1049 cache
->path
->name
.len
--;
1052 if (ngx_conf_full_name(cf
->cycle
, &cache
->path
->name
, 0) != NGX_OK
) {
1053 return NGX_CONF_ERROR
;
1056 for (i
= 2; i
< cf
->args
->nelts
; i
++) {
1058 if (ngx_strncmp(value
[i
].data
, "levels=", 7) == 0) {
1061 p
= value
[i
].data
+ 7;
1062 last
= value
[i
].data
+ value
[i
].len
;
1066 if (*p
> '0' && *p
< '6') {
1068 cache
->path
->level
[n
] = *p
++ - '0';
1069 cache
->path
->len
+= cache
->path
->level
[n
] + 1;
1078 goto invalid_levels
;
1081 if (cache
->path
->level
[n
] == 0) {
1082 goto invalid_levels
;
1091 goto invalid_levels
;
1094 if (cache
->path
->len
< 10 + 3) {
1100 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1101 "invalid \"levels\" \"%V\"", &value
[i
]);
1102 return NGX_CONF_ERROR
;
1105 if (ngx_strncmp(value
[i
].data
, "keys_zone=", 10) == 0) {
1107 name
.data
= value
[i
].data
+ 10;
1109 p
= (u_char
*) ngx_strchr(name
.data
, ':');
1112 name
.len
= p
- name
.data
;
1116 s
.len
= value
[i
].data
+ value
[i
].len
- p
;
1119 size
= ngx_parse_size(&s
);
1125 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1126 "invalid keys zone size \"%V\"", &value
[i
]);
1127 return NGX_CONF_ERROR
;
1130 if (ngx_strncmp(value
[i
].data
, "inactive=", 9) == 0) {
1132 s
.len
= value
[i
].len
- 9;
1133 s
.data
= value
[i
].data
+ 9;
1135 inactive
= ngx_parse_time(&s
, 1);
1137 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1138 "invalid inactive value \"%V\"", &value
[i
]);
1139 return NGX_CONF_ERROR
;
1145 if (ngx_strncmp(value
[i
].data
, "clean_time=", 11) == 0) {
1147 s
.len
= value
[i
].len
- 11;
1148 s
.data
= value
[i
].data
+ 11;
1150 clean_time
= ngx_parse_time(&s
, 1);
1151 if (clean_time
< 0 || clean_time
> 24 * 60 * 60) {
1152 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1153 "invalid clean_time value \"%V\"", &value
[i
]);
1154 return NGX_CONF_ERROR
;
1160 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1161 "invalid parameter \"%V\"", &value
[i
]);
1162 return NGX_CONF_ERROR
;
1165 if (name
.len
== 0 || size
== 0) {
1166 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1167 "\"%V\" must have \"keys_zone\" parameter",
1169 return NGX_CONF_ERROR
;
1172 cache
->path
->cleaner
= ngx_http_file_cache_cleaner
;
1173 cache
->path
->data
= cache
;
1175 if (ngx_add_path(cf
, &cache
->path
) != NGX_OK
) {
1176 return NGX_CONF_ERROR
;
1179 cache
->shm_zone
= ngx_shared_memory_add(cf
, &name
, size
, cmd
->post
);
1180 if (cache
->shm_zone
== NULL
) {
1181 return NGX_CONF_ERROR
;
1184 if (cache
->shm_zone
->data
) {
1185 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1186 "duplicate zone \"%V\"", &name
);
1187 return NGX_CONF_ERROR
;
1190 next
= ngx_next_time(clean_time
);
1193 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, ngx_errno
,
1194 ngx_next_time_n
" failed");
1195 return NGX_CONF_ERROR
;
1198 cache
->shm_zone
->init
= ngx_http_file_cache_init
;
1199 cache
->shm_zone
->data
= cache
;
1201 cache
->inactive
= inactive
;
1202 cache
->clean_time
= clean_time
;
1203 cache
->next_clean_time
= next
;
1210 ngx_http_file_cache_valid_set_slot(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
1217 ngx_uint_t i
, n
, status
;
1219 ngx_http_cache_valid_t
*v
;
1220 static ngx_uint_t statuses
[] = { 200, 301, 302 };
1222 a
= (ngx_array_t
**) (p
+ cmd
->offset
);
1224 if (*a
== NGX_CONF_UNSET_PTR
) {
1225 *a
= ngx_array_create(cf
->pool
, 1, sizeof(ngx_http_cache_valid_t
));
1227 return NGX_CONF_ERROR
;
1231 value
= cf
->args
->elts
;
1232 n
= cf
->args
->nelts
- 1;
1234 valid
= ngx_parse_time(&value
[n
], 1);
1236 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1237 "invalid time value \"%V\"", &value
[n
]);
1238 return NGX_CONF_ERROR
;
1243 for (i
= 0; i
< 3; i
++) {
1244 v
= ngx_array_push(*a
);
1246 return NGX_CONF_ERROR
;
1249 v
->status
= statuses
[i
];
1256 for (i
= 1; i
< n
; i
++) {
1258 if (ngx_strcmp(value
[i
].data
, "any") == 0) {
1264 status
= ngx_atoi(value
[i
].data
, value
[i
].len
);
1266 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
1267 "invalid status \"%V\"", &value
[i
]);
1268 return NGX_CONF_ERROR
;
1272 v
= ngx_array_push(*a
);
1274 return NGX_CONF_ERROR
;