Mercurial > hg > nginx
annotate src/core/ngx_open_file_cache.c @ 4019:5364d2e711cc
SIGWINCH/NOACCEPT signal is disabled now in non-daemon mode.
Non-daemon mode is currently used by supervisord, daemontools and so on
or during debugging. The NOACCEPT signal is only used for online upgrade
which is not supported when nginx is run under supervisord, etc.,
so this change should not break existant setups.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 22 Aug 2011 12:34:48 +0000 |
parents | e7cd13b7f759 |
children | 37da005a5808 010a0907bc95 |
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 file->count++; |
1453 | 288 |
1775 | 289 if (file->event) { |
290 file->use_event = 1; | |
1453 | 291 } |
292 | |
1775 | 293 goto renew; |
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 renew: | |
398 | |
399 file->created = now; | |
400 | |
401 found: | |
402 | |
403 file->accessed = now; | |
404 | |
1765 | 405 ngx_queue_insert_head(&cache->expire_queue, &file->queue); |
1453 | 406 |
1772 | 407 ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0, |
408 "cached open file: %s, fd:%d, c:%d, e:%d, u:%d", | |
409 file->name, file->fd, file->count, file->err, file->uses); | |
1453 | 410 |
411 if (of->err == 0) { | |
412 | |
413 if (!of->is_dir) { | |
414 cln->handler = ngx_open_file_cleanup; | |
415 ofcln = cln->data; | |
416 | |
417 ofcln->cache = cache; | |
418 ofcln->file = file; | |
1772 | 419 ofcln->min_uses = of->min_uses; |
1453 | 420 ofcln->log = pool->log; |
421 } | |
422 | |
423 return NGX_OK; | |
424 } | |
425 | |
426 return NGX_ERROR; | |
427 | |
428 failed: | |
429 | |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
430 if (file) { |
1453 | 431 ngx_rbtree_delete(&cache->rbtree, &file->node); |
432 | |
433 cache->current--; | |
434 | |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
435 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
|
436 |
2006
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
437 if (file->fd != NGX_INVALID_FILE) { |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
438 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
|
439 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
|
440 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
|
441 file->name); |
2006
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
442 } |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
443 } |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
444 |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
445 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
|
446 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
|
447 |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
448 } else { |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
449 file->close = 1; |
1453 | 450 } |
451 } | |
452 | |
453 if (of->fd != NGX_INVALID_FILE) { | |
454 if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { | |
455 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, | |
456 ngx_close_file_n " \"%s\" failed", name->data); | |
457 } | |
458 } | |
459 | |
460 return NGX_ERROR; | |
461 } | |
462 | |
463 | |
464 static ngx_int_t | |
465 ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log) | |
466 { | |
467 ngx_fd_t fd; | |
468 ngx_file_info_t fi; | |
469 | |
2070 | 470 if (of->fd != NGX_INVALID_FILE) { |
1453 | 471 |
2782
4bd7825fab80
uniform ngx_file_info() interface with ngx_fd_info()
Igor Sysoev <igor@sysoev.ru>
parents:
2756
diff
changeset
|
472 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
|
473 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
|
474 goto failed; |
1453 | 475 } |
476 | |
2070 | 477 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
|
478 goto done; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
479 } |
1453 | 480 |
2070 | 481 } else if (of->test_dir) { |
482 | |
2782
4bd7825fab80
uniform ngx_file_info() interface with ngx_fd_info()
Igor Sysoev <igor@sysoev.ru>
parents:
2756
diff
changeset
|
483 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
|
484 of->failed = ngx_file_info_n; |
2070 | 485 goto failed; |
486 } | |
487 | |
2460
225fa4abd76f
test ngx_file_info() result, the bug has been introduced in r2070
Igor Sysoev <igor@sysoev.ru>
parents:
2246
diff
changeset
|
488 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
|
489 goto done; |
1453 | 490 } |
491 } | |
492 | |
2072 | 493 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
|
494 |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
495 /* |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
496 * 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
|
497 * 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
|
498 */ |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
499 |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
500 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
|
501 NGX_FILE_OPEN, 0); |
2072 | 502 |
503 } else { | |
2629
367b29612a00
Win32 appends synchronized if only FILE_APPEND_DATA and SYNCHRONIZE are set
Igor Sysoev <igor@sysoev.ru>
parents:
2628
diff
changeset
|
504 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
|
505 NGX_FILE_DEFAULT_ACCESS); |
2072 | 506 } |
1453 | 507 |
508 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
|
509 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
|
510 goto failed; |
1453 | 511 } |
512 | |
513 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { | |
514 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, | |
515 ngx_fd_info_n " \"%s\" failed", name); | |
516 | |
517 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
518 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
519 ngx_close_file_n " \"%s\" failed", name); | |
520 } | |
521 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
522 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
|
523 |
1453 | 524 return NGX_ERROR; |
525 } | |
526 | |
527 if (ngx_is_dir(&fi)) { | |
528 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
529 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
530 ngx_close_file_n " \"%s\" failed", name); | |
531 } | |
532 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
533 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
|
534 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
535 } else { |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
536 of->fd = fd; |
2129 | 537 |
3178 | 538 if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { |
539 if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { | |
540 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
541 ngx_read_ahead_n " \"%s\" failed", name); | |
542 } | |
543 } | |
544 | |
2129 | 545 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
|
546 if (ngx_directio_on(fd) == NGX_FILE_ERROR) { |
2129 | 547 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
|
548 ngx_directio_on_n " \"%s\" failed", name); |
2231
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
549 |
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
550 } else { |
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
551 of->is_directio = 1; |
2129 | 552 } |
553 } | |
1453 | 554 } |
555 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
556 done: |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
557 |
1453 | 558 of->uniq = ngx_file_uniq(&fi); |
559 of->mtime = ngx_file_mtime(&fi); | |
560 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
|
561 of->fs_size = ngx_file_fs_size(&fi); |
1453 | 562 of->is_dir = ngx_is_dir(&fi); |
563 of->is_file = ngx_is_file(&fi); | |
564 of->is_link = ngx_is_link(&fi); | |
565 of->is_exec = ngx_is_exec(&fi); | |
566 | |
567 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
|
568 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
569 failed: |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
570 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
571 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
|
572 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
|
573 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
574 return NGX_ERROR; |
1453 | 575 } |
576 | |
577 | |
1775 | 578 /* |
579 * we ignore any possible event setting error and | |
580 * fallback to usual periodic file retests | |
581 */ | |
582 | |
583 static void | |
584 ngx_open_file_add_event(ngx_open_file_cache_t *cache, | |
585 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log) | |
586 { | |
587 ngx_open_file_cache_event_t *fev; | |
588 | |
589 if (!(ngx_event_flags & NGX_USE_VNODE_EVENT) | |
590 || !of->events | |
591 || file->event | |
592 || of->fd == NGX_INVALID_FILE | |
593 || file->uses < of->min_uses) | |
594 { | |
595 return; | |
596 } | |
597 | |
2070 | 598 file->use_event = 0; |
599 | |
1775 | 600 file->event = ngx_calloc(sizeof(ngx_event_t), log); |
601 if (file->event== NULL) { | |
602 return; | |
603 } | |
604 | |
605 fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log); | |
606 if (fev == NULL) { | |
607 ngx_free(file->event); | |
608 file->event = NULL; | |
609 return; | |
610 } | |
611 | |
612 fev->fd = of->fd; | |
613 fev->file = file; | |
614 fev->cache = cache; | |
615 | |
616 file->event->handler = ngx_open_file_cache_remove; | |
617 file->event->data = fev; | |
618 | |
619 /* | |
620 * although vnode event may be called while ngx_cycle->poll | |
621 * destruction, however, cleanup procedures are run before any | |
622 * memory freeing and events will be canceled. | |
623 */ | |
624 | |
625 file->event->log = ngx_cycle->log; | |
626 | |
627 if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) | |
628 != NGX_OK) | |
629 { | |
630 ngx_free(file->event->data); | |
631 ngx_free(file->event); | |
632 file->event = NULL; | |
633 return; | |
634 } | |
635 | |
636 /* | |
2071 | 637 * we do not set file->use_event here because there may be a race |
638 * condition: a file may be deleted between opening the file and | |
639 * adding event, so we rely upon event notification only after | |
640 * one file revalidation on next file access | |
1775 | 641 */ |
642 | |
643 return; | |
644 } | |
645 | |
646 | |
1453 | 647 static void |
648 ngx_open_file_cleanup(void *data) | |
649 { | |
650 ngx_open_file_cache_cleanup_t *c = data; | |
651 | |
652 c->file->count--; | |
653 | |
1772 | 654 ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log); |
1453 | 655 |
656 /* drop one or two expired open files */ | |
657 ngx_expire_old_cached_files(c->cache, 1, c->log); | |
658 } | |
659 | |
660 | |
661 static void | |
662 ngx_close_cached_file(ngx_open_file_cache_t *cache, | |
1772 | 663 ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log) |
1453 | 664 { |
1772 | 665 ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0, |
666 "close cached open file: %s, fd:%d, c:%d, u:%d, %d", | |
667 file->name, file->fd, file->count, file->uses, file->close); | |
1453 | 668 |
669 if (!file->close) { | |
670 | |
671 file->accessed = ngx_time(); | |
672 | |
1765 | 673 ngx_queue_remove(&file->queue); |
1453 | 674 |
1765 | 675 ngx_queue_insert_head(&cache->expire_queue, &file->queue); |
1453 | 676 |
1772 | 677 if (file->uses >= min_uses || file->count) { |
678 return; | |
679 } | |
1453 | 680 } |
681 | |
1775 | 682 ngx_open_file_del_event(file); |
1453 | 683 |
684 if (file->count) { | |
685 return; | |
686 } | |
687 | |
1772 | 688 if (file->fd != NGX_INVALID_FILE) { |
689 | |
690 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { | |
691 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
692 ngx_close_file_n " \"%s\" failed", file->name); | |
693 } | |
694 | |
695 file->fd = NGX_INVALID_FILE; | |
696 } | |
697 | |
698 if (!file->close) { | |
699 return; | |
1453 | 700 } |
701 | |
702 ngx_free(file->name); | |
703 ngx_free(file); | |
704 } | |
705 | |
706 | |
707 static void | |
1775 | 708 ngx_open_file_del_event(ngx_cached_open_file_t *file) |
709 { | |
710 if (file->event == NULL) { | |
711 return; | |
712 } | |
713 | |
714 (void) ngx_del_event(file->event, NGX_VNODE_EVENT, | |
715 file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT); | |
716 | |
717 ngx_free(file->event->data); | |
718 ngx_free(file->event); | |
719 file->event = NULL; | |
720 file->use_event = 0; | |
721 } | |
722 | |
723 | |
724 static void | |
1453 | 725 ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, |
726 ngx_log_t *log) | |
727 { | |
728 time_t now; | |
1765 | 729 ngx_queue_t *q; |
1453 | 730 ngx_cached_open_file_t *file; |
731 | |
732 now = ngx_time(); | |
733 | |
734 /* | |
735 * n == 1 deletes one or two inactive files | |
736 * n == 0 deletes least recently used file by force | |
737 * and one or two inactive files | |
738 */ | |
739 | |
740 while (n < 3) { | |
741 | |
1765 | 742 if (ngx_queue_empty(&cache->expire_queue)) { |
1453 | 743 return; |
744 } | |
745 | |
1765 | 746 q = ngx_queue_last(&cache->expire_queue); |
747 | |
748 file = ngx_queue_data(q, ngx_cached_open_file_t, queue); | |
749 | |
1453 | 750 if (n++ != 0 && now - file->accessed <= cache->inactive) { |
751 return; | |
752 } | |
753 | |
1765 | 754 ngx_queue_remove(q); |
1453 | 755 |
756 ngx_rbtree_delete(&cache->rbtree, &file->node); | |
757 | |
758 cache->current--; | |
759 | |
760 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | |
761 "expire cached open file: %s", file->name); | |
762 | |
763 if (!file->err && !file->is_dir) { | |
764 file->close = 1; | |
1772 | 765 ngx_close_cached_file(cache, file, 0, log); |
1453 | 766 |
767 } else { | |
768 ngx_free(file->name); | |
769 ngx_free(file); | |
770 } | |
771 } | |
772 } | |
773 | |
774 | |
775 static void | |
776 ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, | |
777 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) | |
778 { | |
779 ngx_rbtree_node_t **p; | |
780 ngx_cached_open_file_t *file, *file_temp; | |
781 | |
782 for ( ;; ) { | |
783 | |
784 if (node->key < temp->key) { | |
785 | |
786 p = &temp->left; | |
787 | |
788 } else if (node->key > temp->key) { | |
789 | |
790 p = &temp->right; | |
791 | |
792 } else { /* node->key == temp->key */ | |
793 | |
794 file = (ngx_cached_open_file_t *) node; | |
795 file_temp = (ngx_cached_open_file_t *) temp; | |
796 | |
797 p = (ngx_strcmp(file->name, file_temp->name) < 0) | |
798 ? &temp->left : &temp->right; | |
799 } | |
800 | |
801 if (*p == sentinel) { | |
802 break; | |
803 } | |
804 | |
805 temp = *p; | |
806 } | |
807 | |
808 *p = node; | |
809 node->parent = temp; | |
810 node->left = sentinel; | |
811 node->right = sentinel; | |
812 ngx_rbt_red(node); | |
813 } | |
814 | |
815 | |
1775 | 816 static ngx_cached_open_file_t * |
817 ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, | |
818 uint32_t hash) | |
819 { | |
820 ngx_int_t rc; | |
821 ngx_rbtree_node_t *node, *sentinel; | |
822 ngx_cached_open_file_t *file; | |
823 | |
824 node = cache->rbtree.root; | |
825 sentinel = cache->rbtree.sentinel; | |
826 | |
827 while (node != sentinel) { | |
828 | |
829 if (hash < node->key) { | |
830 node = node->left; | |
831 continue; | |
832 } | |
833 | |
834 if (hash > node->key) { | |
835 node = node->right; | |
836 continue; | |
837 } | |
838 | |
839 /* hash == node->key */ | |
840 | |
841 do { | |
842 file = (ngx_cached_open_file_t *) node; | |
843 | |
844 rc = ngx_strcmp(name->data, file->name); | |
845 | |
846 if (rc == 0) { | |
847 return file; | |
848 } | |
849 | |
850 node = (rc < 0) ? node->left : node->right; | |
851 | |
852 } while (node != sentinel && hash == node->key); | |
853 | |
854 break; | |
855 } | |
856 | |
857 return NULL; | |
858 } | |
859 | |
860 | |
1453 | 861 static void |
862 ngx_open_file_cache_remove(ngx_event_t *ev) | |
863 { | |
864 ngx_cached_open_file_t *file; | |
865 ngx_open_file_cache_event_t *fev; | |
866 | |
867 fev = ev->data; | |
868 file = fev->file; | |
869 | |
1765 | 870 ngx_queue_remove(&file->queue); |
1453 | 871 |
872 ngx_rbtree_delete(&fev->cache->rbtree, &file->node); | |
873 | |
874 fev->cache->current--; | |
875 | |
876 /* NGX_ONESHOT_EVENT was already deleted */ | |
877 file->event = NULL; | |
2070 | 878 file->use_event = 0; |
1453 | 879 |
880 file->close = 1; | |
881 | |
1772 | 882 ngx_close_cached_file(fev->cache, file, 0, ev->log); |
1453 | 883 |
884 /* free memory only when fev->cache and fev->file are already not needed */ | |
885 | |
886 ngx_free(ev->data); | |
887 ngx_free(ev); | |
888 } |