comparison src/http/ngx_http_file_cache.c @ 632:5b73504dd4ba NGINX_1_1_0

nginx 1.1.0 *) Feature: cache loader run time decrease. *) Feature: "loader_files", "loader_sleep", and "loader_threshold" options of the "proxy/fastcgi/scgi/uwsgi_cache_path" directives. *) Feature: loading time decrease of configuration with large number of HTTPS sites. *) Feature: now nginx supports ECDHE key exchange ciphers. Thanks to Adrian Kotelba. *) Feature: the "lingering_close" directive. Thanks to Maxim Dounin. *) Bugfix: in closing connection for pipelined requests. Thanks to Maxim Dounin. *) Bugfix: nginx did not disable gzipping if client sent "gzip;q=0" in "Accept-Encoding" request header line. *) Bugfix: in timeout in unbuffered proxied mode. Thanks to Maxim Dounin. *) Bugfix: memory leaks when a "proxy_pass" directive contains variables and proxies to an HTTPS backend. Thanks to Maxim Dounin. *) Bugfix: in parameter validaiton of a "proxy_pass" directive with variables. Thanks to Lanshun Zhou. *) Bugfix: SSL did not work on QNX. Thanks to Maxim Dounin. *) Bugfix: SSL modules could not be built by gcc 4.6 without --with-debug option.
author Igor Sysoev <http://sysoev.ru>
date Mon, 01 Aug 2011 00:00:00 +0400
parents ad6fee8052d7
children 23ef0645ea57
comparison
equal deleted inserted replaced
631:9b978fa3cd33 632:5b73504dd4ba
29 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache); 29 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
30 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache); 30 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
31 static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, 31 static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache,
32 ngx_queue_t *q, u_char *name); 32 ngx_queue_t *q, u_char *name);
33 static ngx_int_t 33 static ngx_int_t
34 ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache); 34 ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache);
35 static ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, 35 static ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx,
36 ngx_str_t *path); 36 ngx_str_t *path);
37 static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, 37 static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx,
38 ngx_str_t *path); 38 ngx_str_t *path);
39 static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, 39 static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx,
374 } 374 }
375 375
376 if ((size_t) n < c->header_start) { 376 if ((size_t) n < c->header_start) {
377 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, 377 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
378 "cache file \"%s\" is too small", c->file.name.data); 378 "cache file \"%s\" is too small", c->file.name.data);
379 return NGX_ERROR; 379 return NGX_DECLINED;
380 } 380 }
381 381
382 h = (ngx_http_file_cache_header_t *) c->buf->pos; 382 h = (ngx_http_file_cache_header_t *) c->buf->pos;
383 383
384 if (h->crc32 != c->crc32) { 384 if (h->crc32 != c->crc32) {
528 rc = NGX_OK; 528 rc = NGX_OK;
529 529
530 goto done; 530 goto done;
531 } 531 }
532 532
533 if (fcn->exists) { 533 if (fcn->exists || fcn->uses >= c->min_uses) {
534 534
535 c->exists = fcn->exists; 535 c->exists = fcn->exists;
536 c->body_start = fcn->body_start; 536 if (fcn->body_start) {
537 c->body_start = fcn->body_start;
538 }
537 539
538 rc = NGX_OK; 540 rc = NGX_OK;
539 541
540 goto done; 542 goto done;
541 } 543 }
542 544
543 if (fcn->uses >= c->min_uses) { 545 rc = NGX_AGAIN;
544
545 c->exists = fcn->exists;
546 c->body_start = fcn->body_start;
547
548 rc = NGX_OK;
549
550 } else {
551 rc = NGX_AGAIN;
552 }
553 546
554 goto done; 547 goto done;
555 } 548 }
556 549
557 fcn = ngx_slab_alloc_locked(cache->shpool, 550 fcn = ngx_slab_alloc_locked(cache->shpool,
856 ngx_http_cache_t *c; 849 ngx_http_cache_t *c;
857 850
858 c = r->cache; 851 c = r->cache;
859 852
860 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 853 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
861 "http file cache send: %s", c->file.name.data); 854 "http file cache send: %s", c->file.name.data);
862 855
863 /* we need to allocate all before the header would be sent */ 856 /* we need to allocate all before the header would be sent */
864 857
865 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); 858 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
866 if (b == NULL) { 859 if (b == NULL) {
1212 1205
1213 if (wait > 0) { 1206 if (wait > 0) {
1214 return wait; 1207 return wait;
1215 } 1208 }
1216 1209
1217 if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) { 1210 if (ngx_quit || ngx_terminate) {
1218 return next; 1211 return next;
1219 } 1212 }
1220 } 1213 }
1221 } 1214 }
1222 1215
1266 cache->bsize); 1259 cache->bsize);
1267 } 1260 }
1268 1261
1269 1262
1270 static ngx_int_t 1263 static ngx_int_t
1271 ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache) 1264 ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache)
1272 { 1265 {
1273 ngx_msec_t elapsed; 1266 ngx_msec_t elapsed;
1274 1267
1275 if (cache->files++ > 100) { 1268 if (++cache->files >= cache->loader_files) {
1276 1269
1277 ngx_time_update(); 1270 ngx_time_update();
1278 1271
1279 elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); 1272 elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));
1280 1273
1281 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, 1274 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1282 "http file cache manager time: %M", elapsed); 1275 "http file cache loader time elapsed: %M", elapsed);
1283 1276
1284 if (elapsed > 200) { 1277 if (elapsed >= cache->loader_threshold) {
1285 1278
1286 /* 1279 if (cache->loader_files > 1) {
1287 * if processing 100 files takes more than 200ms, 1280 cache->loader_files /= 2;
1288 * it seems that many operations require disk i/o, 1281 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
1289 * therefore sleep 200ms 1282 "cache %V loader_files decreased to %ui",
1290 */ 1283 &cache->path->name, cache->loader_files);
1291 1284
1292 ngx_msleep(200); 1285 } else {
1293 1286 cache->loader_sleep *= 2;
1294 ngx_time_update(); 1287 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
1295 } 1288 "cache %V loader_sleep increased to %Mms",
1289 &cache->path->name, cache->loader_sleep);
1290 }
1291 }
1292
1293 ngx_msleep(cache->loader_sleep);
1294
1295 ngx_time_update();
1296 1296
1297 cache->last = ngx_current_msec; 1297 cache->last = ngx_current_msec;
1298 cache->files = 0; 1298 cache->files = 0;
1299 } 1299 }
1300 1300
1318 1318
1319 if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) { 1319 if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) {
1320 (void) ngx_http_file_cache_delete_file(ctx, path); 1320 (void) ngx_http_file_cache_delete_file(ctx, path);
1321 } 1321 }
1322 1322
1323 return ngx_http_file_cache_manager_sleep(cache); 1323 return ngx_http_file_cache_loader_sleep(cache);
1324 } 1324 }
1325 1325
1326 1326
1327 static ngx_int_t 1327 static ngx_int_t
1328 ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name) 1328 ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name)
1329 { 1329 {
1330 u_char *p; 1330 u_char *p;
1331 ngx_fd_t fd; 1331 ngx_int_t n;
1332 ngx_int_t n; 1332 ngx_uint_t i;
1333 ngx_uint_t i; 1333 ngx_http_cache_t c;
1334 ngx_file_info_t fi; 1334 ngx_http_file_cache_t *cache;
1335 ngx_http_cache_t c;
1336 ngx_http_file_cache_t *cache;
1337 ngx_http_file_cache_header_t h;
1338 1335
1339 if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { 1336 if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) {
1340 return NGX_ERROR; 1337 return NGX_ERROR;
1341 } 1338 }
1342 1339
1343 ngx_memzero(&c, sizeof(ngx_http_cache_t)); 1340 if (ctx->size < (off_t) sizeof(ngx_http_file_cache_header_t)) {
1344
1345 fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
1346
1347 if (fd == NGX_INVALID_FILE) {
1348 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
1349 ngx_open_file_n " \"%s\" failed", name->data);
1350 return NGX_ERROR;
1351 }
1352
1353 c.file.fd = fd;
1354 c.file.name = *name;
1355 c.file.log = ctx->log;
1356
1357 n = ngx_read_file(&c.file, (u_char *) &h,
1358 sizeof(ngx_http_file_cache_header_t), 0);
1359 if (n == NGX_ERROR) {
1360 return NGX_ERROR;
1361 }
1362
1363 if ((size_t) n < sizeof(ngx_http_file_cache_header_t)) {
1364 ngx_log_error(NGX_LOG_CRIT, ctx->log, 0, 1341 ngx_log_error(NGX_LOG_CRIT, ctx->log, 0,
1365 "cache file \"%s\" is too small", name->data); 1342 "cache file \"%s\" is too small", name->data);
1366 return NGX_ERROR; 1343 return NGX_ERROR;
1367 } 1344 }
1368 1345
1346 ngx_memzero(&c, sizeof(ngx_http_cache_t));
1369 cache = ctx->data; 1347 cache = ctx->data;
1370 1348
1371 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { 1349 c.length = ctx->size;
1372 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, 1350 c.fs_size = (ctx->fs_size + cache->bsize - 1) / cache->bsize;
1373 ngx_fd_info_n " \"%s\" failed", name->data);
1374
1375 } else {
1376 c.uniq = ngx_file_uniq(&fi);
1377 c.valid_sec = h.valid_sec;
1378 c.valid_msec = h.valid_msec;
1379 c.body_start = h.body_start;
1380 c.length = ngx_file_size(&fi);
1381 c.fs_size = (ngx_file_fs_size(&fi) + cache->bsize - 1) / cache->bsize;
1382 }
1383
1384 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1385 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
1386 ngx_close_file_n " \"%s\" failed", name->data);
1387 }
1388
1389 if (c.body_start == 0) {
1390 return NGX_ERROR;
1391 }
1392 1351
1393 p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; 1352 p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN];
1394 1353
1395 for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { 1354 for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) {
1396 n = ngx_hextoi(p, 2); 1355 n = ngx_hextoi(p, 2);
1433 1392
1434 ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node); 1393 ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
1435 1394
1436 fcn->uses = 1; 1395 fcn->uses = 1;
1437 fcn->count = 0; 1396 fcn->count = 0;
1438 fcn->valid_msec = c->valid_msec; 1397 fcn->valid_msec = 0;
1439 fcn->error = 0; 1398 fcn->error = 0;
1440 fcn->exists = 1; 1399 fcn->exists = 1;
1441 fcn->updating = 0; 1400 fcn->updating = 0;
1442 fcn->deleting = 0; 1401 fcn->deleting = 0;
1443 fcn->uniq = c->uniq; 1402 fcn->uniq = 0;
1444 fcn->valid_sec = c->valid_sec; 1403 fcn->valid_sec = 0;
1445 fcn->body_start = c->body_start; 1404 fcn->body_start = 0;
1446 fcn->fs_size = c->fs_size; 1405 fcn->fs_size = c->fs_size;
1447 1406
1448 cache->sh->size += c->fs_size; 1407 cache->sh->size += c->fs_size;
1449 1408
1450 } else { 1409 } else {
1508 off_t max_size; 1467 off_t max_size;
1509 u_char *last, *p; 1468 u_char *last, *p;
1510 time_t inactive; 1469 time_t inactive;
1511 ssize_t size; 1470 ssize_t size;
1512 ngx_str_t s, name, *value; 1471 ngx_str_t s, name, *value;
1472 ngx_int_t loader_files, loader_sleep, loader_threshold;
1513 ngx_uint_t i, n; 1473 ngx_uint_t i, n;
1514 ngx_http_file_cache_t *cache; 1474 ngx_http_file_cache_t *cache;
1515 1475
1516 cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t)); 1476 cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
1517 if (cache == NULL) { 1477 if (cache == NULL) {
1522 if (cache->path == NULL) { 1482 if (cache->path == NULL) {
1523 return NGX_CONF_ERROR; 1483 return NGX_CONF_ERROR;
1524 } 1484 }
1525 1485
1526 inactive = 600; 1486 inactive = 600;
1487 loader_files = 100;
1488 loader_sleep = 50;
1489 loader_threshold = 200;
1527 1490
1528 name.len = 0; 1491 name.len = 0;
1529 size = 0; 1492 size = 0;
1530 max_size = NGX_MAX_OFF_T_VALUE; 1493 max_size = NGX_MAX_OFF_T_VALUE;
1531 1494
1635 } 1598 }
1636 1599
1637 continue; 1600 continue;
1638 } 1601 }
1639 1602
1603 if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {
1604
1605 loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);
1606 if (loader_files == NGX_ERROR) {
1607 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1608 "invalid loader_files value \"%V\"", &value[i]);
1609 return NGX_CONF_ERROR;
1610 }
1611
1612 continue;
1613 }
1614
1615 if (ngx_strncmp(value[i].data, "loader_sleep=", 13) == 0) {
1616
1617 s.len = value[i].len - 13;
1618 s.data = value[i].data + 13;
1619
1620 loader_sleep = ngx_parse_time(&s, 0);
1621 if (loader_sleep < 0) {
1622 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1623 "invalid loader_sleep value \"%V\"", &value[i]);
1624 return NGX_CONF_ERROR;
1625 }
1626
1627 continue;
1628 }
1629
1630 if (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) {
1631
1632 s.len = value[i].len - 17;
1633 s.data = value[i].data + 17;
1634
1635 loader_threshold = ngx_parse_time(&s, 0);
1636 if (loader_threshold < 0) {
1637 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1638 "invalid loader_threshold value \"%V\"", &value[i]);
1639 return NGX_CONF_ERROR;
1640 }
1641
1642 continue;
1643 }
1644
1640 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1645 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1641 "invalid parameter \"%V\"", &value[i]); 1646 "invalid parameter \"%V\"", &value[i]);
1642 return NGX_CONF_ERROR; 1647 return NGX_CONF_ERROR;
1643 } 1648 }
1644 1649
1650 } 1655 }
1651 1656
1652 cache->path->manager = ngx_http_file_cache_manager; 1657 cache->path->manager = ngx_http_file_cache_manager;
1653 cache->path->loader = ngx_http_file_cache_loader; 1658 cache->path->loader = ngx_http_file_cache_loader;
1654 cache->path->data = cache; 1659 cache->path->data = cache;
1660 cache->path->conf_file = cf->conf_file->file.name.data;
1661 cache->path->line = cf->conf_file->line;
1662 cache->loader_files = loader_files;
1663 cache->loader_sleep = (ngx_msec_t) loader_sleep;
1664 cache->loader_threshold = (ngx_msec_t) loader_threshold;
1655 1665
1656 if (ngx_add_path(cf, &cache->path) != NGX_OK) { 1666 if (ngx_add_path(cf, &cache->path) != NGX_OK) {
1657 return NGX_CONF_ERROR; 1667 return NGX_CONF_ERROR;
1658 } 1668 }
1659 1669