changeset 633:cde3626b2d0d NGINX_0_8_47

nginx 0.8.47 *) Bugfix: $request_time variable had invalid values for subrequests. *) Bugfix: errors intercepted by error_page could be cached. *) Bugfix: a cache manager process my got caught in an endless loop, if max_size parameter was used; the bug had appeared in 0.8.46.
author Igor Sysoev <http://sysoev.ru>
date Wed, 28 Jul 2010 00:00:00 +0400
parents 5de4f69bbbab
children 8b891ad58d6a
files CHANGES CHANGES.ru src/core/nginx.h src/http/modules/perl/nginx.pm src/http/ngx_http_cache.h src/http/ngx_http_core_module.c src/http/ngx_http_file_cache.c src/http/ngx_http_upstream.c
diffstat 8 files changed, 74 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,12 +1,22 @@
 
+Changes with nginx 0.8.47                                        28 Jul 2010
+
+    *) Bugfix: $request_time variable had invalid values for subrequests.
+
+    *) Bugfix: errors intercepted by error_page could be cached.
+
+    *) Bugfix: a cache manager process my got caught in an endless loop, if 
+       max_size parameter was used; the bug had appeared in 0.8.46.
+
+
 Changes with nginx 0.8.46                                        19 Jul 2010
 
     *) Change: now the "proxy_no_cache", "fastcgi_no_cache", 
-       "uwsgi_no_cache", and "sсgi_no_cache" directives affect on a cached 
+       "uwsgi_no_cache", and "scgi_no_cache" directives affect on a cached 
        response saving only.
 
     *) Feature: the "proxy_cache_bypass", "fastcgi_cache_bypass", 
-       "uwsgi_cache_bypass", and "sсgi_cache_bypass" directives.
+       "uwsgi_cache_bypass", and "scgi_cache_bypass" directives.
 
     *) Bugfix: nginx did not free memory in cache keys zones if there was 
        an error during working with backend: the memory was freed only 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,12 +1,23 @@
 
+Изменения в nginx 0.8.47                                          28.07.2010
+
+    *) Исправление: переменная $request_time имела неверные значения для 
+       подзапросов.
+
+    *) Исправление: ошибки, перехваченные error_page, не кэшировались.
+
+    *) Исправление: если использовался параметр max_size, то cache manager 
+       мог зациклиться. ошибка появилась в 0.8.46.
+
+
 Изменения в nginx 0.8.46                                          19.07.2010
 
     *) Изменение: директивы proxy_no_cache, fastcgi_no_cache, 
-       uwsgi_no_cache и sсgi_no_cache теперь влияют только на сохранение 
+       uwsgi_no_cache и scgi_no_cache теперь влияют только на сохранение 
        закэшированного ответа.
 
     *) Добавление: директивы proxy_cache_bypass, fastcgi_cache_bypass, 
-       uwsgi_cache_bypass и sсgi_cache_bypass.
+       uwsgi_cache_bypass и scgi_cache_bypass.
 
     *) Исправление: nginx не освобождал память в keys_zone кэшей в случае 
        ошибки работы с бэкендом: память освобождалась только по истечении 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8046
-#define NGINX_VERSION      "0.8.46"
+#define nginx_version         8047
+#define NGINX_VERSION      "0.8.47"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -48,7 +48,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.8.46';
+our $VERSION = '0.8.47';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -78,6 +78,7 @@ struct ngx_http_cache_s {
     ngx_http_file_cache_node_t      *node;
 
     unsigned                         updated:1;
+    unsigned                         updating:1;
     unsigned                         exists:1;
     unsigned                         temp_file:1;
 };
@@ -129,7 +130,7 @@ ngx_int_t ngx_http_file_cache_open(ngx_h
 void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf);
 void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf);
 ngx_int_t ngx_http_cache_send(ngx_http_request_t *);
-void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf);
+void ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf);
 time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status);
 
 char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -2152,6 +2152,7 @@ ngx_http_subrequest(ngx_http_request_t *
     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,
     ngx_http_post_subrequest_t *ps, ngx_uint_t flags)
 {
+    ngx_time_t                    *tp;
     ngx_connection_t              *c;
     ngx_http_request_t            *sr;
     ngx_http_core_srv_conf_t      *cscf;
@@ -2264,6 +2265,10 @@ ngx_http_subrequest(ngx_http_request_t *
 
     sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
 
+    tp = ngx_timeofday();
+    r->start_sec = tp->sec;
+    r->start_msec = tp->msec;
+
     r->main->subrequests++;
     r->main->count++;
 
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -161,6 +161,7 @@ ngx_http_file_cache_new(ngx_http_request
 
     r->cache = c;
     c->file.log = r->connection->log;
+    c->file.fd = NGX_INVALID_FILE;
 
     return NGX_OK;
 }
@@ -429,6 +430,7 @@ ngx_http_file_cache_read(ngx_http_reques
 
         } else {
             c->node->updating = 1;
+            c->updating = 1;
             rc = NGX_HTTP_CACHE_STALE;
         }
 
@@ -792,6 +794,7 @@ ngx_http_file_cache_update(ngx_http_requ
                    "http file cache update");
 
     c->updated = 1;
+    c->updating = 0;
 
     cache = c->file_cache;
 
@@ -901,37 +904,35 @@ ngx_http_cache_send(ngx_http_request_t *
 
 
 void
-ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf)
+ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf)
 {
-    ngx_http_cache_t            *c;
     ngx_http_file_cache_t       *cache;
     ngx_http_file_cache_node_t  *fcn;
 
-    c = r->cache;
-
     if (c->updated) {
         return;
     }
 
-    c->updated = 1;
-
     cache = c->file_cache;
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http file cache free");
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
+                   "http file cache free, fd: %d", c->file.fd);
 
     ngx_shmtx_lock(&cache->shpool->mutex);
 
     fcn = c->node;
     fcn->count--;
-    fcn->updating = 0;
+
+    if (c->updating) {
+        fcn->updating = 0;
+    }
 
     if (c->error) {
         fcn->valid_sec = c->valid_sec;
         fcn->valid_msec = c->valid_msec;
         fcn->error = c->error;
 
-    } else if (fcn->valid_msec == 0 && fcn->count == 0) {
+    } else if (!fcn->exists && fcn->count == 0) {
         ngx_queue_remove(&fcn->queue);
         ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
         ngx_slab_free_locked(cache->shpool, fcn);
@@ -940,14 +941,17 @@ ngx_http_file_cache_free(ngx_http_reques
 
     ngx_shmtx_unlock(&cache->shpool->mutex);
 
+    c->updated = 1;
+    c->updating = 0;
+
     if (c->temp_file) {
         if (tf && tf->file.fd != NGX_INVALID_FILE) {
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
                            "http file cache incomplete: \"%s\"",
                            tf->file.name.data);
 
             if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+                ngx_log_error(NGX_LOG_CRIT, c->file.log, ngx_errno,
                               ngx_delete_file_n " \"%s\" failed",
                               tf->file.name.data);
             }
@@ -961,28 +965,19 @@ ngx_http_file_cache_cleanup(void *data)
 {
     ngx_http_cache_t  *c = data;
 
-    ngx_http_file_cache_t  *cache;
-
     if (c->updated) {
         return;
     }
 
-    c->updated = 1;
-
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
                    "http file cache cleanup");
 
-    if (c->error) {
-        return;
+    if (c->updating) {
+        ngx_log_error(NGX_LOG_ALERT, c->file.log, 0,
+                      "stalled cache updating, error:%ui", c->error);
     }
 
-    cache = c->file_cache;
-
-    ngx_shmtx_lock(&cache->shpool->mutex);
-
-    c->node->count--;
-
-    ngx_shmtx_unlock(&cache->shpool->mutex);
+    ngx_http_file_cache_free(c, NULL);
 }
 
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1720,6 +1720,21 @@ ngx_http_upstream_intercept_errors(ngx_h
                 r->headers_out.www_authenticate = h;
             }
 
+#if (NGX_HTTP_CACHE)
+
+            if (r->cache) {
+                time_t  valid;
+
+                valid = ngx_http_file_cache_valid(u->conf->cache_valid, status);
+
+                if (valid) {
+                    r->cache->valid_sec = ngx_time() + valid;
+                    r->cache->error = status;
+                }
+
+                ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
+            }
+#endif
             ngx_http_upstream_finalize_request(r, u, status);
 
             return NGX_OK;
@@ -1933,7 +1948,7 @@ ngx_http_upstream_process_body_in_memory
 
         if (size == 0) {
             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
-                          "upstream buffer is too small to read repsonse");
+                          "upstream buffer is too small to read response");
             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
             return;
         }
@@ -2171,7 +2186,7 @@ ngx_http_upstream_send_response(ngx_http
                    "http cacheable: %d", u->cacheable);
 
     if (u->cacheable == 0 && r->cache) {
-        ngx_http_file_cache_free(r, u->pipe->temp_file);
+        ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
     }
 
 #endif
@@ -2646,7 +2661,7 @@ ngx_http_upstream_process_request(ngx_ht
                 ngx_http_file_cache_update(r, u->pipe->temp_file);
 
             } else if (p->upstream_error) {
-                ngx_http_file_cache_free(r, u->pipe->temp_file);
+                ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
             }
         }
 
@@ -2974,10 +2989,6 @@ ngx_http_upstream_finalize_request(ngx_h
     if (u->cacheable && r->cache) {
         time_t  valid;
 
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http upstream cache fd: %d",
-                       r->cache->file.fd);
-
         if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) {
 
             valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc);
@@ -2988,7 +2999,7 @@ ngx_http_upstream_finalize_request(ngx_h
             }
         }
 
-        ngx_http_file_cache_free(r, u->pipe->temp_file);
+        ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
     }
 
 #endif