~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/ngx_http_file_cache.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 #include <ngx_http.h>
 10 #include <ngx_md5.h>
 11 
 12 
 13 static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
 14     ngx_http_cache_t *c);
 15 #if (NGX_HAVE_FILE_AIO)
 16 static void ngx_http_cache_aio_event_handler(ngx_event_t *ev);
 17 #endif
 18 static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
 19     ngx_http_cache_t *c);
 20 static ngx_http_file_cache_node_t *
 21     ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
 22 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
 23     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 24 static void ngx_http_file_cache_cleanup(void *data);
 25 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
 26 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
 27 static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache,
 28     ngx_queue_t *q, u_char *name);
 29 static ngx_int_t
 30     ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache);
 31 static ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx,
 32     ngx_str_t *path);
 33 static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx,
 34     ngx_str_t *path);
 35 static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx,
 36     ngx_str_t *path);
 37 static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache,
 38     ngx_http_cache_t *c);
 39 static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx,
 40     ngx_str_t *path);
 41 
 42 
 43 ngx_str_t  ngx_http_cache_status[] = {
 44     ngx_string("MISS"),
 45     ngx_string("EXPIRED"),
 46     ngx_string("STALE"),
 47     ngx_string("UPDATING"),
 48     ngx_string("HIT")
 49 };
 50 
 51 
 52 static u_char  ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' };
 53 
 54 
 55 static ngx_int_t
 56 ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data)
 57 {
 58     ngx_http_file_cache_t  *ocache = data;
 59 
 60     size_t                  len;
 61     ngx_uint_t              n;
 62     ngx_http_file_cache_t  *cache;
 63 
 64     cache = shm_zone->data;
 65 
 66     if (ocache) {
 67         if (ngx_strcmp(cache->path->name.data, ocache->path->name.data) != 0) {
 68             ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
 69                           "cache \"%V\" uses the \"%V\" cache path "
 70                           "while previously it used the \"%V\" cache path",
 71                           &shm_zone->shm.name, &cache->path->name,
 72                           &ocache->path->name);
 73 
 74             return NGX_ERROR;
 75         }
 76 
 77         for (n = 0; n < 3; n++) {
 78             if (cache->path->level[n] != ocache->path->level[n]) {
 79                 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
 80                               "cache \"%V\" had previously different levels",
 81                               &shm_zone->shm.name);
 82                 return NGX_ERROR;
 83             }
 84         }
 85 
 86         cache->sh = ocache->sh;
 87 
 88         cache->shpool = ocache->shpool;
 89         cache->bsize = ocache->bsize;
 90 
 91         cache->max_size /= cache->bsize;
 92 
 93         if (!cache->sh->cold || cache->sh->loading) {
 94             cache->path->loader = NULL;
 95         }
 96 
 97         return NGX_OK;
 98     }
 99 
100     cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
101 
102     if (shm_zone->shm.exists) {
103         cache->sh = cache->shpool->data;
104         cache->bsize = ngx_fs_bsize(cache->path->name.data);
105 
106         return NGX_OK;
107     }
108 
109     cache->sh = ngx_slab_alloc(cache->shpool, sizeof(ngx_http_file_cache_sh_t));
110     if (cache->sh == NULL) {
111         return NGX_ERROR;
112     }
113 
114     cache->shpool->data = cache->sh;
115 
116     ngx_rbtree_init(&cache->sh->rbtree, &cache->sh->sentinel,
117                     ngx_http_file_cache_rbtree_insert_value);
118 
119     ngx_queue_init(&cache->sh->queue);
120 
121     cache->sh->cold = 1;
122     cache->sh->loading = 0;
123     cache->sh->size = 0;
124 
125     cache->bsize = ngx_fs_bsize(cache->path->name.data);
126 
127     cache->max_size /= cache->bsize;
128 
129     len = sizeof(" in cache keys zone \"\"") + shm_zone->shm.name.len;
130 
131     cache->shpool->log_ctx = ngx_slab_alloc(cache->shpool, len);
132     if (cache->shpool->log_ctx == NULL) {
133         return NGX_ERROR;
134     }
135 
136     ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z",
137                 &shm_zone->shm.name);
138 
139     return NGX_OK;
140 }
141 
142 
143 void
144 ngx_http_file_cache_create_key(ngx_http_request_t *r)
145 {
146     size_t             len;
147     ngx_str_t         *key;
148     ngx_uint_t         i;
149     ngx_md5_t          md5;
150     ngx_http_cache_t  *c;
151 
152     c = r->cache;
153 
154     len = 0;
155 
156     ngx_crc32_init(c->crc32);
157     ngx_md5_init(&md5);
158 
159     key = c->keys.elts;
160     for (i = 0; i < c->keys.nelts; i++) {
161         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
162                        "http cache key: \"%V\"", &key[i]);
163 
164         len += key[i].len;
165 
166         ngx_crc32_update(&c->crc32, key[i].data, key[i].len);
167         ngx_md5_update(&md5, key[i].data, key[i].len);
168     }
169 
170     c->header_start = sizeof(ngx_http_file_cache_header_t)
171                       + sizeof(ngx_http_file_cache_key) + len + 1;
172 
173     ngx_crc32_final(c->crc32);
174     ngx_md5_final(c->key, &md5);
175 }
176 
177 
178 ngx_int_t
179 ngx_http_file_cache_open(ngx_http_request_t *r)
180 {
181     u_char                    *p;
182     ngx_int_t                  rc, rv;
183     ngx_uint_t                 cold, test;
184     ngx_path_t                *path;
185     ngx_http_cache_t          *c;
186     ngx_pool_cleanup_t        *cln;
187     ngx_open_file_info_t       of;
188     ngx_http_file_cache_t     *cache;
189     ngx_http_core_loc_conf_t  *clcf;
190 
191     c = r->cache;
192 
193     if (c->buf) {
194         return ngx_http_file_cache_read(r, c);
195     }
196 
197     cache = c->file_cache;
198 
199     cln = ngx_pool_cleanup_add(r->pool, 0);
200     if (cln == NULL) {
201         return NGX_ERROR;
202     }
203 
204     rc = ngx_http_file_cache_exists(cache, c);
205 
206     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
207                    "http file cache exists: %i e:%d", rc, c->exists);
208 
209     if (rc == NGX_ERROR) {
210         return rc;
211     }
212 
213     cln->handler = ngx_http_file_cache_cleanup;
214     cln->data = c;
215 
216     if (rc == NGX_AGAIN) {
217         return NGX_HTTP_CACHE_SCARCE;
218     }
219 
220     cold = cache->sh->cold;
221 
222     if (rc == NGX_OK) {
223 
224         if (c->error) {
225             return c->error;
226         }
227 
228         c->temp_file = 1;
229         test = c->exists ? 1 : 0;
230         rv = NGX_DECLINED;
231 
232     } else { /* rc == NGX_DECLINED */
233 
234         if (c->min_uses > 1) {
235 
236             if (!cold) {
237                 return NGX_HTTP_CACHE_SCARCE;
238             }
239 
240             test = 1;
241             rv = NGX_HTTP_CACHE_SCARCE;
242 
243         } else {
244             c->temp_file = 1;
245             test = cold ? 1 : 0;
246             rv = NGX_DECLINED;
247         }
248     }
249 
250     path = cache->path;
251 
252     c->file.name.len = path->name.len + 1 + path->len
253                        + 2 * NGX_HTTP_CACHE_KEY_LEN;
254 
255     c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1);
256     if (c->file.name.data == NULL) {
257         return NGX_ERROR;
258     }
259 
260     ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
261 
262     p = c->file.name.data + path->name.len + 1 + path->len;
263     p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN);
264     *p = '\0';
265 
266     ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len);
267 
268     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
269                    "cache file: \"%s\"", c->file.name.data);
270 
271     if (!test) {
272         return NGX_DECLINED;
273     }
274 
275     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
276 
277     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
278 
279     of.uniq = c->uniq;
280     of.valid = clcf->open_file_cache_valid;
281     of.min_uses = clcf->open_file_cache_min_uses;
282     of.events = clcf->open_file_cache_events;
283     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
284     of.read_ahead = clcf->read_ahead;
285 
286     if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool)
287         != NGX_OK)
288     {
289         switch (of.err) {
290 
291         case 0:
292             return NGX_ERROR;
293 
294         case NGX_ENOENT:
295         case NGX_ENOTDIR:
296             return rv;
297 
298         default:
299             ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
300                           ngx_open_file_n " \"%s\" failed", c->file.name.data);
301             return NGX_ERROR;
302         }
303     }
304 
305     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
306                    "http file cache fd: %d", of.fd);
307 
308     c->file.fd = of.fd;
309     c->file.log = r->connection->log;
310     c->uniq = of.uniq;
311     c->length = of.size;
312 
313     c->buf = ngx_create_temp_buf(r->pool, c->body_start);
314     if (c->buf == NULL) {
315         return NGX_ERROR;
316     }
317 
318     return ngx_http_file_cache_read(r, c);
319 }
320 
321 
322 static ngx_int_t
323 ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c)
324 {
325     time_t                         now;
326     ssize_t                        n;
327     ngx_int_t                      rc;
328     ngx_http_file_cache_t         *cache;
329     ngx_http_file_cache_header_t  *h;
330 
331     c = r->cache;
332 
333 #if (NGX_HAVE_FILE_AIO)
334     {
335     ngx_http_core_loc_conf_t      *clcf;
336 
337     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
338 
339     if (clcf->aio) {
340         n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
341 
342         if (n == NGX_AGAIN) {
343             c->file.aio->data = r;
344             c->file.aio->handler = ngx_http_cache_aio_event_handler;
345 
346             r->main->blocked++;
347             r->aio = 1;
348 
349             return NGX_AGAIN;
350         }
351 
352     } else {
353         n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
354     }
355     }
356 #else
357 
358     n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
359 
360 #endif
361 
362     if (n == NGX_ERROR) {
363         return n;
364     }
365 
366     if ((size_t) n <= c->header_start) {
367         ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
368                       "cache file \"%s\" is too small", c->file.name.data);
369         return NGX_ERROR;
370     }
371 
372     h = (ngx_http_file_cache_header_t *) c->buf->pos;
373 
374     if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) {
375         ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
376                       "cache file \"%s\" has md5 collision", c->file.name.data);
377         return NGX_DECLINED;
378     }
379 
380     c->buf->last += n;
381 
382     c->valid_sec = h->valid_sec;
383     c->last_modified = h->last_modified;
384     c->date = h->date;
385     c->valid_msec = h->valid_msec;
386     c->body_start = h->body_start;
387 
388     r->cached = 1;
389 
390     cache = c->file_cache;
391 
392     if (cache->sh->cold) {
393 
394         ngx_shmtx_lock(&cache->shpool->mutex);
395 
396         if (!c->node->exists) {
397             c->node->uses = 1;
398             c->node->body_start = c->body_start;
399             c->node->exists = 1;
400             c->node->uniq = c->uniq;
401 
402             cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
403         }
404 
405         ngx_shmtx_unlock(&cache->shpool->mutex);
406     }
407 
408     now = ngx_time();
409 
410     if (c->valid_sec < now) {
411 
412         ngx_shmtx_lock(&cache->shpool->mutex);
413 
414         if (c->node->updating) {
415             rc = NGX_HTTP_CACHE_UPDATING;
416 
417         } else {
418             c->node->updating = 1;
419             rc = NGX_HTTP_CACHE_STALE;
420         }
421 
422         ngx_shmtx_unlock(&cache->shpool->mutex);
423 
424         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
425                        "http file cache expired: %i %T %T",
426                        rc, c->valid_sec, now);
427 
428         return rc;
429     }
430 
431     return NGX_OK;
432 }
433 
434 
435 #if (NGX_HAVE_FILE_AIO)
436 
437 
438 static void
439 ngx_http_cache_aio_event_handler(ngx_event_t *ev)
440 {
441     ngx_event_aio_t     *aio;
442     ngx_http_request_t  *r;
443 
444     aio = ev->data;
445     r = aio->data;
446 
447     r->main->blocked--;
448     r->aio = 0;
449 
450     r->connection->write->handler(r->connection->write);
451 }
452 
453 #endif
454 
455 
456 static ngx_int_t
457 ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
458 {
459     ngx_int_t                    rc;
460     ngx_http_file_cache_node_t  *fcn;
461 
462     ngx_shmtx_lock(&cache->shpool->mutex);
463 
464     fcn = ngx_http_file_cache_lookup(cache, c->key);
465 
466     if (fcn) {
467         ngx_queue_remove(&fcn->queue);
468 
469         if (fcn->error) {
470 
471             if (fcn->valid_sec < ngx_time()) {
472                 goto renew;
473             }
474 
475             rc = NGX_OK;
476 
477             goto done;
478         }
479 
480         fcn->uses++;
481         fcn->count++;
482 
483         if (fcn->exists) {
484 
485             c->exists = fcn->exists;
486             c->body_start = fcn->body_start;
487 
488             rc = NGX_OK;
489 
490             goto done;
491         }
492 
493         if (fcn->uses >= c->min_uses) {
494 
495             c->exists = fcn->exists;
496             c->body_start = fcn->body_start;
497 
498             rc = NGX_OK;
499 
500         } else {
501             rc = NGX_AGAIN;
502         }
503 
504         goto done;
505     }
506 
507     fcn = ngx_slab_alloc_locked(cache->shpool,
508                                 sizeof(ngx_http_file_cache_node_t));
509     if (fcn == NULL) {
510         ngx_shmtx_unlock(&cache->shpool->mutex);
511 
512         (void) ngx_http_file_cache_forced_expire(cache);
513 
514         ngx_shmtx_lock(&cache->shpool->mutex);
515 
516         fcn = ngx_slab_alloc_locked(cache->shpool,
517                                     sizeof(ngx_http_file_cache_node_t));
518         if (fcn == NULL) {
519             rc = NGX_ERROR;
520             goto failed;
521         }
522     }
523 
524     ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));
525 
526     ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
527                NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
528 
529     ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
530 
531 renew:
532 
533     rc = NGX_DECLINED;
534 
535     fcn->uses = 1;
536     fcn->count = 1;
537     fcn->valid_msec = 0;
538     fcn->error = 0;
539     fcn->exists = 0;
540     fcn->valid_sec = 0;
541     fcn->uniq = 0;
542     fcn->body_start = 0;
543     fcn->length = 0;
544 
545 done:
546 
547     fcn->expire = ngx_time() + cache->inactive;
548 
549     ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
550 
551     c->uniq = fcn->uniq;
552     c->error = fcn->error;
553     c->node = fcn;
554 
555 failed:
556 
557     ngx_shmtx_unlock(&cache->shpool->mutex);
558 
559     return rc;
560 }
561 
562 
563 static ngx_http_file_cache_node_t *
564 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key)
565 {
566     ngx_int_t                    rc;
567     ngx_rbtree_key_t             node_key;
568     ngx_rbtree_node_t           *node, *sentinel;
569     ngx_http_file_cache_node_t  *fcn;
570 
571     ngx_memcpy((u_char *) &node_key, key, sizeof(ngx_rbtree_key_t));
572 
573     node = cache->sh->rbtree.root;
574     sentinel = cache->sh->rbtree.sentinel;
575 
576     while (node != sentinel) {
577 
578         if (node_key < node->key) {
579             node = node->left;
580             continue;
581         }
582 
583         if (node_key > node->key) {
584             node = node->right;
585             continue;
586         }
587 
588         /* node_key == node->key */
589 
590         do {
591             fcn = (ngx_http_file_cache_node_t *) node;
592 
593             rc = ngx_memcmp(&key[sizeof(ngx_rbtree_key_t)], fcn->key,
594                             NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
595 
596             if (rc == 0) {
597                 return fcn;
598             }
599 
600             node = (rc < 0) ? node->left : node->right;
601 
602         } while (node != sentinel && node_key == node->key);
603 
604         break;
605     }
606 
607     /* not found */
608 
609     return NULL;
610 }
611 
612 
613 static void
614 ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
615     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
616 {
617     ngx_rbtree_node_t           **p;
618     ngx_http_file_cache_node_t   *cn, *cnt;
619 
620     for ( ;; ) {
621 
622         if (node->key < temp->key) {
623 
624             p = &temp->left;
625 
626         } else if (node->key > temp->key) {
627 
628             p = &temp->right;
629 
630         } else { /* node->key == temp->key */
631 
632             cn = (ngx_http_file_cache_node_t *) node;
633             cnt = (ngx_http_file_cache_node_t *) temp;
634 
635             p = (ngx_memcmp(cn->key, cnt->key,
636                             NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t))
637                  < 0)
638                     ? &temp->left : &temp->right;
639         }
640 
641         if (*p == sentinel) {
642             break;
643         }
644 
645         temp = *p;
646     }
647 
648     *p = node;
649     node->parent = temp;
650     node->left = sentinel;
651     node->right = sentinel;
652     ngx_rbt_red(node);
653 }
654 
655 
656 void
657 ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
658 {
659     ngx_http_file_cache_header_t  *h = (ngx_http_file_cache_header_t *) buf;
660 
661     u_char            *p;
662     ngx_str_t         *key;
663     ngx_uint_t         i;
664     ngx_http_cache_t  *c;
665 
666     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
667                    "http file cache set header");
668 
669     c = r->cache;
670 
671     h->valid_sec = c->valid_sec;
672     h->last_modified = c->last_modified;
673     h->date = c->date;
674     h->crc32 = c->crc32;
675     h->valid_msec = (u_short) c->valid_msec;
676     h->header_start = (u_short) c->header_start;
677     h->body_start = (u_short) c->body_start;
678 
679     p = buf + sizeof(ngx_http_file_cache_header_t);
680 
681     p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key));
682 
683     key = c->keys.elts;
684     for (i = 0; i < c->keys.nelts; i++) {
685         p = ngx_copy(p, key[i].data, key[i].len);
686     }
687 
688     *p = LF;
689 }
690 
691 
692 void
693 ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
694 {
695     off_t                   size, length;
696     ngx_int_t               rc;
697     ngx_file_uniq_t         uniq;
698     ngx_file_info_t         fi;
699     ngx_http_cache_t        *c;
700     ngx_ext_rename_file_t   ext;
701     ngx_http_file_cache_t  *cache;
702 
703     c = r->cache;
704 
705     if (c->updated) {
706         return;
707     }
708 
709     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
710                    "http file cache update");
711 
712     c->updated = 1;
713 
714     cache = c->file_cache;
715 
716     uniq = 0;
717     length = 0;
718 
719     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
720                    "http file cache rename: \"%s\" to \"%s\"",
721                    tf->file.name.data, c->file.name.data);
722 
723     ext.access = NGX_FILE_OWNER_ACCESS;
724     ext.path_access = NGX_FILE_OWNER_ACCESS;
725     ext.time = -1;
726     ext.create_path = 1;
727     ext.delete_file = 1;
728     ext.log = r->connection->log;
729 
730     rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);
731 
732     if (rc == NGX_OK) {
733 
734         if (ngx_fd_info(tf->file.fd, &fi) == NGX_FILE_ERROR) {
735             ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
736                           ngx_fd_info_n " \"%s\" failed", tf->file.name.data);
737 
738             rc = NGX_ERROR;
739 
740         } else {
741             uniq = ngx_file_uniq(&fi);
742             length = ngx_file_size(&fi);
743         }
744     }
745 
746     size = (length + cache->bsize - 1) / cache->bsize;
747 
748     ngx_shmtx_lock(&cache->shpool->mutex);
749 
750     c->node->count--;
751     c->node->uniq = uniq;
752     c->node->body_start = c->body_start;
753 
754     size = size - (c->node->length + cache->bsize - 1) / cache->bsize;
755 
756     c->node->length = length;
757 
758     cache->sh->size += size;
759 
760     if (rc == NGX_OK) {
761         c->node->exists = 1;
762     }
763 
764     c->node->updating = 0;
765 
766     ngx_shmtx_unlock(&cache->shpool->mutex);
767 }
768 
769 
770 ngx_int_t
771 ngx_http_cache_send(ngx_http_request_t *r)
772 {
773     off_t              size;
774     ngx_int_t          rc;
775     ngx_buf_t         *b;
776     ngx_chain_t        out;
777     ngx_http_cache_t  *c;
778 
779     c = r->cache;
780 
781     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
782                   "http file cache send: %s", c->file.name.data);
783 
784     /* we need to allocate all before the header would be sent */
785 
786     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
787     if (b == NULL) {
788         return NGX_HTTP_INTERNAL_SERVER_ERROR;
789     }
790 
791     b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
792     if (b->file == NULL) {
793         return NGX_HTTP_INTERNAL_SERVER_ERROR;
794     }
795 
796     rc = ngx_http_send_header(r);
797 
798     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
799         return rc;
800     }
801 
802     size = c->length - c->body_start;
803     if (size == 0) {
804         return rc;
805     }
806 
807     b->file_pos = c->body_start;
808     b->file_last = c->length;
809 
810     b->in_file = size ? 1: 0;
811     b->last_buf = (r == r->main) ? 1: 0;
812     b->last_in_chain = 1;
813 
814     b->file->fd = c->file.fd;
815     b->file->name = c->file.name;
816     b->file->log = r->connection->log;
817 
818     out.buf = b;
819     out.next = NULL;
820 
821     return ngx_http_output_filter(r, &out);
822 }
823 
824 
825 void
826 ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf)
827 {
828     ngx_http_cache_t       *c;
829     ngx_http_file_cache_t  *cache;
830 
831     c = r->cache;
832 
833     if (c->updated) {
834         return;
835     }
836 
837     c->updated = 1;
838 
839     cache = c->file_cache;
840 
841     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
842                    "http file cache free");
843 
844     ngx_shmtx_lock(&cache->shpool->mutex);
845 
846     c->node->count--;
847 
848     if (c->error) {
849         c->node->valid_sec = c->valid_sec;
850         c->node->valid_msec = c->valid_msec;
851         c->node->error = c->error;
852     }
853 
854     c->node->updating = 0;
855 
856     ngx_shmtx_unlock(&cache->shpool->mutex);
857 
858     if (c->temp_file) {
859         if (tf && tf->file.fd != NGX_INVALID_FILE) {
860             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
861                            "http file cache incomplete: \"%s\"",
862                            tf->file.name.data);
863 
864             if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
865                 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
866                               ngx_delete_file_n " \"%s\" failed",
867                               tf->file.name.data);
868             }
869         }
870     }
871 }
872 
873 
874 static void
875 ngx_http_file_cache_cleanup(void *data)
876 {
877     ngx_http_cache_t  *c = data;
878 
879     ngx_http_file_cache_t  *cache;
880 
881     if (c->updated) {
882         return;
883     }
884 
885     c->updated = 1;
886 
887     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
888                    "http file cache cleanup");
889 
890     if (c->error) {
891         return;
892     }
893 
894     cache = c->file_cache;
895 
896     ngx_shmtx_lock(&cache->shpool->mutex);
897 
898     c->node->count--;
899 
900     ngx_shmtx_unlock(&cache->shpool->mutex);
901 }
902 
903 
904 static time_t
905 ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache)
906 {
907     u_char                      *name;
908     size_t                       len;
909     time_t                       wait;
910     ngx_uint_t                   tries;
911     ngx_path_t                  *path;
912     ngx_queue_t                 *q;
913     ngx_http_file_cache_node_t  *fcn;
914 
915     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
916                    "http file cache forced expire");
917 
918     path = cache->path;
919     len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
920 
921     name = ngx_alloc(len + 1, ngx_cycle->log);
922     if (name == NULL) {
923         return 10;
924     }
925 
926     ngx_memcpy(name, path->name.data, path->name.len);
927 
928     wait = 10;
929     tries = 0;
930 
931     ngx_shmtx_lock(&cache->shpool->mutex);
932 
933     for (q = ngx_queue_last(&cache->sh->queue);
934          q != ngx_queue_sentinel(&cache->sh->queue);
935          q = ngx_queue_prev(q))
936     {
937         fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
938 
939         ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
940                   "http file cache forced expire: #%d %d %02xd%02xd%02xd%02xd",
941                   fcn->count, fcn->exists,
942                   fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
943 
944         if (fcn->count) {
945 
946             if (tries++ < 20) {
947                 continue;
948             }
949 
950             wait = 1;
951 
952             break;
953         }
954 
955         if (!fcn->exists) {
956 
957             ngx_queue_remove(q);
958             ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
959             ngx_slab_free_locked(cache->shpool, fcn);
960 
961             break;
962         }
963 
964         ngx_http_file_cache_delete(cache, q, name);
965 
966         break;
967     }
968 
969     ngx_shmtx_unlock(&cache->shpool->mutex);
970 
971     ngx_free(name);
972 
973     return wait;
974 }
975 
976 
977 static time_t
978 ngx_http_file_cache_expire(ngx_http_file_cache_t *cache)
979 {
980     u_char                      *name, *p;
981     size_t                       len;
982     time_t                       now, wait;
983     ngx_path_t                  *path;
984     ngx_queue_t                 *q;
985     ngx_http_file_cache_node_t  *fcn;
986     u_char                       key[2 * NGX_HTTP_CACHE_KEY_LEN];
987 
988     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
989                    "http file cache expire");
990 
991     path = cache->path;
992     len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
993 
994     name = ngx_alloc(len + 1, ngx_cycle->log);
995     if (name == NULL) {
996         return 10;
997     }
998 
999     ngx_memcpy(name, path->name.data, path->name.len);
1000 
1001     now = ngx_time();
1002 
1003     ngx_shmtx_lock(&cache->shpool->mutex);
1004 
1005     for ( ;; ) {
1006 
1007         if (ngx_queue_empty(&cache->sh->queue)) {
1008             wait = 10;
1009             break;
1010         }
1011 
1012         q = ngx_queue_last(&cache->sh->queue);
1013 
1014         fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
1015 
1016         wait = fcn->expire - now;
1017 
1018         if (wait > 0) {
1019             wait = wait > 10 ? 10 : wait;
1020             break;
1021         }
1022 
1023         ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1024                        "http file cache expire: #%d %d %02xd%02xd%02xd%02xd",
1025                        fcn->count, fcn->exists,
1026                        fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
1027 
1028         if (fcn->count) {
1029 
1030             p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
1031                              sizeof(ngx_rbtree_key_t));
1032 
1033             len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
1034             (void) ngx_hex_dump(p, fcn->key, len);
1035 
1036             /*
1037              * abnormally exited workers may leave locked cache entries,
1038              * and although it may be safe to remove them completely,
1039              * we prefer to remove them from inactive queue and rbtree
1040              * only, and to allow other leaks
1041              */
1042 
1043             ngx_queue_remove(q);
1044             ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1045 
1046             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
1047                        "ignore long locked inactive cache entry %*s, count:%d",
1048                        2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count);
1049 
1050             continue;
1051         }
1052 
1053         if (!fcn->exists) {
1054 
1055             ngx_queue_remove(q);
1056             ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1057             ngx_slab_free_locked(cache->shpool, fcn);
1058 
1059             continue;
1060         }
1061 
1062         ngx_http_file_cache_delete(cache, q, name);
1063     }
1064 
1065     ngx_shmtx_unlock(&cache->shpool->mutex);
1066 
1067     ngx_free(name);
1068 
1069     return wait;
1070 }
1071 
1072 
1073 static void
1074 ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q,
1075     u_char *name)
1076 {
1077     u_char                      *p;
1078     size_t                       len;
1079     ngx_path_t                  *path;
1080     ngx_http_file_cache_node_t  *fcn;
1081 
1082     fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
1083 
1084     cache->sh->size -= (fcn->length + cache->bsize - 1) / cache->bsize;
1085 
1086     path = cache->path;
1087 
1088     p = name + path->name.len + 1 + path->len;
1089 
1090     p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t));
1091 
1092     len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
1093     p = ngx_hex_dump(p, fcn->key, len);
1094     *p = '\0';
1095 
1096     ngx_queue_remove(q);
1097 
1098     ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1099 
1100     ngx_slab_free_locked(cache->shpool, fcn);
1101 
1102     ngx_shmtx_unlock(&cache->shpool->mutex);
1103 
1104     len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
1105 
1106     ngx_create_hashed_filename(path, name, len);
1107 
1108     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1109                    "http file cache expire: \"%s\"", name);
1110 
1111     if (ngx_delete_file(name) == NGX_FILE_ERROR) {
1112         ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
1113                       ngx_delete_file_n " \"%s\" failed", name);
1114     }
1115 
1116     ngx_shmtx_lock(&cache->shpool->mutex);
1117 }
1118 
1119 
1120 static time_t
1121 ngx_http_file_cache_manager(void *data)
1122 {
1123     ngx_http_file_cache_t  *cache = data;
1124 
1125     off_t   size;
1126     time_t  next;
1127 
1128     next = ngx_http_file_cache_expire(cache);
1129 
1130     cache->last = ngx_current_msec;
1131     cache->files = 0;
1132 
1133     for ( ;; ) {
1134         ngx_shmtx_lock(&cache->shpool->mutex);
1135 
1136         size = cache->sh->size;
1137 
1138         ngx_shmtx_unlock(&cache->shpool->mutex);
1139 
1140         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1141                        "http file cache size: %O", size);
1142 
1143         if (size < cache->max_size) {
1144             return next;
1145         }
1146 
1147         next = ngx_http_file_cache_forced_expire(cache);
1148 
1149         if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) {
1150             return next;
1151         }
1152     }
1153 }
1154 
1155 
1156 static void
1157 ngx_http_file_cache_loader(void *data)
1158 {
1159     ngx_http_file_cache_t  *cache = data;
1160 
1161     ngx_tree_ctx_t  tree;
1162 
1163     if (!cache->sh->cold || cache->sh->loading) {
1164         return;
1165     }
1166 
1167     if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) {
1168         return;
1169     }
1170 
1171     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1172                    "http file cache loader");
1173 
1174     tree.init_handler = NULL;
1175     tree.file_handler = ngx_http_file_cache_manage_file;
1176     tree.pre_tree_handler = ngx_http_file_cache_noop;
1177     tree.post_tree_handler = ngx_http_file_cache_noop;
1178     tree.spec_handler = ngx_http_file_cache_delete_file;
1179     tree.data = cache;
1180     tree.alloc = 0;
1181     tree.log = ngx_cycle->log;
1182 
1183     cache->last = ngx_current_msec;
1184     cache->files = 0;
1185 
1186     if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {
1187         cache->sh->loading = 0;
1188         return;
1189     }
1190 
1191     cache->sh->cold = 0;
1192     cache->sh->loading = 0;
1193 
1194     ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
1195                   "http file cache: %V %.3fM, bsize: %uz",
1196                   &cache->path->name,
1197                   ((double) cache->sh->size * cache->bsize) / (1024 * 1024),
1198                   cache->bsize);
1199 }
1200 
1201 
1202 static ngx_int_t
1203 ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache)
1204 {
1205     ngx_msec_t  elapsed;
1206 
1207     if (cache->files++ > 100) {
1208 
1209         ngx_time_update(0, 0);
1210 
1211         elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));
1212 
1213         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1214                        "http file cache manager time: %M", elapsed);
1215 
1216         if (elapsed > 200) {
1217 
1218             /*
1219              * if processing 100 files takes more than 200ms,
1220              * it seems that many operations require disk i/o,
1221              * therefore sleep 200ms
1222              */
1223 
1224             ngx_msleep(200);
1225 
1226             ngx_time_update(0, 0);
1227         }
1228 
1229         cache->last = ngx_current_msec;
1230         cache->files = 0;
1231     }
1232 
1233     return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK;
1234 }
1235 
1236 
1237 static ngx_int_t
1238 ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
1239 {
1240     return NGX_OK;
1241 }
1242 
1243 
1244 static ngx_int_t
1245 ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
1246 {
1247     ngx_http_file_cache_t  *cache;
1248 
1249     cache = ctx->data;
1250 
1251     if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) {
1252         (void) ngx_http_file_cache_delete_file(ctx, path);
1253     }
1254 
1255     return ngx_http_file_cache_manager_sleep(cache);
1256 }
1257 
1258 
1259 static ngx_int_t
1260 ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name)
1261 {
1262     u_char                        *p;
1263     ngx_fd_t                       fd;
1264     ngx_int_t                      n;
1265     ngx_uint_t                     i;
1266     ngx_file_info_t                fi;
1267     ngx_http_cache_t               c;
1268     ngx_http_file_cache_t         *cache;
1269     ngx_http_file_cache_header_t   h;
1270 
1271     if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) {
1272         return NGX_ERROR;
1273     }
1274 
1275     ngx_memzero(&c, sizeof(ngx_http_cache_t));
1276 
1277     fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
1278 
1279     if (fd == NGX_INVALID_FILE) {
1280         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
1281                       ngx_open_file_n " \"%s\" failed", name->data);
1282         return NGX_ERROR;
1283     }
1284 
1285     c.file.fd = fd;
1286     c.file.name = *name;
1287     c.file.log = ctx->log;
1288 
1289     n = ngx_read_file(&c.file, (u_char *) &h,
1290                       sizeof(ngx_http_file_cache_header_t), 0);
1291     if (n == NGX_ERROR) {
1292         return NGX_ERROR;
1293     }
1294 
1295     if ((size_t) n < sizeof(ngx_http_file_cache_header_t)) {
1296         ngx_log_error(NGX_LOG_CRIT, ctx->log, 0,
1297                       "cache file \"%s\" is too small", name->data);
1298         return NGX_ERROR;
1299     }
1300 
1301     if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
1302         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
1303                       ngx_fd_info_n " \"%s\" failed", name->data);
1304 
1305     } else {
1306         c.uniq = ngx_file_uniq(&fi);
1307         c.valid_sec = h.valid_sec;
1308         c.valid_msec = h.valid_msec;
1309         c.body_start = h.body_start;
1310         c.length = ngx_file_size(&fi);
1311     }
1312 
1313     if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1314         ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
1315                       ngx_close_file_n " \"%s\" failed", name->data);
1316     }
1317 
1318     if (c.body_start == 0) {
1319         return NGX_ERROR;
1320     }
1321 
1322     p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN];
1323 
1324     for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) {
1325         n = ngx_hextoi(p, 2);
1326 
1327         if (n == NGX_ERROR) {
1328             return NGX_ERROR;
1329         }
1330 
1331         p += 2;
1332 
1333         c.key[i] = (u_char) n;
1334     }
1335 
1336     cache = ctx->data;
1337 
1338     return ngx_http_file_cache_add(cache, &c);
1339 }
1340 
1341 
1342 static ngx_int_t
1343 ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
1344 {
1345     ngx_http_file_cache_node_t  *fcn;
1346 
1347     ngx_shmtx_lock(&cache->shpool->mutex);
1348 
1349     fcn = ngx_http_file_cache_lookup(cache, c->key);
1350 
1351     if (fcn == NULL) {
1352 
1353         fcn = ngx_slab_alloc_locked(cache->shpool,
1354                                     sizeof(ngx_http_file_cache_node_t));
1355         if (fcn == NULL) {
1356             ngx_shmtx_unlock(&cache->shpool->mutex);
1357             return NGX_ERROR;
1358         }
1359 
1360         ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));
1361 
1362         ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
1363                    NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
1364 
1365         ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
1366 
1367         fcn->uses = 1;
1368         fcn->count = 0;
1369         fcn->valid_msec = c->valid_msec;
1370         fcn->error = 0;
1371         fcn->exists = 1;
1372         fcn->uniq = c->uniq;
1373         fcn->valid_sec = c->valid_sec;
1374         fcn->body_start = c->body_start;
1375         fcn->length = c->length;
1376 
1377         cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
1378 
1379     } else {
1380         ngx_queue_remove(&fcn->queue);
1381     }
1382 
1383     fcn->expire = ngx_time() + cache->inactive;
1384 
1385     ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);
1386 
1387     ngx_shmtx_unlock(&cache->shpool->mutex);
1388 
1389     return NGX_OK;
1390 }
1391 
1392 
1393 static ngx_int_t
1394 ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
1395 {
1396     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
1397                    "http file cache delete: \"%s\"", path->data);
1398 
1399     if (ngx_delete_file(path->data) == NGX_FILE_ERROR) {
1400         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
1401                       ngx_delete_file_n " \"%s\" failed", path->data);
1402     }
1403 
1404     return NGX_OK;
1405 }
1406 
1407 
1408 time_t
1409 ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status)
1410 {
1411     ngx_uint_t               i;
1412     ngx_http_cache_valid_t  *valid;
1413 
1414     if (cache_valid == NULL) {
1415         return 0;
1416     }
1417 
1418     valid = cache_valid->elts;
1419     for (i = 0; i < cache_valid->nelts; i++) {
1420 
1421         if (valid[i].status == 0) {
1422             return valid[i].valid;
1423         }
1424 
1425         if (valid[i].status == status) {
1426             return valid[i].valid;
1427         }
1428     }
1429 
1430     return 0;
1431 }
1432 
1433 
1434 char *
1435 ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1436 {
1437     off_t                   max_size;
1438     u_char                 *last, *p;
1439     time_t                  inactive;
1440     ssize_t                 size;
1441     ngx_str_t               s, name, *value;
1442     ngx_uint_t              i, n;
1443     ngx_http_file_cache_t  *cache;
1444 
1445     cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
1446     if (cache == NULL) {
1447         return NGX_CONF_ERROR;
1448     }
1449 
1450     cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
1451     if (cache->path == NULL) {
1452         return NGX_CONF_ERROR;
1453     }
1454 
1455     inactive = 600;
1456 
1457     name.len = 0;
1458     size = 0;
1459     max_size = NGX_MAX_OFF_T_VALUE;
1460 
1461     value = cf->args->elts;
1462 
1463     cache->path->name = value[1];
1464 
1465     if (cache->path->name.data[cache->path->name.len - 1] == '/') {
1466         cache->path->name.len--;
1467     }
1468 
1469     if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {
1470         return NGX_CONF_ERROR;
1471     }
1472 
1473     for (i = 2; i < cf->args->nelts; i++) {
1474 
1475         if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {
1476 
1477             p = value[i].data + 7;
1478             last = value[i].data + value[i].len;
1479 
1480             for (n = 0; n < 3 && p < last; n++) {
1481 
1482                 if (*p > '' && *p < '3') {
1483 
1484                     cache->path->level[n] = *p++ - '';
1485                     cache->path->len += cache->path->level[n] + 1;
1486 
1487                     if (p == last) {
1488                         break;
1489                     }
1490 
1491                     if (*p++ == ':' && n < 2 && p != last) {
1492                         continue;
1493                     }
1494 
1495                     goto invalid_levels;
1496                 }
1497 
1498                 goto invalid_levels;
1499             }
1500 
1501             if (cache->path->len < 10 + 3) {
1502                 continue;
1503             }
1504 
1505         invalid_levels:
1506 
1507             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1508                                "invalid \"levels\" \"%V\"", &value[i]);
1509             return NGX_CONF_ERROR;
1510         }
1511 
1512         if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {
1513 
1514             name.data = value[i].data + 10;
1515 
1516             p = (u_char *) ngx_strchr(name.data, ':');
1517 
1518             if (p) {
1519                 *p = '\0';
1520 
1521                 name.len = p - name.data;
1522 
1523                 p++;
1524 
1525                 s.len = value[i].data + value[i].len - p;
1526                 s.data = p;
1527 
1528                 size = ngx_parse_size(&s);
1529                 if (size > 8191) {
1530                     continue;
1531                 }
1532             }
1533 
1534             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1535                                "invalid keys zone size \"%V\"", &value[i]);
1536             return NGX_CONF_ERROR;
1537         }
1538 
1539         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
1540 
1541             s.len = value[i].len - 9;
1542             s.data = value[i].data + 9;
1543 
1544             inactive = ngx_parse_time(&s, 1);
1545             if (inactive < 0) {
1546                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1547                                    "invalid inactive value \"%V\"", &value[i]);
1548                 return NGX_CONF_ERROR;
1549             }
1550 
1551             continue;
1552         }
1553 
1554         if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {
1555 
1556             s.len = value[i].len - 9;
1557             s.data = value[i].data + 9;
1558 
1559             max_size = ngx_parse_offset(&s);
1560             if (max_size < 0) {
1561                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1562                                    "invalid max_size value \"%V\"", &value[i]);
1563                 return NGX_CONF_ERROR;
1564             }
1565 
1566             continue;
1567         }
1568 
1569         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1570                            "invalid parameter \"%V\"", &value[i]);
1571         return NGX_CONF_ERROR;
1572     }
1573 
1574     if (name.len == 0 || size == 0) {
1575         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1576                            "\"%V\" must have \"keys_zone\" parameter",
1577                            &cmd->name);
1578         return NGX_CONF_ERROR;
1579     }
1580 
1581     cache->path->manager = ngx_http_file_cache_manager;
1582     cache->path->loader = ngx_http_file_cache_loader;
1583     cache->path->data = cache;
1584 
1585     if (ngx_add_path(cf, &cache->path) != NGX_OK) {
1586         return NGX_CONF_ERROR;
1587     }
1588 
1589     cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
1590     if (cache->shm_zone == NULL) {
1591         return NGX_CONF_ERROR;
1592     }
1593 
1594     if (cache->shm_zone->data) {
1595         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1596                            "duplicate zone \"%V\"", &name);
1597         return NGX_CONF_ERROR;
1598     }
1599 
1600 
1601     cache->shm_zone->init = ngx_http_file_cache_init;
1602     cache->shm_zone->data = cache;
1603 
1604     cache->inactive = inactive;
1605     cache->max_size = max_size;
1606 
1607     return NGX_CONF_OK;
1608 }
1609 
1610 
1611 char *
1612 ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
1613     void *conf)
1614 {
1615     char  *p = conf;
1616 
1617     time_t                    valid;
1618     ngx_str_t                *value;
1619     ngx_uint_t                i, n, status;
1620     ngx_array_t             **a;
1621     ngx_http_cache_valid_t   *v;
1622     static ngx_uint_t         statuses[] = { 200, 301, 302 };
1623 
1624     a = (ngx_array_t **) (p + cmd->offset);
1625 
1626     if (*a == NGX_CONF_UNSET_PTR) {
1627         *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_cache_valid_t));
1628         if (*a == NULL) {
1629             return NGX_CONF_ERROR;
1630         }
1631     }
1632 
1633     value = cf->args->elts;
1634     n = cf->args->nelts - 1;
1635 
1636     valid = ngx_parse_time(&value[n], 1);
1637     if (valid < 0) {
1638         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1639                            "invalid time value \"%V\"", &value[n]);
1640         return NGX_CONF_ERROR;
1641     }
1642 
1643     if (n == 1) {
1644 
1645         for (i = 0; i < 3; i++) {
1646             v = ngx_array_push(*a);
1647             if (v == NULL) {
1648                 return NGX_CONF_ERROR;
1649             }
1650 
1651             v->status = statuses[i];
1652             v->valid = valid;
1653         }
1654 
1655         return NGX_CONF_OK;
1656     }
1657 
1658     for (i = 1; i < n; i++) {
1659 
1660         if (ngx_strcmp(value[i].data, "any") == 0) {
1661 
1662             status = 0;
1663 
1664         } else {
1665 
1666             status = ngx_atoi(value[i].data, value[i].len);
1667             if (status < 100) {
1668                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1669                                    "invalid status \"%V\"", &value[i]);
1670                 return NGX_CONF_ERROR;
1671             }
1672         }
1673 
1674         v = ngx_array_push(*a);
1675         if (v == NULL) {
1676             return NGX_CONF_ERROR;
1677         }
1678 
1679         v->status = status;
1680         v->valid = valid;
1681     }
1682 
1683     return NGX_CONF_OK;
1684 }
1685 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.