[PATCH 09 of 15] Tempfiles: Sending data from tempfile

Jiří Setnička jiri.setnicka at cdn77.com
Fri Jan 28 16:32:01 UTC 2022


# HG changeset patch
# User Jiří Setnička  <jiri.setnicka at cdn77.com>
# Date 1643385660 -3600
#      Fri Jan 28 17:01:00 2022 +0100
# Node ID 24453fd1ce204f361748c32e3c271d9e6fc7c9eb
# Parent  101a15e01c313f1327937c84fbf143f875d868de
Tempfiles: Sending data from tempfile
This commit adds mechanism for sending only a part of the tempfile:

1. When waiting for tempfile (c->waiting) ngx_http_cache_send obtains current
   size of file opened by ngx_http_file_cache_open and saves it into c->length
2. ngx_http_cache_send_internal sends appropriate part of the tempfile and
   records sent bytes. If output filter returned NGX_AGAIN, just wait for write
   event to wake us, otherwise setup timer using
   ngx_http_cache_wait_for_temp_file.
3. When tempfile is completed and moved it will server rest of the file (because
   opened file descriptor still points on the moved file, thank you POSIX) and
   it will return NGX_OK.

diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -92,6 +92,7 @@ struct ngx_http_cache_s {
     size_t                           buffer_size;
     size_t                           header_start;
     size_t                           body_start;
+    size_t                           body_sent_bytes;
     off_t                            length;
     off_t                            fs_size;
 
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -55,6 +55,8 @@ static ngx_int_t ngx_http_file_cache_reo
     ngx_http_cache_t *c);
 static ngx_int_t ngx_http_file_cache_update_variant(ngx_http_request_t *r,
     ngx_http_cache_t *c);
+static ngx_int_t ngx_http_cache_send_internal(ngx_http_request_t *r,
+    ngx_int_t last);
 static void ngx_http_file_cache_cleanup(void *data);
 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
@@ -1923,11 +1925,59 @@ done:
     }
 }
 
-
 ngx_int_t
 ngx_http_cache_send(ngx_http_request_t *r)
 {
     ngx_int_t          rc;
+    ngx_event_t       *wev;
+    ngx_http_cache_t  *c;
+
+    c = r->cache;
+
+    if (!c->waiting) {
+        return ngx_http_cache_send_internal(r, 1);
+    }
+
+    wev = r->connection->write;
+
+    ngx_shmtx_lock(&c->file_cache->shpool->mutex);
+
+    c->length = c->tf_node->length;
+
+    ngx_shmtx_unlock(&c->file_cache->shpool->mutex);
+
+    rc = ngx_http_cache_send_internal(r, 0);
+
+    if (rc != NGX_OK && rc != NGX_AGAIN) {
+        return rc;
+    }
+
+    if (rc == NGX_AGAIN && !wev->ready) {
+        return NGX_BUSY; /* epoll will wake us */
+    }
+
+    rc = ngx_http_file_cache_wait_for_temp_file(r, c);
+
+    if (rc == NGX_AGAIN) {
+        return NGX_BUSY;
+    }
+
+    if (rc == NGX_DECLINED) {
+        return NGX_ERROR; /* cannot restart here */
+    }
+
+    if (rc == NGX_DONE) {
+        return ngx_http_cache_send_internal(r, 1);
+    }
+
+    return rc;
+}
+
+
+static ngx_int_t
+ngx_http_cache_send_internal(ngx_http_request_t *r, ngx_int_t last)
+{
+    ngx_int_t          rc;
     ngx_buf_t         *b;
     ngx_chain_t        out;
     ngx_http_cache_t  *c;
@@ -1937,10 +1987,28 @@ ngx_http_cache_send(ngx_http_request_t *
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http file cache send: %s", c->file.name.data);
 
+    if (r->header_sent && r->header_only) {
+        return NGX_OK;
+    }
+
     if (r != r->main && c->length - c->body_start == 0) {
         return ngx_http_send_header(r);
     }
 
+    if (!last && (size_t)c->length == c->body_start + c->body_sent_bytes) {
+        /* nothing to write, invoke only output filter */
+
+        if (!r->header_sent) {
+            rc = ngx_http_send_header(r);
+
+            if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+                return rc;
+            }
+        }
+
+        return ngx_http_output_filter(r, NULL);
+    }
+
     /* we need to allocate all before the header would be sent */
 
     b = ngx_calloc_buf(r->pool);
@@ -1953,18 +2021,25 @@ ngx_http_cache_send(ngx_http_request_t *
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    rc = ngx_http_send_header(r);
-
-    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
-        return rc;
+    if (!r->header_sent) {
+        rc = ngx_http_send_header(r);
+
+        if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+            return rc;
+        }
     }
 
-    b->file_pos = c->body_start;
+    /* If we send more bytes reset wait_time */
+    r->cache->wait_time = ngx_current_msec + r->cache->tempfile_timeout;
+
+    b->file_pos = c->body_start + c->body_sent_bytes;
     b->file_last = c->length;
-
-    b->in_file = (c->length - c->body_start) ? 1: 0;
-    b->last_buf = (r == r->main) ? 1: 0;
-    b->last_in_chain = 1;
+    c->body_sent_bytes = c->length - c->body_start;
+
+    b->in_file = (c->length - b->file_pos) ? 1: 0;
+    b->last_buf = (r == r->main && last) ? 1: 0;
+    b->last_in_chain = last;
+    b->flush = 1;
 
     b->file->fd = c->file.fd;
     b->file->name = c->file.name;


More information about the nginx-devel mailing list