comparison src/core/ngx_open_file_cache.c @ 358:9121a0a91f47 NGINX_0_6_23

nginx 0.6.23 *) Change: the "off" parameter in the "ssl_session_cache" directive; now this is default parameter. *) Change: the "open_file_cache_retest" directive was renamed to the "open_file_cache_valid". *) Feature: the "open_file_cache_min_uses" directive. *) Feature: the ngx_http_gzip_static_module. *) Feature: the "gzip_disable" directive. *) Feature: the "memcached_pass" directive may be used inside the "if" block. *) Bugfix: a segmentation fault occurred in worker process, if the "memcached_pass" and "if" directives were used in the same location. *) Bugfix: if a "satisfy_any on" directive was used and not all access and auth modules directives were set, then other given access and auth directives were not tested; *) Bugfix: regex parameters in a "valid_referers" directive were not inherited from previous level. *) Bugfix: a "post_action" directive did run if a request was completed with 499 status code. *) Bugfix: optimization of 16K buffer usage in a SSL connection. Thanks to Ben Maurer. *) Bugfix: the STARTTLS in SMTP mode did not work. Thanks to Oleg Motienko. *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" error; bug appeared in 0.5.13.
author Igor Sysoev <http://sysoev.ru>
date Thu, 27 Dec 2007 00:00:00 +0300
parents b743d290eb3b
children 9a242235a80a
comparison
equal deleted inserted replaced
357:16d557a75356 358:9121a0a91f47
16 * files and directories errors: not found, access denied, etc. 16 * files and directories errors: not found, access denied, etc.
17 */ 17 */
18 18
19 19
20 static void ngx_open_file_cache_cleanup(void *data); 20 static void ngx_open_file_cache_cleanup(void *data);
21 static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,
22 ngx_log_t *log);
23 static void ngx_open_file_add_event(ngx_open_file_cache_t *cache,
24 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log);
21 static void ngx_open_file_cleanup(void *data); 25 static void ngx_open_file_cleanup(void *data);
22 static void ngx_close_cached_file(ngx_open_file_cache_t *cache, 26 static void ngx_close_cached_file(ngx_open_file_cache_t *cache,
23 ngx_cached_open_file_t *file, ngx_log_t *log); 27 ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log);
24 static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, 28 static void ngx_open_file_del_event(ngx_cached_open_file_t *file);
25 ngx_log_t *log);
26 static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, 29 static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache,
27 ngx_uint_t n, ngx_log_t *log); 30 ngx_uint_t n, ngx_log_t *log);
28 static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, 31 static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
29 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); 32 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
33 static ngx_cached_open_file_t *
34 ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name,
35 uint32_t hash);
30 static void ngx_open_file_cache_remove(ngx_event_t *ev); 36 static void ngx_open_file_cache_remove(ngx_event_t *ev);
31 37
32 38
33 ngx_open_file_cache_t * 39 ngx_open_file_cache_t *
34 ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive) 40 ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive)
35 { 41 {
36 ngx_rbtree_node_t *sentinel;
37 ngx_pool_cleanup_t *cln; 42 ngx_pool_cleanup_t *cln;
38 ngx_open_file_cache_t *cache; 43 ngx_open_file_cache_t *cache;
39 44
40 cache = ngx_palloc(pool, sizeof(ngx_open_file_cache_t)); 45 cache = ngx_palloc(pool, sizeof(ngx_open_file_cache_t));
41 if (cache == NULL) { 46 if (cache == NULL) {
42 return NULL; 47 return NULL;
43 } 48 }
44 49
45 cache->list_head.prev = NULL; 50 ngx_rbtree_init(&cache->rbtree, &cache->sentinel,
46 cache->list_head.next = &cache->list_tail;
47
48 cache->list_tail.prev = &cache->list_head;
49 cache->list_tail.next = NULL;
50
51 sentinel = ngx_palloc(pool, sizeof(ngx_rbtree_node_t));
52 if (sentinel == NULL) {
53 return NULL;
54 }
55
56 ngx_rbtree_init(&cache->rbtree, sentinel,
57 ngx_open_file_cache_rbtree_insert_value); 51 ngx_open_file_cache_rbtree_insert_value);
52
53 ngx_queue_init(&cache->expire_queue);
58 54
59 cache->current = 0; 55 cache->current = 0;
60 cache->max = max; 56 cache->max = max;
61 cache->inactive = inactive; 57 cache->inactive = inactive;
62 58
75 static void 71 static void
76 ngx_open_file_cache_cleanup(void *data) 72 ngx_open_file_cache_cleanup(void *data)
77 { 73 {
78 ngx_open_file_cache_t *cache = data; 74 ngx_open_file_cache_t *cache = data;
79 75
76 ngx_queue_t *q;
80 ngx_cached_open_file_t *file; 77 ngx_cached_open_file_t *file;
81 78
82 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, 79 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
83 "open file cache cleanup"); 80 "open file cache cleanup");
84 81
85 for ( ;; ) { 82 for ( ;; ) {
86 83
87 file = cache->list_tail.prev; 84 if (ngx_queue_empty(&cache->expire_queue)) {
88
89 if (file == &cache->list_head) {
90 break; 85 break;
91 } 86 }
92 87
93 file->next->prev = file->prev; 88 q = ngx_queue_last(&cache->expire_queue);
94 file->prev->next = file->next; 89
90 file = ngx_queue_data(q, ngx_cached_open_file_t, queue);
91
92 ngx_queue_remove(q);
95 93
96 ngx_rbtree_delete(&cache->rbtree, &file->node); 94 ngx_rbtree_delete(&cache->rbtree, &file->node);
97 95
98 cache->current--; 96 cache->current--;
99 97
101 "delete cached open file: %s", file->name); 99 "delete cached open file: %s", file->name);
102 100
103 if (!file->err && !file->is_dir) { 101 if (!file->err && !file->is_dir) {
104 file->close = 1; 102 file->close = 1;
105 file->count = 0; 103 file->count = 0;
106 ngx_close_cached_file(cache, file, ngx_cycle->log); 104 ngx_close_cached_file(cache, file, 0, ngx_cycle->log);
107 105
108 } else { 106 } else {
109 ngx_free(file->name); 107 ngx_free(file->name);
110 ngx_free(file); 108 ngx_free(file);
111 } 109 }
130 ngx_open_file_info_t *of, ngx_pool_t *pool) 128 ngx_open_file_info_t *of, ngx_pool_t *pool)
131 { 129 {
132 time_t now; 130 time_t now;
133 uint32_t hash; 131 uint32_t hash;
134 ngx_int_t rc; 132 ngx_int_t rc;
135 ngx_rbtree_node_t *node, *sentinel;
136 ngx_pool_cleanup_t *cln; 133 ngx_pool_cleanup_t *cln;
137 ngx_cached_open_file_t *file; 134 ngx_cached_open_file_t *file;
138 ngx_pool_cleanup_file_t *clnf; 135 ngx_pool_cleanup_file_t *clnf;
139 ngx_open_file_cache_event_t *fev;
140 ngx_open_file_cache_cleanup_t *ofcln; 136 ngx_open_file_cache_cleanup_t *ofcln;
141 137
142 of->err = 0; 138 of->err = 0;
143 139
144 if (cache == NULL) { 140 if (cache == NULL) {
165 cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t)); 161 cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t));
166 if (cln == NULL) { 162 if (cln == NULL) {
167 return NGX_ERROR; 163 return NGX_ERROR;
168 } 164 }
169 165
166 now = ngx_time();
167
170 hash = ngx_crc32_long(name->data, name->len); 168 hash = ngx_crc32_long(name->data, name->len);
171 169
172 node = cache->rbtree.root; 170 file = ngx_open_file_lookup(cache, name, hash);
173 sentinel = cache->rbtree.sentinel; 171
174 172 if (file) {
175 now = ngx_time(); 173
176 174 file->uses++;
177 while (node != sentinel) { 175
178 176 ngx_queue_remove(&file->queue);
179 if (hash < node->key) { 177
180 node = node->left; 178 if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) {
181 continue; 179
182 } 180 /* file was not used often enough to keep open */
183 181
184 if (hash > node->key) { 182 rc = ngx_open_and_stat_file(name->data, of, pool->log);
185 node = node->right; 183
186 continue; 184 if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
187 } 185 goto failed;
188 186 }
189 /* hash == node->key */ 187
190 188 goto add_event;
191 do { 189 }
192 file = (ngx_cached_open_file_t *) node; 190
193 191 if ((file->event && file->use_event)
194 rc = ngx_strcmp(name->data, file->name); 192 || (file->event == NULL && now - file->created < of->valid))
195 193 {
196 if (rc == 0) { 194 if (file->err == 0) {
197 195
198 file->next->prev = file->prev; 196 of->fd = file->fd;
199 file->prev->next = file->next; 197 of->uniq = file->uniq;
200 198 of->mtime = file->mtime;
201 if (file->event || now - file->created < of->retest) { 199 of->size = file->size;
202 if (file->err == 0) { 200
203 of->fd = file->fd; 201 of->is_dir = file->is_dir;
204 of->uniq = file->uniq; 202 of->is_file = file->is_file;
205 of->mtime = file->mtime; 203 of->is_link = file->is_link;
206 of->size = file->size; 204 of->is_exec = file->is_exec;
207 205
208 of->is_dir = file->is_dir; 206 if (!file->is_dir) {
209 of->is_file = file->is_file; 207 file->count++;
210 of->is_link = file->is_link; 208 ngx_open_file_add_event(cache, file, of, pool->log);
211 of->is_exec = file->is_exec;
212
213 if (!file->is_dir) {
214 file->count++;
215 }
216
217 } else {
218 of->err = file->err;
219 }
220
221 goto found;
222 } 209 }
223 210
224 ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, 211 } else {
225 "retest open file: %s, fd:%d, c:%d, e:%d", 212 of->err = file->err;
226 file->name, file->fd, file->count, file->err); 213 }
227 214
228 if (file->is_dir) { 215 goto found;
229 216 }
230 /* 217
231 * chances that directory became file are very small 218 ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
232 * so test_dir flag allows to use a single ngx_file_info() 219 "retest open file: %s, fd:%d, c:%d, e:%d",
233 * syscall instead of three syscalls 220 file->name, file->fd, file->count, file->err);
234 */ 221
235 222 if (file->is_dir) {
236 of->test_dir = 1; 223
224 /*
225 * chances that directory became file are very small
226 * so test_dir flag allows to use a single syscall
227 * in ngx_file_info() instead of three syscalls
228 */
229
230 of->test_dir = 1;
231 }
232
233 rc = ngx_open_and_stat_file(name->data, of, pool->log);
234
235 if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
236 goto failed;
237 }
238
239 if (of->is_dir) {
240
241 if (file->is_dir || file->err) {
242 goto update;
243 }
244
245 /* file became directory */
246
247 } else if (of->err == 0) { /* file */
248
249 if (file->is_dir || file->err) {
250 goto add_event;
251 }
252
253 if (of->uniq == file->uniq
254 && of->mtime == file->mtime
255 && of->size == file->size)
256 {
257 if (ngx_close_file(of->fd) == NGX_FILE_ERROR) {
258 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
259 ngx_close_file_n " \"%s\" failed",
260 name->data);
237 } 261 }
238 262
239 rc = ngx_open_and_stat_file(name->data, of, pool->log); 263 of->fd = file->fd;
240 264 file->count++;
241 if (rc != NGX_OK && (of->err == 0 || !of->errors)) { 265
242 goto failed; 266 if (file->event) {
267 file->use_event = 1;
268 goto renew;
243 } 269 }
244 270
245 if (of->is_dir) { 271 ngx_open_file_add_event(cache, file, of, pool->log);
246 if (file->is_dir || file->err) { 272
247 goto update; 273 goto renew;
248 }
249
250 /* file became directory */
251
252 } else if (of->err == 0) { /* file */
253
254 if (file->is_dir || file->err) {
255 goto update;
256 }
257
258 if (of->uniq == file->uniq
259 && of->mtime == file->mtime
260 && of->size == file->size)
261 {
262 if (ngx_close_file(of->fd) == NGX_FILE_ERROR) {
263 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
264 ngx_close_file_n " \"%s\" failed",
265 name->data);
266 }
267
268 of->fd = file->fd;
269 file->count++;
270
271 goto renew;
272 }
273
274 /* file was changed */
275
276 } else { /* error to cache */
277
278 if (file->err || file->is_dir) {
279 goto update;
280 }
281
282 /* file was removed, etc. */
283 }
284
285 if (file->count == 0) {
286 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
287 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
288 ngx_close_file_n " \"%s\" failed",
289 name->data);
290 }
291
292 goto update;
293 }
294
295 ngx_rbtree_delete(&cache->rbtree, &file->node);
296
297 cache->current--;
298
299 file->close = 1;
300
301 goto create;
302 } 274 }
303 275
304 node = (rc < 0) ? node->left : node->right; 276 /* file was changed */
305 277
306 } while (node != sentinel && hash == node->key); 278 } else { /* error to cache */
307 279
308 break; 280 if (file->err || file->is_dir) {
281 goto update;
282 }
283
284 /* file was removed, etc. */
285 }
286
287 if (file->count == 0) {
288
289 ngx_open_file_del_event(file);
290
291 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
292 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
293 ngx_close_file_n " \"%s\" failed",
294 name->data);
295 }
296
297 goto add_event;
298 }
299
300 ngx_rbtree_delete(&cache->rbtree, &file->node);
301
302 cache->current--;
303
304 file->close = 1;
305
306 goto create;
309 } 307 }
310 308
311 /* not found */ 309 /* not found */
312 310
313 file = NULL; 311 file = NULL;
344 342
345 ngx_rbtree_insert(&cache->rbtree, &file->node); 343 ngx_rbtree_insert(&cache->rbtree, &file->node);
346 344
347 cache->current++; 345 cache->current++;
348 346
347 file->uses = 1;
349 file->count = 0; 348 file->count = 0;
349 file->use_event = 0;
350 file->event = NULL;
351
352 add_event:
353
354 ngx_open_file_add_event(cache, file, of, pool->log);
350 355
351 update: 356 update:
352
353 if (of->events
354 && (ngx_event_flags & NGX_USE_VNODE_EVENT)
355 && of->fd != NGX_INVALID_FILE)
356 {
357 file->event = ngx_calloc(sizeof(ngx_event_t), pool->log);
358 if (file->event== NULL) {
359 goto failed;
360 }
361
362 fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), pool->log);
363 if (fev == NULL) {
364 goto failed;
365 }
366
367 fev->fd = of->fd;
368 fev->file = file;
369 fev->cache = cache;
370
371 file->event->handler = ngx_open_file_cache_remove;
372 file->event->data = fev;
373
374 /*
375 * although vnode event may be called while ngx_cycle->poll
376 * destruction; however, cleanup procedures are run before any
377 * memory freeing and events will be canceled.
378 */
379
380 file->event->log = ngx_cycle->log;
381
382 if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT)
383 != NGX_OK)
384 {
385 ngx_free(file->event->data);
386 ngx_free(file->event);
387 goto failed;
388 }
389
390 } else {
391 file->event = NULL;
392 }
393 357
394 file->fd = of->fd; 358 file->fd = of->fd;
395 file->err = of->err; 359 file->err = of->err;
396 360
397 if (of->err == 0) { 361 if (of->err == 0) {
417 381
418 found: 382 found:
419 383
420 file->accessed = now; 384 file->accessed = now;
421 385
422 /* add to the inactive list head */ 386 ngx_queue_insert_head(&cache->expire_queue, &file->queue);
423 387
424 file->next = cache->list_head.next; 388 ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0,
425 file->next->prev = file; 389 "cached open file: %s, fd:%d, c:%d, e:%d, u:%d",
426 file->prev = &cache->list_head; 390 file->name, file->fd, file->count, file->err, file->uses);
427 cache->list_head.next = file;
428
429 ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
430 "cached open file: %s, fd:%d, c:%d, e:%d",
431 file->name, file->fd, file->count, file->err);
432 391
433 if (of->err == 0) { 392 if (of->err == 0) {
434 393
435 if (!of->is_dir) { 394 if (!of->is_dir) {
436 cln->handler = ngx_open_file_cleanup; 395 cln->handler = ngx_open_file_cleanup;
437 ofcln = cln->data; 396 ofcln = cln->data;
438 397
439 ofcln->cache = cache; 398 ofcln->cache = cache;
440 ofcln->file = file; 399 ofcln->file = file;
400 ofcln->min_uses = of->min_uses;
441 ofcln->log = pool->log; 401 ofcln->log = pool->log;
442 } 402 }
443 403
444 return NGX_OK; 404 return NGX_OK;
445 } 405 }
541 501
542 return NGX_OK; 502 return NGX_OK;
543 } 503 }
544 504
545 505
506 /*
507 * we ignore any possible event setting error and
508 * fallback to usual periodic file retests
509 */
510
546 static void 511 static void
547 ngx_open_file_cleanup(void *data) 512 ngx_open_file_add_event(ngx_open_file_cache_t *cache,
548 { 513 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log)
549 ngx_open_file_cache_cleanup_t *c = data; 514 {
550 515 ngx_open_file_cache_event_t *fev;
551 c->file->count--; 516
552 517 if (!(ngx_event_flags & NGX_USE_VNODE_EVENT)
553 ngx_close_cached_file(c->cache, c->file, c->log); 518 || !of->events
554 519 || file->event
555 /* drop one or two expired open files */ 520 || of->fd == NGX_INVALID_FILE
556 ngx_expire_old_cached_files(c->cache, 1, c->log); 521 || file->uses < of->min_uses)
557 } 522 {
558
559
560 static void
561 ngx_close_cached_file(ngx_open_file_cache_t *cache,
562 ngx_cached_open_file_t *file, ngx_log_t *log)
563 {
564 ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0,
565 "close cached open file: %s, fd:%d, c:%d, %d",
566 file->name, file->fd, file->count, file->close);
567
568 if (!file->close) {
569
570 file->accessed = ngx_time();
571
572 if (cache->list_head.next != file) {
573
574 /* delete from inactive list */
575
576 file->next->prev = file->prev;
577 file->prev->next = file->next;
578
579 /* add to the inactive list head */
580
581 file->next = cache->list_head.next;
582 file->next->prev = file;
583 file->prev = &cache->list_head;
584 cache->list_head.next = file;
585 }
586
587 return; 523 return;
588 } 524 }
589 525
590 if (file->event) { 526 file->event = ngx_calloc(sizeof(ngx_event_t), log);
591 (void) ngx_del_event(file->event, NGX_VNODE_EVENT, 527 if (file->event== NULL) {
592 file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT); 528 return;
593 529 }
530
531 fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log);
532 if (fev == NULL) {
533 ngx_free(file->event);
534 file->event = NULL;
535 return;
536 }
537
538 fev->fd = of->fd;
539 fev->file = file;
540 fev->cache = cache;
541
542 file->event->handler = ngx_open_file_cache_remove;
543 file->event->data = fev;
544
545 /*
546 * although vnode event may be called while ngx_cycle->poll
547 * destruction, however, cleanup procedures are run before any
548 * memory freeing and events will be canceled.
549 */
550
551 file->event->log = ngx_cycle->log;
552
553 if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT)
554 != NGX_OK)
555 {
594 ngx_free(file->event->data); 556 ngx_free(file->event->data);
595 ngx_free(file->event); 557 ngx_free(file->event);
596 file->event = NULL; 558 file->event = NULL;
597 } 559 return;
560 }
561
562 /*
563 * we do not file->use_event here because there may be a race
564 * condition between opening file and adding event, so we rely
565 * upon event notification only after first file revalidation
566 */
567
568 return;
569 }
570
571
572 static void
573 ngx_open_file_cleanup(void *data)
574 {
575 ngx_open_file_cache_cleanup_t *c = data;
576
577 c->file->count--;
578
579 ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log);
580
581 /* drop one or two expired open files */
582 ngx_expire_old_cached_files(c->cache, 1, c->log);
583 }
584
585
586 static void
587 ngx_close_cached_file(ngx_open_file_cache_t *cache,
588 ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log)
589 {
590 ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0,
591 "close cached open file: %s, fd:%d, c:%d, u:%d, %d",
592 file->name, file->fd, file->count, file->uses, file->close);
593
594 if (!file->close) {
595
596 file->accessed = ngx_time();
597
598 ngx_queue_remove(&file->queue);
599
600 ngx_queue_insert_head(&cache->expire_queue, &file->queue);
601
602 if (file->uses >= min_uses || file->count) {
603 return;
604 }
605 }
606
607 ngx_open_file_del_event(file);
598 608
599 if (file->count) { 609 if (file->count) {
600 return; 610 return;
601 } 611 }
602 612
603 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { 613 if (file->fd != NGX_INVALID_FILE) {
604 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, 614
605 ngx_close_file_n " \"%s\" failed", file->name); 615 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
616 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
617 ngx_close_file_n " \"%s\" failed", file->name);
618 }
619
620 file->fd = NGX_INVALID_FILE;
621 }
622
623 if (!file->close) {
624 return;
606 } 625 }
607 626
608 ngx_free(file->name); 627 ngx_free(file->name);
609 ngx_free(file); 628 ngx_free(file);
629 }
630
631
632 static void
633 ngx_open_file_del_event(ngx_cached_open_file_t *file)
634 {
635 if (file->event == NULL) {
636 return;
637 }
638
639 (void) ngx_del_event(file->event, NGX_VNODE_EVENT,
640 file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT);
641
642 ngx_free(file->event->data);
643 ngx_free(file->event);
644 file->event = NULL;
645 file->use_event = 0;
610 } 646 }
611 647
612 648
613 static void 649 static void
614 ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, 650 ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n,
615 ngx_log_t *log) 651 ngx_log_t *log)
616 { 652 {
617 time_t now; 653 time_t now;
654 ngx_queue_t *q;
618 ngx_cached_open_file_t *file; 655 ngx_cached_open_file_t *file;
619 656
620 now = ngx_time(); 657 now = ngx_time();
621 658
622 /* 659 /*
625 * and one or two inactive files 662 * and one or two inactive files
626 */ 663 */
627 664
628 while (n < 3) { 665 while (n < 3) {
629 666
630 file = cache->list_tail.prev; 667 if (ngx_queue_empty(&cache->expire_queue)) {
631
632 if (file == &cache->list_head) {
633 return; 668 return;
634 } 669 }
670
671 q = ngx_queue_last(&cache->expire_queue);
672
673 file = ngx_queue_data(q, ngx_cached_open_file_t, queue);
635 674
636 if (n++ != 0 && now - file->accessed <= cache->inactive) { 675 if (n++ != 0 && now - file->accessed <= cache->inactive) {
637 return; 676 return;
638 } 677 }
639 678
640 file->next->prev = file->prev; 679 ngx_queue_remove(q);
641 file->prev->next = file->next;
642 680
643 ngx_rbtree_delete(&cache->rbtree, &file->node); 681 ngx_rbtree_delete(&cache->rbtree, &file->node);
644 682
645 cache->current--; 683 cache->current--;
646 684
647 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, 685 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
648 "expire cached open file: %s", file->name); 686 "expire cached open file: %s", file->name);
649 687
650 if (!file->err && !file->is_dir) { 688 if (!file->err && !file->is_dir) {
651 file->close = 1; 689 file->close = 1;
652 ngx_close_cached_file(cache, file, log); 690 ngx_close_cached_file(cache, file, 0, log);
653 691
654 } else { 692 } else {
655 ngx_free(file->name); 693 ngx_free(file->name);
656 ngx_free(file); 694 ngx_free(file);
657 } 695 }
698 node->right = sentinel; 736 node->right = sentinel;
699 ngx_rbt_red(node); 737 ngx_rbt_red(node);
700 } 738 }
701 739
702 740
741 static ngx_cached_open_file_t *
742 ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name,
743 uint32_t hash)
744 {
745 ngx_int_t rc;
746 ngx_rbtree_node_t *node, *sentinel;
747 ngx_cached_open_file_t *file;
748
749 node = cache->rbtree.root;
750 sentinel = cache->rbtree.sentinel;
751
752 while (node != sentinel) {
753
754 if (hash < node->key) {
755 node = node->left;
756 continue;
757 }
758
759 if (hash > node->key) {
760 node = node->right;
761 continue;
762 }
763
764 /* hash == node->key */
765
766 do {
767 file = (ngx_cached_open_file_t *) node;
768
769 rc = ngx_strcmp(name->data, file->name);
770
771 if (rc == 0) {
772 return file;
773 }
774
775 node = (rc < 0) ? node->left : node->right;
776
777 } while (node != sentinel && hash == node->key);
778
779 break;
780 }
781
782 return NULL;
783 }
784
785
703 static void 786 static void
704 ngx_open_file_cache_remove(ngx_event_t *ev) 787 ngx_open_file_cache_remove(ngx_event_t *ev)
705 { 788 {
706 ngx_cached_open_file_t *file; 789 ngx_cached_open_file_t *file;
707 ngx_open_file_cache_event_t *fev; 790 ngx_open_file_cache_event_t *fev;
708 791
709 fev = ev->data; 792 fev = ev->data;
710 file = fev->file; 793 file = fev->file;
711 794
712 file->next->prev = file->prev; 795 ngx_queue_remove(&file->queue);
713 file->prev->next = file->next;
714 796
715 ngx_rbtree_delete(&fev->cache->rbtree, &file->node); 797 ngx_rbtree_delete(&fev->cache->rbtree, &file->node);
716 798
717 fev->cache->current--; 799 fev->cache->current--;
718 800
719 /* NGX_ONESHOT_EVENT was already deleted */ 801 /* NGX_ONESHOT_EVENT was already deleted */
720 file->event = NULL; 802 file->event = NULL;
721 803
722 file->close = 1; 804 file->close = 1;
723 805
724 ngx_close_cached_file(fev->cache, file, ev->log); 806 ngx_close_cached_file(fev->cache, file, 0, ev->log);
725 807
726 /* free memory only when fev->cache and fev->file are already not needed */ 808 /* free memory only when fev->cache and fev->file are already not needed */
727 809
728 ngx_free(ev->data); 810 ngx_free(ev->data);
729 ngx_free(ev); 811 ngx_free(ev);