diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2021-09-22 16:12:05 -0400 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2021-09-30 17:34:03 -0400 |
commit | 6e62b84258fd955b34d3cbc0135c0e742aed4358 (patch) | |
tree | e1c6a733c50238aa22c01a997bf08f312b2ddd4b /src/http-header-glue.c | |
parent | 6bd6226e90932b7ef1cafe6fb3f846d8cea2e9eb (diff) | |
download | lighttpd-git-6e62b84258fd955b34d3cbc0135c0e742aed4358.tar.gz |
[core] splice() data from backends to tempfiles
splice() data from backends to tempfiles (where splice() is available);
reduce copying data to userspace when writing data to tempfiles
Note: splice() on Linux returns EINVAL if target file has O_APPEND set
so lighttpd uses pwrite() (where available) when writing to tempfiles
(instead of lseek() + write(), or O_APPEND and write())
Diffstat (limited to 'src/http-header-glue.c')
-rw-r--r-- | src/http-header-glue.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/src/http-header-glue.c b/src/http-header-glue.c index be1535a2..85840d31 100644 --- a/src/http-header-glue.c +++ b/src/http-header-glue.c @@ -750,6 +750,42 @@ static int http_response_append_buffer(request_st * const r, buffer * const mem, } +#ifdef HAVE_SPLICE +static int http_response_append_splice(request_st * const r, http_response_opts * const opts, buffer * const b, const int fd, unsigned int toread) { + /* check if worthwhile to splice() to avoid copying through userspace */ + /*assert(opts->simple_accum);*//*(checked in caller)*/ + if (r->resp_body_scratchpad >= toread + && (toread > 32768 + || (toread >= 8192 /*(!http_response_append_buffer_simple_accum())*/ + && r->write_queue.last && r->write_queue.last->file.is_temp))) { + + if (!buffer_is_blank(b)) { + /*(flush small reads previously accumulated in b)*/ + int rc = http_response_append_buffer(r, b, 0); /*(0 to flush)*/ + chunk_buffer_yield(b); /*(improve large buf reuse)*/ + if (__builtin_expect( (0 != rc), 0)) return -1; /* error */ + } + + /*assert(opts->fdfmt == S_IFSOCK || opts->fdfmt == S_IFIFO);*/ + ssize_t n = (opts->fdfmt == S_IFSOCK) + ? chunkqueue_append_splice_sock_tempfile( + &r->write_queue, fd, toread, r->conf.errh) + : chunkqueue_append_splice_pipe_tempfile( + &r->write_queue, fd, toread, r->conf.errh); + if (__builtin_expect( (n >= 0), 1)) { + if (0 == (r->resp_body_scratchpad -= n)) + r->resp_body_finished = 1; + return 1; /* success */ + } + else if (n != -EINVAL) + return -1; /* error */ + /*(fall through; target filesystem w/o splice() support)*/ + } + return 0; /* not handled */ +} +#endif + + static int http_response_append_mem(request_st * const r, const char * const mem, size_t len) { if (r->resp_decode_chunked) return http_chunk_decode_append_mem(r, mem, len); @@ -1159,6 +1195,19 @@ handler_t http_response_read(request_st * const r, http_response_opts * const op avail = buffer_string_space(b); if (0 == fdevent_ioctl_fionread(fd, opts->fdfmt, (int *)&toread)) { + + #ifdef HAVE_SPLICE + /* check if worthwhile to splice() to avoid copying to userspace */ + if (opts->simple_accum) { + int rc = http_response_append_splice(r, opts, b, fd, toread); + if (rc) { + if (__builtin_expect( (rc > 0), 1)) + break; + return HANDLER_ERROR; + } /*(fall through to handle traditionally)*/ + } + #endif + if (avail < toread) { uint32_t blen = buffer_clen(b); if (toread + blen < 4096) |