Mercurial > hg > nginx-quic
annotate src/core/ngx_open_file_cache.c @ 4367:9c4acdf9b276 stable-1.0
Merge of r4315:
Allowed add_header for proxied 206 replies.
It was working for nginx's own 206 replies as they are seen as 200 in the
headers filter module (range filter goes later in the headers filter chain),
but not for proxied replies.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 14 Dec 2011 18:06:21 +0000 |
parents | 010a0907bc95 |
children | 4919fb357a5d |
rev | line source |
---|---|
1453 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 | |
11 | |
12 /* | |
13 * open file cache caches | |
14 * open file handles with stat() info; | |
15 * directories stat() info; | |
16 * files and directories errors: not found, access denied, etc. | |
17 */ | |
18 | |
19 | |
3178 | 20 #define NGX_MIN_READ_AHEAD (128 * 1024) |
21 | |
22 | |
1453 | 23 static void ngx_open_file_cache_cleanup(void *data); |
1775 | 24 static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, |
25 ngx_log_t *log); | |
26 static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, | |
27 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); | |
1453 | 28 static void ngx_open_file_cleanup(void *data); |
29 static void ngx_close_cached_file(ngx_open_file_cache_t *cache, | |
1772 | 30 ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log); |
1775 | 31 static void ngx_open_file_del_event(ngx_cached_open_file_t *file); |
1453 | 32 static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, |
33 ngx_uint_t n, ngx_log_t *log); | |
34 static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, | |
35 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); | |
1775 | 36 static ngx_cached_open_file_t * |
37 ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, | |
38 uint32_t hash); | |
1453 | 39 static void ngx_open_file_cache_remove(ngx_event_t *ev); |
40 | |
41 | |
42 ngx_open_file_cache_t * | |
43 ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive) | |
44 { | |
45 ngx_pool_cleanup_t *cln; | |
46 ngx_open_file_cache_t *cache; | |
47 | |
48 cache = ngx_palloc(pool, sizeof(ngx_open_file_cache_t)); | |
49 if (cache == NULL) { | |
50 return NULL; | |
51 } | |
52 | |
1761 | 53 ngx_rbtree_init(&cache->rbtree, &cache->sentinel, |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1458
diff
changeset
|
54 ngx_open_file_cache_rbtree_insert_value); |
1453 | 55 |
1765 | 56 ngx_queue_init(&cache->expire_queue); |
57 | |
1453 | 58 cache->current = 0; |
59 cache->max = max; | |
60 cache->inactive = inactive; | |
61 | |
62 cln = ngx_pool_cleanup_add(pool, 0); | |
63 if (cln == NULL) { | |
64 return NULL; | |
65 } | |
66 | |
67 cln->handler = ngx_open_file_cache_cleanup; | |
68 cln->data = cache; | |
69 | |
70 return cache; | |
71 } | |
72 | |
73 | |
74 static void | |
75 ngx_open_file_cache_cleanup(void *data) | |
76 { | |
77 ngx_open_file_cache_t *cache = data; | |
78 | |
1765 | 79 ngx_queue_t *q; |
1453 | 80 ngx_cached_open_file_t *file; |
81 | |
82 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, | |
83 "open file cache cleanup"); | |
84 | |
85 for ( ;; ) { | |
86 | |
1765 | 87 if (ngx_queue_empty(&cache->expire_queue)) { |
1766 | 88 break; |
1453 | 89 } |
90 | |
1765 | 91 q = ngx_queue_last(&cache->expire_queue); |
92 | |
93 file = ngx_queue_data(q, ngx_cached_open_file_t, queue); | |
94 | |
95 ngx_queue_remove(q); | |
1453 | 96 |
97 ngx_rbtree_delete(&cache->rbtree, &file->node); | |
98 | |
99 cache->current--; | |
100 | |
101 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, | |
102 "delete cached open file: %s", file->name); | |
103 | |
104 if (!file->err && !file->is_dir) { | |
105 file->close = 1; | |
106 file->count = 0; | |
1772 | 107 ngx_close_cached_file(cache, file, 0, ngx_cycle->log); |
1453 | 108 |
109 } else { | |
110 ngx_free(file->name); | |
111 ngx_free(file); | |
112 } | |
113 } | |
114 | |
115 if (cache->current) { | |
116 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | |
117 "%d items still leave in open file cache", | |
118 cache->current); | |
119 } | |
120 | |
121 if (cache->rbtree.root != cache->rbtree.sentinel) { | |
122 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | |
123 "rbtree still is not empty in open file cache"); | |
124 | |
125 } | |
126 } | |
127 | |
128 | |
129 ngx_int_t | |
130 ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, | |
131 ngx_open_file_info_t *of, ngx_pool_t *pool) | |
132 { | |
133 time_t now; | |
134 uint32_t hash; | |
135 ngx_int_t rc; | |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
136 ngx_file_info_t fi; |
1453 | 137 ngx_pool_cleanup_t *cln; |
138 ngx_cached_open_file_t *file; | |
139 ngx_pool_cleanup_file_t *clnf; | |
140 ngx_open_file_cache_cleanup_t *ofcln; | |
141 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
142 of->fd = NGX_INVALID_FILE; |
1453 | 143 of->err = 0; |
144 | |
145 if (cache == NULL) { | |
146 | |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
147 if (of->test_only) { |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
148 |
2782
4bd7825fab80
uniform ngx_file_info() interface with ngx_fd_info()
Igor Sysoev <igor@sysoev.ru>
parents:
2756
diff
changeset
|
149 if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) { |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
150 of->err = ngx_errno; |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
151 of->failed = ngx_file_info_n; |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
152 return NGX_ERROR; |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
153 } |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
154 |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
155 of->uniq = ngx_file_uniq(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
156 of->mtime = ngx_file_mtime(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
157 of->size = ngx_file_size(&fi); |
3899
e7cd13b7f759
Use more precise stat.st_blocks to account cache size on Unix
Igor Sysoev <igor@sysoev.ru>
parents:
3497
diff
changeset
|
158 of->fs_size = ngx_file_fs_size(&fi); |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
159 of->is_dir = ngx_is_dir(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
160 of->is_file = ngx_is_file(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
161 of->is_link = ngx_is_link(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
162 of->is_exec = ngx_is_exec(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
163 |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
164 return NGX_OK; |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
165 } |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
166 |
1453 | 167 cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); |
168 if (cln == NULL) { | |
169 return NGX_ERROR; | |
170 } | |
171 | |
172 rc = ngx_open_and_stat_file(name->data, of, pool->log); | |
173 | |
174 if (rc == NGX_OK && !of->is_dir) { | |
175 cln->handler = ngx_pool_cleanup_file; | |
176 clnf = cln->data; | |
177 | |
178 clnf->fd = of->fd; | |
179 clnf->name = name->data; | |
180 clnf->log = pool->log; | |
181 } | |
182 | |
183 return rc; | |
184 } | |
185 | |
186 cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t)); | |
187 if (cln == NULL) { | |
188 return NGX_ERROR; | |
189 } | |
190 | |
191 now = ngx_time(); | |
192 | |
1775 | 193 hash = ngx_crc32_long(name->data, name->len); |
194 | |
195 file = ngx_open_file_lookup(cache, name, hash); | |
196 | |
197 if (file) { | |
198 | |
199 file->uses++; | |
200 | |
1987 | 201 ngx_queue_remove(&file->queue); |
202 | |
1775 | 203 if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) { |
204 | |
205 /* file was not used often enough to keep open */ | |
206 | |
207 rc = ngx_open_and_stat_file(name->data, of, pool->log); | |
1453 | 208 |
1775 | 209 if (rc != NGX_OK && (of->err == 0 || !of->errors)) { |
210 goto failed; | |
211 } | |
212 | |
213 goto add_event; | |
1453 | 214 } |
215 | |
2070 | 216 if (file->use_event |
2063
67a29af877ed
initialize of.uniq in ngx_open_cached_file()
Igor Sysoev <igor@sysoev.ru>
parents:
2006
diff
changeset
|
217 || (file->event == NULL |
67a29af877ed
initialize of.uniq in ngx_open_cached_file()
Igor Sysoev <igor@sysoev.ru>
parents:
2006
diff
changeset
|
218 && (of->uniq == 0 || of->uniq == file->uniq) |
67a29af877ed
initialize of.uniq in ngx_open_cached_file()
Igor Sysoev <igor@sysoev.ru>
parents:
2006
diff
changeset
|
219 && now - file->created < of->valid)) |
1775 | 220 { |
221 if (file->err == 0) { | |
1772 | 222 |
1775 | 223 of->fd = file->fd; |
224 of->uniq = file->uniq; | |
225 of->mtime = file->mtime; | |
226 of->size = file->size; | |
1453 | 227 |
1775 | 228 of->is_dir = file->is_dir; |
229 of->is_file = file->is_file; | |
230 of->is_link = file->is_link; | |
231 of->is_exec = file->is_exec; | |
2246
987831d73bd8
cache directio flag in open file cache
Igor Sysoev <igor@sysoev.ru>
parents:
2231
diff
changeset
|
232 of->is_directio = file->is_directio; |
1453 | 233 |
1775 | 234 if (!file->is_dir) { |
235 file->count++; | |
236 ngx_open_file_add_event(cache, file, of, pool->log); | |
1453 | 237 } |
238 | |
1775 | 239 } else { |
240 of->err = file->err; | |
2783
87c088e6956a
set of.failed for cached error, the bug has been introduced in r2757
Igor Sysoev <igor@sysoev.ru>
parents:
2782
diff
changeset
|
241 of->failed = ngx_open_file_n; |
1775 | 242 } |
243 | |
244 goto found; | |
245 } | |
246 | |
247 ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, | |
248 "retest open file: %s, fd:%d, c:%d, e:%d", | |
249 file->name, file->fd, file->count, file->err); | |
1453 | 250 |
1775 | 251 if (file->is_dir) { |
252 | |
253 /* | |
254 * chances that directory became file are very small | |
255 * so test_dir flag allows to use a single syscall | |
256 * in ngx_file_info() instead of three syscalls | |
257 */ | |
258 | |
259 of->test_dir = 1; | |
260 } | |
261 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
262 of->fd = file->fd; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
263 of->uniq = file->uniq; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
264 |
1775 | 265 rc = ngx_open_and_stat_file(name->data, of, pool->log); |
1453 | 266 |
1775 | 267 if (rc != NGX_OK && (of->err == 0 || !of->errors)) { |
268 goto failed; | |
269 } | |
270 | |
271 if (of->is_dir) { | |
272 | |
273 if (file->is_dir || file->err) { | |
274 goto update; | |
275 } | |
276 | |
277 /* file became directory */ | |
1453 | 278 |
1775 | 279 } else if (of->err == 0) { /* file */ |
280 | |
281 if (file->is_dir || file->err) { | |
282 goto add_event; | |
283 } | |
1453 | 284 |
2070 | 285 if (of->uniq == file->uniq) { |
1453 | 286 |
1775 | 287 if (file->event) { |
288 file->use_event = 1; | |
1453 | 289 } |
290 | |
4161 | 291 of->is_directio = file->is_directio; |
292 | |
293 goto update; | |
1775 | 294 } |
1453 | 295 |
1775 | 296 /* file was changed */ |
1453 | 297 |
1775 | 298 } else { /* error to cache */ |
1453 | 299 |
1775 | 300 if (file->err || file->is_dir) { |
301 goto update; | |
1453 | 302 } |
303 | |
1775 | 304 /* file was removed, etc. */ |
305 } | |
306 | |
307 if (file->count == 0) { | |
308 | |
309 ngx_open_file_del_event(file); | |
1453 | 310 |
1775 | 311 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { |
312 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, | |
313 ngx_close_file_n " \"%s\" failed", | |
314 name->data); | |
315 } | |
1453 | 316 |
1775 | 317 goto add_event; |
318 } | |
319 | |
320 ngx_rbtree_delete(&cache->rbtree, &file->node); | |
321 | |
322 cache->current--; | |
323 | |
324 file->close = 1; | |
325 | |
326 goto create; | |
1453 | 327 } |
328 | |
329 /* not found */ | |
330 | |
331 rc = ngx_open_and_stat_file(name->data, of, pool->log); | |
332 | |
333 if (rc != NGX_OK && (of->err == 0 || !of->errors)) { | |
334 goto failed; | |
335 } | |
336 | |
337 create: | |
338 | |
339 if (cache->current >= cache->max) { | |
340 ngx_expire_old_cached_files(cache, 0, pool->log); | |
341 } | |
342 | |
343 file = ngx_alloc(sizeof(ngx_cached_open_file_t), pool->log); | |
344 | |
345 if (file == NULL) { | |
346 goto failed; | |
347 } | |
348 | |
349 file->name = ngx_alloc(name->len + 1, pool->log); | |
350 | |
351 if (file->name == NULL) { | |
352 ngx_free(file); | |
353 file = NULL; | |
354 goto failed; | |
355 } | |
356 | |
357 ngx_cpystrn(file->name, name->data, name->len + 1); | |
358 | |
359 file->node.key = hash; | |
360 | |
361 ngx_rbtree_insert(&cache->rbtree, &file->node); | |
362 | |
363 cache->current++; | |
364 | |
1775 | 365 file->uses = 1; |
1453 | 366 file->count = 0; |
2934
b6d588fa3ee9
initialize use_event field in open file cache
Igor Sysoev <igor@sysoev.ru>
parents:
2783
diff
changeset
|
367 file->use_event = 0; |
1775 | 368 file->event = NULL; |
369 | |
370 add_event: | |
371 | |
372 ngx_open_file_add_event(cache, file, of, pool->log); | |
1453 | 373 |
374 update: | |
375 | |
376 file->fd = of->fd; | |
377 file->err = of->err; | |
378 | |
379 if (of->err == 0) { | |
380 file->uniq = of->uniq; | |
381 file->mtime = of->mtime; | |
382 file->size = of->size; | |
383 | |
384 file->close = 0; | |
385 | |
386 file->is_dir = of->is_dir; | |
387 file->is_file = of->is_file; | |
388 file->is_link = of->is_link; | |
389 file->is_exec = of->is_exec; | |
2246
987831d73bd8
cache directio flag in open file cache
Igor Sysoev <igor@sysoev.ru>
parents:
2231
diff
changeset
|
390 file->is_directio = of->is_directio; |
1453 | 391 |
392 if (!of->is_dir) { | |
393 file->count++; | |
394 } | |
395 } | |
396 | |
397 file->created = now; | |
398 | |
399 found: | |
400 | |
401 file->accessed = now; | |
402 | |
1765 | 403 ngx_queue_insert_head(&cache->expire_queue, &file->queue); |
1453 | 404 |
1772 | 405 ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0, |
406 "cached open file: %s, fd:%d, c:%d, e:%d, u:%d", | |
407 file->name, file->fd, file->count, file->err, file->uses); | |
1453 | 408 |
409 if (of->err == 0) { | |
410 | |
411 if (!of->is_dir) { | |
412 cln->handler = ngx_open_file_cleanup; | |
413 ofcln = cln->data; | |
414 | |
415 ofcln->cache = cache; | |
416 ofcln->file = file; | |
1772 | 417 ofcln->min_uses = of->min_uses; |
1453 | 418 ofcln->log = pool->log; |
419 } | |
420 | |
421 return NGX_OK; | |
422 } | |
423 | |
424 return NGX_ERROR; | |
425 | |
426 failed: | |
427 | |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
428 if (file) { |
1453 | 429 ngx_rbtree_delete(&cache->rbtree, &file->node); |
430 | |
431 cache->current--; | |
432 | |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
433 if (file->count == 0) { |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
434 |
2006
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
435 if (file->fd != NGX_INVALID_FILE) { |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
436 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
437 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
438 ngx_close_file_n " \"%s\" failed", |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
439 file->name); |
2006
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
440 } |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
441 } |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
442 |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
443 ngx_free(file->name); |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
444 ngx_free(file); |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
445 |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
446 } else { |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
447 file->close = 1; |
1453 | 448 } |
449 } | |
450 | |
451 if (of->fd != NGX_INVALID_FILE) { | |
452 if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { | |
453 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, | |
454 ngx_close_file_n " \"%s\" failed", name->data); | |
455 } | |
456 } | |
457 | |
458 return NGX_ERROR; | |
459 } | |
460 | |
461 | |
462 static ngx_int_t | |
463 ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log) | |
464 { | |
465 ngx_fd_t fd; | |
466 ngx_file_info_t fi; | |
467 | |
2070 | 468 if (of->fd != NGX_INVALID_FILE) { |
1453 | 469 |
2782
4bd7825fab80
uniform ngx_file_info() interface with ngx_fd_info()
Igor Sysoev <igor@sysoev.ru>
parents:
2756
diff
changeset
|
470 if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
471 of->failed = ngx_file_info_n; |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
472 goto failed; |
1453 | 473 } |
474 | |
2070 | 475 if (of->uniq == ngx_file_uniq(&fi)) { |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
476 goto done; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
477 } |
1453 | 478 |
2070 | 479 } else if (of->test_dir) { |
480 | |
2782
4bd7825fab80
uniform ngx_file_info() interface with ngx_fd_info()
Igor Sysoev <igor@sysoev.ru>
parents:
2756
diff
changeset
|
481 if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
482 of->failed = ngx_file_info_n; |
2070 | 483 goto failed; |
484 } | |
485 | |
2460
225fa4abd76f
test ngx_file_info() result, the bug has been introduced in r2070
Igor Sysoev <igor@sysoev.ru>
parents:
2246
diff
changeset
|
486 if (ngx_is_dir(&fi)) { |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
487 goto done; |
1453 | 488 } |
489 } | |
490 | |
2072 | 491 if (!of->log) { |
3497
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
492 |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
493 /* |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
494 * Use non-blocking open() not to hang on FIFO files, etc. |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
495 * This flag has no effect on a regular files. |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
496 */ |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
497 |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
498 fd = ngx_open_file(name, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
499 NGX_FILE_OPEN, 0); |
2072 | 500 |
501 } else { | |
2629
367b29612a00
Win32 appends synchronized if only FILE_APPEND_DATA and SYNCHRONIZE are set
Igor Sysoev <igor@sysoev.ru>
parents:
2628
diff
changeset
|
502 fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, |
367b29612a00
Win32 appends synchronized if only FILE_APPEND_DATA and SYNCHRONIZE are set
Igor Sysoev <igor@sysoev.ru>
parents:
2628
diff
changeset
|
503 NGX_FILE_DEFAULT_ACCESS); |
2072 | 504 } |
1453 | 505 |
506 if (fd == NGX_INVALID_FILE) { | |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
507 of->failed = ngx_open_file_n; |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
508 goto failed; |
1453 | 509 } |
510 | |
511 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { | |
512 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, | |
513 ngx_fd_info_n " \"%s\" failed", name); | |
514 | |
515 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
516 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
517 ngx_close_file_n " \"%s\" failed", name); | |
518 } | |
519 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
520 of->fd = NGX_INVALID_FILE; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
521 |
1453 | 522 return NGX_ERROR; |
523 } | |
524 | |
525 if (ngx_is_dir(&fi)) { | |
526 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
527 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
528 ngx_close_file_n " \"%s\" failed", name); | |
529 } | |
530 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
531 of->fd = NGX_INVALID_FILE; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
532 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
533 } else { |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
534 of->fd = fd; |
2129 | 535 |
3178 | 536 if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { |
537 if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { | |
538 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
539 ngx_read_ahead_n " \"%s\" failed", name); | |
540 } | |
541 } | |
542 | |
2129 | 543 if (of->directio <= ngx_file_size(&fi)) { |
3164
b1b1775698d5
uniform ngx_directio_on/off() interface with other file functions
Igor Sysoev <igor@sysoev.ru>
parents:
2934
diff
changeset
|
544 if (ngx_directio_on(fd) == NGX_FILE_ERROR) { |
2129 | 545 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
2246
987831d73bd8
cache directio flag in open file cache
Igor Sysoev <igor@sysoev.ru>
parents:
2231
diff
changeset
|
546 ngx_directio_on_n " \"%s\" failed", name); |
2231
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
547 |
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
548 } else { |
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
549 of->is_directio = 1; |
2129 | 550 } |
551 } | |
1453 | 552 } |
553 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
554 done: |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
555 |
1453 | 556 of->uniq = ngx_file_uniq(&fi); |
557 of->mtime = ngx_file_mtime(&fi); | |
558 of->size = ngx_file_size(&fi); | |
3899
e7cd13b7f759
Use more precise stat.st_blocks to account cache size on Unix
Igor Sysoev <igor@sysoev.ru>
parents:
3497
diff
changeset
|
559 of->fs_size = ngx_file_fs_size(&fi); |
1453 | 560 of->is_dir = ngx_is_dir(&fi); |
561 of->is_file = ngx_is_file(&fi); | |
562 of->is_link = ngx_is_link(&fi); | |
563 of->is_exec = ngx_is_exec(&fi); | |
564 | |
565 return NGX_OK; | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
566 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
567 failed: |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
568 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
569 of->fd = NGX_INVALID_FILE; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
570 of->err = ngx_errno; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
571 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
572 return NGX_ERROR; |
1453 | 573 } |
574 | |
575 | |
1775 | 576 /* |
577 * we ignore any possible event setting error and | |
578 * fallback to usual periodic file retests | |
579 */ | |
580 | |
581 static void | |
582 ngx_open_file_add_event(ngx_open_file_cache_t *cache, | |
583 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log) | |
584 { | |
585 ngx_open_file_cache_event_t *fev; | |
586 | |
587 if (!(ngx_event_flags & NGX_USE_VNODE_EVENT) | |
588 || !of->events | |
589 || file->event | |
590 || of->fd == NGX_INVALID_FILE | |
591 || file->uses < of->min_uses) | |
592 { | |
593 return; | |
594 } | |
595 | |
2070 | 596 file->use_event = 0; |
597 | |
1775 | 598 file->event = ngx_calloc(sizeof(ngx_event_t), log); |
599 if (file->event== NULL) { | |
600 return; | |
601 } | |
602 | |
603 fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log); | |
604 if (fev == NULL) { | |
605 ngx_free(file->event); | |
606 file->event = NULL; | |
607 return; | |
608 } | |
609 | |
610 fev->fd = of->fd; | |
611 fev->file = file; | |
612 fev->cache = cache; | |
613 | |
614 file->event->handler = ngx_open_file_cache_remove; | |
615 file->event->data = fev; | |
616 | |
617 /* | |
618 * although vnode event may be called while ngx_cycle->poll | |
619 * destruction, however, cleanup procedures are run before any | |
620 * memory freeing and events will be canceled. | |
621 */ | |
622 | |
623 file->event->log = ngx_cycle->log; | |
624 | |
625 if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) | |
626 != NGX_OK) | |
627 { | |
628 ngx_free(file->event->data); | |
629 ngx_free(file->event); | |
630 file->event = NULL; | |
631 return; | |
632 } | |
633 | |
634 /* | |
2071 | 635 * we do not set file->use_event here because there may be a race |
636 * condition: a file may be deleted between opening the file and | |
637 * adding event, so we rely upon event notification only after | |
638 * one file revalidation on next file access | |
1775 | 639 */ |
640 | |
641 return; | |
642 } | |
643 | |
644 | |
1453 | 645 static void |
646 ngx_open_file_cleanup(void *data) | |
647 { | |
648 ngx_open_file_cache_cleanup_t *c = data; | |
649 | |
650 c->file->count--; | |
651 | |
1772 | 652 ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log); |
1453 | 653 |
654 /* drop one or two expired open files */ | |
655 ngx_expire_old_cached_files(c->cache, 1, c->log); | |
656 } | |
657 | |
658 | |
659 static void | |
660 ngx_close_cached_file(ngx_open_file_cache_t *cache, | |
1772 | 661 ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log) |
1453 | 662 { |
1772 | 663 ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0, |
664 "close cached open file: %s, fd:%d, c:%d, u:%d, %d", | |
665 file->name, file->fd, file->count, file->uses, file->close); | |
1453 | 666 |
667 if (!file->close) { | |
668 | |
669 file->accessed = ngx_time(); | |
670 | |
1765 | 671 ngx_queue_remove(&file->queue); |
1453 | 672 |
1765 | 673 ngx_queue_insert_head(&cache->expire_queue, &file->queue); |
1453 | 674 |
1772 | 675 if (file->uses >= min_uses || file->count) { |
676 return; | |
677 } | |
1453 | 678 } |
679 | |
1775 | 680 ngx_open_file_del_event(file); |
1453 | 681 |
682 if (file->count) { | |
683 return; | |
684 } | |
685 | |
1772 | 686 if (file->fd != NGX_INVALID_FILE) { |
687 | |
688 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { | |
689 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
690 ngx_close_file_n " \"%s\" failed", file->name); | |
691 } | |
692 | |
693 file->fd = NGX_INVALID_FILE; | |
694 } | |
695 | |
696 if (!file->close) { | |
697 return; | |
1453 | 698 } |
699 | |
700 ngx_free(file->name); | |
701 ngx_free(file); | |
702 } | |
703 | |
704 | |
705 static void | |
1775 | 706 ngx_open_file_del_event(ngx_cached_open_file_t *file) |
707 { | |
708 if (file->event == NULL) { | |
709 return; | |
710 } | |
711 | |
712 (void) ngx_del_event(file->event, NGX_VNODE_EVENT, | |
713 file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT); | |
714 | |
715 ngx_free(file->event->data); | |
716 ngx_free(file->event); | |
717 file->event = NULL; | |
718 file->use_event = 0; | |
719 } | |
720 | |
721 | |
722 static void | |
1453 | 723 ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, |
724 ngx_log_t *log) | |
725 { | |
726 time_t now; | |
1765 | 727 ngx_queue_t *q; |
1453 | 728 ngx_cached_open_file_t *file; |
729 | |
730 now = ngx_time(); | |
731 | |
732 /* | |
733 * n == 1 deletes one or two inactive files | |
734 * n == 0 deletes least recently used file by force | |
735 * and one or two inactive files | |
736 */ | |
737 | |
738 while (n < 3) { | |
739 | |
1765 | 740 if (ngx_queue_empty(&cache->expire_queue)) { |
1453 | 741 return; |
742 } | |
743 | |
1765 | 744 q = ngx_queue_last(&cache->expire_queue); |
745 | |
746 file = ngx_queue_data(q, ngx_cached_open_file_t, queue); | |
747 | |
1453 | 748 if (n++ != 0 && now - file->accessed <= cache->inactive) { |
749 return; | |
750 } | |
751 | |
1765 | 752 ngx_queue_remove(q); |
1453 | 753 |
754 ngx_rbtree_delete(&cache->rbtree, &file->node); | |
755 | |
756 cache->current--; | |
757 | |
758 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | |
759 "expire cached open file: %s", file->name); | |
760 | |
761 if (!file->err && !file->is_dir) { | |
762 file->close = 1; | |
1772 | 763 ngx_close_cached_file(cache, file, 0, log); |
1453 | 764 |
765 } else { | |
766 ngx_free(file->name); | |
767 ngx_free(file); | |
768 } | |
769 } | |
770 } | |
771 | |
772 | |
773 static void | |
774 ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, | |
775 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) | |
776 { | |
777 ngx_rbtree_node_t **p; | |
778 ngx_cached_open_file_t *file, *file_temp; | |
779 | |
780 for ( ;; ) { | |
781 | |
782 if (node->key < temp->key) { | |
783 | |
784 p = &temp->left; | |
785 | |
786 } else if (node->key > temp->key) { | |
787 | |
788 p = &temp->right; | |
789 | |
790 } else { /* node->key == temp->key */ | |
791 | |
792 file = (ngx_cached_open_file_t *) node; | |
793 file_temp = (ngx_cached_open_file_t *) temp; | |
794 | |
795 p = (ngx_strcmp(file->name, file_temp->name) < 0) | |
796 ? &temp->left : &temp->right; | |
797 } | |
798 | |
799 if (*p == sentinel) { | |
800 break; | |
801 } | |
802 | |
803 temp = *p; | |
804 } | |
805 | |
806 *p = node; | |
807 node->parent = temp; | |
808 node->left = sentinel; | |
809 node->right = sentinel; | |
810 ngx_rbt_red(node); | |
811 } | |
812 | |
813 | |
1775 | 814 static ngx_cached_open_file_t * |
815 ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, | |
816 uint32_t hash) | |
817 { | |
818 ngx_int_t rc; | |
819 ngx_rbtree_node_t *node, *sentinel; | |
820 ngx_cached_open_file_t *file; | |
821 | |
822 node = cache->rbtree.root; | |
823 sentinel = cache->rbtree.sentinel; | |
824 | |
825 while (node != sentinel) { | |
826 | |
827 if (hash < node->key) { | |
828 node = node->left; | |
829 continue; | |
830 } | |
831 | |
832 if (hash > node->key) { | |
833 node = node->right; | |
834 continue; | |
835 } | |
836 | |
837 /* hash == node->key */ | |
838 | |
839 do { | |
840 file = (ngx_cached_open_file_t *) node; | |
841 | |
842 rc = ngx_strcmp(name->data, file->name); | |
843 | |
844 if (rc == 0) { | |
845 return file; | |
846 } | |
847 | |
848 node = (rc < 0) ? node->left : node->right; | |
849 | |
850 } while (node != sentinel && hash == node->key); | |
851 | |
852 break; | |
853 } | |
854 | |
855 return NULL; | |
856 } | |
857 | |
858 | |
1453 | 859 static void |
860 ngx_open_file_cache_remove(ngx_event_t *ev) | |
861 { | |
862 ngx_cached_open_file_t *file; | |
863 ngx_open_file_cache_event_t *fev; | |
864 | |
865 fev = ev->data; | |
866 file = fev->file; | |
867 | |
1765 | 868 ngx_queue_remove(&file->queue); |
1453 | 869 |
870 ngx_rbtree_delete(&fev->cache->rbtree, &file->node); | |
871 | |
872 fev->cache->current--; | |
873 | |
874 /* NGX_ONESHOT_EVENT was already deleted */ | |
875 file->event = NULL; | |
2070 | 876 file->use_event = 0; |
1453 | 877 |
878 file->close = 1; | |
879 | |
1772 | 880 ngx_close_cached_file(fev->cache, file, 0, ev->log); |
1453 | 881 |
882 /* free memory only when fev->cache and fev->file are already not needed */ | |
883 | |
884 ngx_free(ev->data); | |
885 ngx_free(ev); | |
886 } |