[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