1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev#include <ngx_md5.h>
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyev
14e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_lock(ngx_http_request_t *r,
15e18a033bSKonstantin Ananyev    ngx_http_cache_t *c);
16e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev);
17e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_lock_wait(ngx_http_request_t *r,
18e18a033bSKonstantin Ananyev    ngx_http_cache_t *c);
19e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
20e18a033bSKonstantin Ananyev    ngx_http_cache_t *c);
21e18a033bSKonstantin Ananyevstatic ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r,
22e18a033bSKonstantin Ananyev    ngx_http_cache_t *c);
23e18a033bSKonstantin Ananyev#if (NGX_HAVE_FILE_AIO)
24e18a033bSKonstantin Ananyevstatic void ngx_http_cache_aio_event_handler(ngx_event_t *ev);
25e18a033bSKonstantin Ananyev#endif
26e18a033bSKonstantin Ananyev#if (NGX_THREADS)
27e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_cache_thread_handler(ngx_thread_task_t *task,
28e18a033bSKonstantin Ananyev    ngx_file_t *file);
29e18a033bSKonstantin Ananyevstatic void ngx_http_cache_thread_event_handler(ngx_event_t *ev);
30e18a033bSKonstantin Ananyev#endif
31e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
32e18a033bSKonstantin Ananyev    ngx_http_cache_t *c);
33e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_name(ngx_http_request_t *r,
34e18a033bSKonstantin Ananyev    ngx_path_t *path);
35e18a033bSKonstantin Ananyevstatic ngx_http_file_cache_node_t *
36e18a033bSKonstantin Ananyev    ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
37e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
38e18a033bSKonstantin Ananyev    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
39e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary,
40e18a033bSKonstantin Ananyev    size_t len, u_char *hash);
41e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_vary_header(ngx_http_request_t *r,
42e18a033bSKonstantin Ananyev    ngx_md5_t *md5, ngx_str_t *name);
43e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_reopen(ngx_http_request_t *r,
44e18a033bSKonstantin Ananyev    ngx_http_cache_t *c);
45e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_update_variant(ngx_http_request_t *r,
46e18a033bSKonstantin Ananyev    ngx_http_cache_t *c);
47e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_cleanup(void *data);
48e18a033bSKonstantin Ananyevstatic time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
49e18a033bSKonstantin Ananyevstatic time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
50e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache,
51e18a033bSKonstantin Ananyev    ngx_queue_t *q, u_char *name);
52e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache);
53e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx,
54e18a033bSKonstantin Ananyev    ngx_str_t *path);
55e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx,
56e18a033bSKonstantin Ananyev    ngx_str_t *path);
57e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_manage_directory(ngx_tree_ctx_t *ctx,
58e18a033bSKonstantin Ananyev    ngx_str_t *path);
59e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx,
60e18a033bSKonstantin Ananyev    ngx_str_t *path);
61e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache,
62e18a033bSKonstantin Ananyev    ngx_http_cache_t *c);
63e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx,
64e18a033bSKonstantin Ananyev    ngx_str_t *path);
65e18a033bSKonstantin Ananyevstatic void ngx_http_file_cache_set_watermark(ngx_http_file_cache_t *cache);
66e18a033bSKonstantin Ananyev
67e18a033bSKonstantin Ananyev
68e18a033bSKonstantin Ananyevngx_str_t  ngx_http_cache_status[] = {
69e18a033bSKonstantin Ananyev    ngx_string("MISS"),
70e18a033bSKonstantin Ananyev    ngx_string("BYPASS"),
71e18a033bSKonstantin Ananyev    ngx_string("EXPIRED"),
72e18a033bSKonstantin Ananyev    ngx_string("STALE"),
73e18a033bSKonstantin Ananyev    ngx_string("UPDATING"),
74e18a033bSKonstantin Ananyev    ngx_string("REVALIDATED"),
75e18a033bSKonstantin Ananyev    ngx_string("HIT")
76e18a033bSKonstantin Ananyev};
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyev
79e18a033bSKonstantin Ananyevstatic u_char  ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' };
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyev
82e18a033bSKonstantin Ananyevstatic ngx_int_t
83e18a033bSKonstantin Ananyevngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data)
84e18a033bSKonstantin Ananyev{
85e18a033bSKonstantin Ananyev    ngx_http_file_cache_t  *ocache = data;
86e18a033bSKonstantin Ananyev
87e18a033bSKonstantin Ananyev    size_t                  len;
88e18a033bSKonstantin Ananyev    ngx_uint_t              n;
89e18a033bSKonstantin Ananyev    ngx_http_file_cache_t  *cache;
90e18a033bSKonstantin Ananyev
91e18a033bSKonstantin Ananyev    cache = shm_zone->data;
92e18a033bSKonstantin Ananyev
93e18a033bSKonstantin Ananyev    if (ocache) {
94e18a033bSKonstantin Ananyev        if (ngx_strcmp(cache->path->name.data, ocache->path->name.data) != 0) {
95e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
96e18a033bSKonstantin Ananyev                          "cache \"%V\" uses the \"%V\" cache path "
97e18a033bSKonstantin Ananyev                          "while previously it used the \"%V\" cache path",
98e18a033bSKonstantin Ananyev                          &shm_zone->shm.name, &cache->path->name,
99e18a033bSKonstantin Ananyev                          &ocache->path->name);
100e18a033bSKonstantin Ananyev
101e18a033bSKonstantin Ananyev            return NGX_ERROR;
102e18a033bSKonstantin Ananyev        }
103e18a033bSKonstantin Ananyev
104e18a033bSKonstantin Ananyev        for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) {
105e18a033bSKonstantin Ananyev            if (cache->path->level[n] != ocache->path->level[n]) {
106e18a033bSKonstantin Ananyev                ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
107e18a033bSKonstantin Ananyev                              "cache \"%V\" had previously different levels",
108e18a033bSKonstantin Ananyev                              &shm_zone->shm.name);
109e18a033bSKonstantin Ananyev                return NGX_ERROR;
110e18a033bSKonstantin Ananyev            }
111e18a033bSKonstantin Ananyev        }
112e18a033bSKonstantin Ananyev
113e18a033bSKonstantin Ananyev        cache->sh = ocache->sh;
114e18a033bSKonstantin Ananyev
115e18a033bSKonstantin Ananyev        cache->shpool = ocache->shpool;
116e18a033bSKonstantin Ananyev        cache->bsize = ocache->bsize;
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyev        cache->max_size /= cache->bsize;
119e18a033bSKonstantin Ananyev
120e18a033bSKonstantin Ananyev        if (!cache->sh->cold || cache->sh->loading) {
121e18a033bSKonstantin Ananyev            cache->path->loader = NULL;
122e18a033bSKonstantin Ananyev        }
123e18a033bSKonstantin Ananyev
124e18a033bSKonstantin Ananyev        return NGX_OK;
125e18a033bSKonstantin Ananyev    }
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyev    cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
128e18a033bSKonstantin Ananyev
129e18a033bSKonstantin Ananyev    if (shm_zone->shm.exists) {
130e18a033bSKonstantin Ananyev        cache->sh = cache->shpool->data;
131e18a033bSKonstantin Ananyev        cache->bsize = ngx_fs_bsize(cache->path->name.data);
132e18a033bSKonstantin Ananyev
133e18a033bSKonstantin Ananyev        return NGX_OK;
134e18a033bSKonstantin Ananyev    }
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyev    cache->sh = ngx_slab_alloc(cache->shpool, sizeof(ngx_http_file_cache_sh_t));
137e18a033bSKonstantin Ananyev    if (cache->sh == NULL) {
138e18a033bSKonstantin Ananyev        return NGX_ERROR;
139e18a033bSKonstantin Ananyev    }
140e18a033bSKonstantin Ananyev
141e18a033bSKonstantin Ananyev    cache->shpool->data = cache->sh;
142e18a033bSKonstantin Ananyev
143e18a033bSKonstantin Ananyev    ngx_rbtree_init(&cache->sh->rbtree, &cache->sh->sentinel,
144e18a033bSKonstantin Ananyev                    ngx_http_file_cache_rbtree_insert_value);
145e18a033bSKonstantin Ananyev
146e18a033bSKonstantin Ananyev    ngx_queue_init(&cache->sh->queue);
147e18a033bSKonstantin Ananyev
148e18a033bSKonstantin Ananyev    cache->sh->cold = 1;
149e18a033bSKonstantin Ananyev    cache->sh->loading = 0;
150e18a033bSKonstantin Ananyev    cache->sh->size = 0;
151e18a033bSKonstantin Ananyev    cache->sh->count = 0;
152e18a033bSKonstantin Ananyev    cache->sh->watermark = (ngx_uint_t) -1;
153e18a033bSKonstantin Ananyev
154e18a033bSKonstantin Ananyev    cache->bsize = ngx_fs_bsize(cache->path->name.data);
155e18a033bSKonstantin Ananyev
156e18a033bSKonstantin Ananyev    cache->max_size /= cache->bsize;
157e18a033bSKonstantin Ananyev
158e18a033bSKonstantin Ananyev    len = sizeof(" in cache keys zone \"\"") + shm_zone->shm.name.len;
159e18a033bSKonstantin Ananyev
160e18a033bSKonstantin Ananyev    cache->shpool->log_ctx = ngx_slab_alloc(cache->shpool, len);
161e18a033bSKonstantin Ananyev    if (cache->shpool->log_ctx == NULL) {
162e18a033bSKonstantin Ananyev        return NGX_ERROR;
163e18a033bSKonstantin Ananyev    }
164e18a033bSKonstantin Ananyev
165e18a033bSKonstantin Ananyev    ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z",
166e18a033bSKonstantin Ananyev                &shm_zone->shm.name);
167e18a033bSKonstantin Ananyev
168e18a033bSKonstantin Ananyev    cache->shpool->log_nomem = 0;
169e18a033bSKonstantin Ananyev
170e18a033bSKonstantin Ananyev    return NGX_OK;
171e18a033bSKonstantin Ananyev}
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyevngx_int_t
175e18a033bSKonstantin Ananyevngx_http_file_cache_new(ngx_http_request_t *r)
176e18a033bSKonstantin Ananyev{
177e18a033bSKonstantin Ananyev    ngx_http_cache_t  *c;
178e18a033bSKonstantin Ananyev
179e18a033bSKonstantin Ananyev    c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
180e18a033bSKonstantin Ananyev    if (c == NULL) {
181e18a033bSKonstantin Ananyev        return NGX_ERROR;
182e18a033bSKonstantin Ananyev    }
183e18a033bSKonstantin Ananyev
184e18a033bSKonstantin Ananyev    if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
185e18a033bSKonstantin Ananyev        return NGX_ERROR;
186e18a033bSKonstantin Ananyev    }
187e18a033bSKonstantin Ananyev
188e18a033bSKonstantin Ananyev    r->cache = c;
189e18a033bSKonstantin Ananyev    c->file.log = r->connection->log;
190e18a033bSKonstantin Ananyev    c->file.fd = NGX_INVALID_FILE;
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyev    return NGX_OK;
193e18a033bSKonstantin Ananyev}
194e18a033bSKonstantin Ananyev
195e18a033bSKonstantin Ananyev
196e18a033bSKonstantin Ananyevngx_int_t
197e18a033bSKonstantin Ananyevngx_http_file_cache_create(ngx_http_request_t *r)
198e18a033bSKonstantin Ananyev{
199e18a033bSKonstantin Ananyev    ngx_http_cache_t       *c;
200e18a033bSKonstantin Ananyev    ngx_pool_cleanup_t     *cln;
201e18a033bSKonstantin Ananyev    ngx_http_file_cache_t  *cache;
202e18a033bSKonstantin Ananyev
203e18a033bSKonstantin Ananyev    c = r->cache;
204e18a033bSKonstantin Ananyev    cache = c->file_cache;
205e18a033bSKonstantin Ananyev
206e18a033bSKonstantin Ananyev    cln = ngx_pool_cleanup_add(r->pool, 0);
207e18a033bSKonstantin Ananyev    if (cln == NULL) {
208e18a033bSKonstantin Ananyev        return NGX_ERROR;
209e18a033bSKonstantin Ananyev    }
210e18a033bSKonstantin Ananyev
211e18a033bSKonstantin Ananyev    cln->handler = ngx_http_file_cache_cleanup;
212e18a033bSKonstantin Ananyev    cln->data = c;
213e18a033bSKonstantin Ananyev
214e18a033bSKonstantin Ananyev    if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) {
215e18a033bSKonstantin Ananyev        return NGX_ERROR;
216e18a033bSKonstantin Ananyev    }
217e18a033bSKonstantin Ananyev
218e18a033bSKonstantin Ananyev    if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
219e18a033bSKonstantin Ananyev        return NGX_ERROR;
220e18a033bSKonstantin Ananyev    }
221e18a033bSKonstantin Ananyev
222e18a033bSKonstantin Ananyev    return NGX_OK;
223e18a033bSKonstantin Ananyev}
224e18a033bSKonstantin Ananyev
225e18a033bSKonstantin Ananyev
226e18a033bSKonstantin Ananyevvoid
227e18a033bSKonstantin Ananyevngx_http_file_cache_create_key(ngx_http_request_t *r)
228e18a033bSKonstantin Ananyev{
229e18a033bSKonstantin Ananyev    size_t             len;
230e18a033bSKonstantin Ananyev    ngx_str_t         *key;
231e18a033bSKonstantin Ananyev    ngx_uint_t         i;
232e18a033bSKonstantin Ananyev    ngx_md5_t          md5;
233e18a033bSKonstantin Ananyev    ngx_http_cache_t  *c;
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev    c = r->cache;
236e18a033bSKonstantin Ananyev
237e18a033bSKonstantin Ananyev    len = 0;
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyev    ngx_crc32_init(c->crc32);
240e18a033bSKonstantin Ananyev    ngx_md5_init(&md5);
241e18a033bSKonstantin Ananyev
242e18a033bSKonstantin Ananyev    key = c->keys.elts;
243e18a033bSKonstantin Ananyev    for (i = 0; i < c->keys.nelts; i++) {
244e18a033bSKonstantin Ananyev        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
245e18a033bSKonstantin Ananyev                       "http cache key: \"%V\"", &key[i]);
246e18a033bSKonstantin Ananyev
247e18a033bSKonstantin Ananyev        len += key[i].len;
248e18a033bSKonstantin Ananyev
249e18a033bSKonstantin Ananyev        ngx_crc32_update(&c->crc32, key[i].data, key[i].len);
250e18a033bSKonstantin Ananyev        ngx_md5_update(&md5, key[i].data, key[i].len);
251e18a033bSKonstantin Ananyev    }
252e18a033bSKonstantin Ananyev
253e18a033bSKonstantin Ananyev    c->header_start = sizeof(ngx_http_file_cache_header_t)
254e18a033bSKonstantin Ananyev                      + sizeof(ngx_http_file_cache_key) + len + 1;
255e18a033bSKonstantin Ananyev
256e18a033bSKonstantin Ananyev    ngx_crc32_final(c->crc32);
257e18a033bSKonstantin Ananyev    ngx_md5_final(c->key, &md5);
258e18a033bSKonstantin Ananyev
259e18a033bSKonstantin Ananyev    ngx_memcpy(c->main, c->key, NGX_HTTP_CACHE_KEY_LEN);
260e18a033bSKonstantin Ananyev}
261e18a033bSKonstantin Ananyev
262e18a033bSKonstantin Ananyev
263e18a033bSKonstantin Ananyevngx_int_t
264e18a033bSKonstantin Ananyevngx_http_file_cache_open(ngx_http_request_t *r)
265e18a033bSKonstantin Ananyev{
266e18a033bSKonstantin Ananyev    ngx_int_t                  rc, rv;
267e18a033bSKonstantin Ananyev    ngx_uint_t                 test;
268e18a033bSKonstantin Ananyev    ngx_http_cache_t          *c;
269e18a033bSKonstantin Ananyev    ngx_pool_cleanup_t        *cln;
270e18a033bSKonstantin Ananyev    ngx_open_file_info_t       of;
271e18a033bSKonstantin Ananyev    ngx_http_file_cache_t     *cache;
272e18a033bSKonstantin Ananyev    ngx_http_core_loc_conf_t  *clcf;
273e18a033bSKonstantin Ananyev
274e18a033bSKonstantin Ananyev    c = r->cache;
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    if (c->waiting) {
277e18a033bSKonstantin Ananyev        return NGX_AGAIN;
278e18a033bSKonstantin Ananyev    }
279e18a033bSKonstantin Ananyev
280e18a033bSKonstantin Ananyev    if (c->reading) {
281e18a033bSKonstantin Ananyev        return ngx_http_file_cache_read(r, c);
282e18a033bSKonstantin Ananyev    }
283e18a033bSKonstantin Ananyev
284e18a033bSKonstantin Ananyev    cache = c->file_cache;
285e18a033bSKonstantin Ananyev
286e18a033bSKonstantin Ananyev    if (c->node == NULL) {
287e18a033bSKonstantin Ananyev        cln = ngx_pool_cleanup_add(r->pool, 0);
288e18a033bSKonstantin Ananyev        if (cln == NULL) {
289e18a033bSKonstantin Ananyev            return NGX_ERROR;
290e18a033bSKonstantin Ananyev        }
291e18a033bSKonstantin Ananyev
292e18a033bSKonstantin Ananyev        cln->handler = ngx_http_file_cache_cleanup;
293e18a033bSKonstantin Ananyev        cln->data = c;
294e18a033bSKonstantin Ananyev    }
295e18a033bSKonstantin Ananyev
296e18a033bSKonstantin Ananyev    rc = ngx_http_file_cache_exists(cache, c);
297e18a033bSKonstantin Ananyev
298e18a033bSKonstantin Ananyev    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
299e18a033bSKonstantin Ananyev                   "http file cache exists: %i e:%d", rc, c->exists);
300e18a033bSKonstantin Ananyev
301e18a033bSKonstantin Ananyev    if (rc == NGX_ERROR) {
302e18a033bSKonstantin Ananyev        return rc;
303e18a033bSKonstantin Ananyev    }
304e18a033bSKonstantin Ananyev
305e18a033bSKonstantin Ananyev    if (rc == NGX_AGAIN) {
306e18a033bSKonstantin Ananyev        return NGX_HTTP_CACHE_SCARCE;
307e18a033bSKonstantin Ananyev    }
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev    if (rc == NGX_OK) {
310e18a033bSKonstantin Ananyev
311e18a033bSKonstantin Ananyev        if (c->error) {
312e18a033bSKonstantin Ananyev            return c->error;
313e18a033bSKonstantin Ananyev        }
314e18a033bSKonstantin Ananyev
315e18a033bSKonstantin Ananyev        c->temp_file = 1;
316e18a033bSKonstantin Ananyev        test = c->exists ? 1 : 0;
317e18a033bSKonstantin Ananyev        rv = NGX_DECLINED;
318e18a033bSKonstantin Ananyev
319e18a033bSKonstantin Ananyev    } else { /* rc == NGX_DECLINED */
320e18a033bSKonstantin Ananyev
321e18a033bSKonstantin Ananyev        test = cache->sh->cold ? 1 : 0;
322e18a033bSKonstantin Ananyev
323e18a033bSKonstantin Ananyev        if (c->min_uses > 1) {
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev            if (!test) {
326e18a033bSKonstantin Ananyev                return NGX_HTTP_CACHE_SCARCE;
327e18a033bSKonstantin Ananyev            }
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev            rv = NGX_HTTP_CACHE_SCARCE;
330e18a033bSKonstantin Ananyev
331e18a033bSKonstantin Ananyev        } else {
332e18a033bSKonstantin Ananyev            c->temp_file = 1;
333e18a033bSKonstantin Ananyev            rv = NGX_DECLINED;
334e18a033bSKonstantin Ananyev        }
335e18a033bSKonstantin Ananyev    }
336e18a033bSKonstantin Ananyev
337e18a033bSKonstantin Ananyev    if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
338e18a033bSKonstantin Ananyev        return NGX_ERROR;
339e18a033bSKonstantin Ananyev    }
340e18a033bSKonstantin Ananyev
341e18a033bSKonstantin Ananyev    if (!test) {
342e18a033bSKonstantin Ananyev        goto done;
343e18a033bSKonstantin Ananyev    }
344e18a033bSKonstantin Ananyev
345e18a033bSKonstantin Ananyev    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyev    ngx_memzero(&of, sizeof(ngx_open_file_info_t));
348e18a033bSKonstantin Ananyev
349e18a033bSKonstantin Ananyev    of.uniq = c->uniq;
350e18a033bSKonstantin Ananyev    of.valid = clcf->open_file_cache_valid;
351e18a033bSKonstantin Ananyev    of.min_uses = clcf->open_file_cache_min_uses;
352e18a033bSKonstantin Ananyev    of.events = clcf->open_file_cache_events;
353e18a033bSKonstantin Ananyev    of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
354e18a033bSKonstantin Ananyev    of.read_ahead = clcf->read_ahead;
355e18a033bSKonstantin Ananyev
356e18a033bSKonstantin Ananyev    if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool)
357e18a033bSKonstantin Ananyev        != NGX_OK)
358e18a033bSKonstantin Ananyev    {
359e18a033bSKonstantin Ananyev        switch (of.err) {
360e18a033bSKonstantin Ananyev
361e18a033bSKonstantin Ananyev        case 0:
362e18a033bSKonstantin Ananyev            return NGX_ERROR;
363e18a033bSKonstantin Ananyev
364e18a033bSKonstantin Ananyev        case NGX_ENOENT:
365e18a033bSKonstantin Ananyev        case NGX_ENOTDIR:
366e18a033bSKonstantin Ananyev            goto done;
367e18a033bSKonstantin Ananyev
368e18a033bSKonstantin Ananyev        default:
369e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
370e18a033bSKonstantin Ananyev                          ngx_open_file_n " \"%s\" failed", c->file.name.data);
371e18a033bSKonstantin Ananyev            return NGX_ERROR;
372e18a033bSKonstantin Ananyev        }
373e18a033bSKonstantin Ananyev    }
374e18a033bSKonstantin Ananyev
375e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
376e18a033bSKonstantin Ananyev                   "http file cache fd: %d", of.fd);
377e18a033bSKonstantin Ananyev
378e18a033bSKonstantin Ananyev    c->file.fd = of.fd;
379e18a033bSKonstantin Ananyev    c->file.log = r->connection->log;
380e18a033bSKonstantin Ananyev    c->uniq = of.uniq;
381e18a033bSKonstantin Ananyev    c->length = of.size;
382e18a033bSKonstantin Ananyev    c->fs_size = (of.fs_size + cache->bsize - 1) / cache->bsize;
383e18a033bSKonstantin Ananyev
384e18a033bSKonstantin Ananyev    c->buf = ngx_create_temp_buf(r->pool, c->body_start);
385e18a033bSKonstantin Ananyev    if (c->buf == NULL) {
386e18a033bSKonstantin Ananyev        return NGX_ERROR;
387e18a033bSKonstantin Ananyev    }
388e18a033bSKonstantin Ananyev
389e18a033bSKonstantin Ananyev    return ngx_http_file_cache_read(r, c);
390e18a033bSKonstantin Ananyev
391e18a033bSKonstantin Ananyevdone:
392e18a033bSKonstantin Ananyev
393e18a033bSKonstantin Ananyev    if (rv == NGX_DECLINED) {
394e18a033bSKonstantin Ananyev        return ngx_http_file_cache_lock(r, c);
395e18a033bSKonstantin Ananyev    }
396e18a033bSKonstantin Ananyev
397e18a033bSKonstantin Ananyev    return rv;
398e18a033bSKonstantin Ananyev}
399e18a033bSKonstantin Ananyev
400e18a033bSKonstantin Ananyev
401e18a033bSKonstantin Ananyevstatic ngx_int_t
402e18a033bSKonstantin Ananyevngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c)
403e18a033bSKonstantin Ananyev{
404e18a033bSKonstantin Ananyev    ngx_msec_t                 now, timer;
405e18a033bSKonstantin Ananyev    ngx_http_file_cache_t     *cache;
406e18a033bSKonstantin Ananyev
407e18a033bSKonstantin Ananyev    if (!c->lock) {
408e18a033bSKonstantin Ananyev        return NGX_DECLINED;
409e18a033bSKonstantin Ananyev    }
410e18a033bSKonstantin Ananyev
411e18a033bSKonstantin Ananyev    now = ngx_current_msec;
412e18a033bSKonstantin Ananyev
413e18a033bSKonstantin Ananyev    cache = c->file_cache;
414e18a033bSKonstantin Ananyev
415e18a033bSKonstantin Ananyev    ngx_shmtx_lock(&cache->shpool->mutex);
416