From 4d7510045d47cbb1fa72d6a5ec18b3bcb5de8fad Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 8 Dec 2014 19:59:07 +0100 Subject: EXP: support splicing all the time This seems to work fine, though it is still possible to disable it using -dS and/or without setting option splice-response. --- src/proto_http.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/session.c | 2 +- 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/src/proto_http.c b/src/proto_http.c index db17e2c..e4e8379 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -10,6 +10,7 @@ * */ +#define _GNU_SOURCE #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include @@ -55,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -3186,6 +3189,7 @@ struct hterm_ctx { static struct chunk hterm_chunk; static struct buffer *hterm_buf; +static struct pipe *hterm_master_pipe; static int httpterm_send_http_headers(struct stream_interface *si) { @@ -3330,13 +3334,68 @@ static void httpterm_io_handler(struct stream_interface *si) tmp_chunk.str = hterm_chunk.str + offset; tmp_chunk.len = max; - /* Note that we cannot use hterm_chunk.str + offset below as we'd corrupt the buffer */ - hterm_buf->p = hterm_buf->data; - hterm_buf->i = max; - hterm_buf->o = 0; + swp = NULL; + if (buffer_empty(si->ib->buf)) { + if (!hctx->req_chunked && + (si->ib->flags & CF_KERN_SPLICING)) { - swp = bi_swpbuf(si->ib, hterm_buf); - if (!swp || swp == hterm_buf) { + if (unlikely(si->ib->pipe == NULL)) { + if (pipes_used >= global.maxpipes || !(si->ib->pipe = get_pipe())) { + si->ib->flags &= ~CF_KERN_SPLICING; + goto abort_splice; + } + } + if (si->ib->pipe->data < hctx->req_size) { + int ret; + + if (global.tune.pipesize && max > global.tune.pipesize) + max = global.tune.pipesize; + + ret = tee(hterm_master_pipe->cons, si->ib->pipe->prod, max, SPLICE_F_NONBLOCK); + max = ret; + if (ret > 0) { + si->ib->flags |= CF_READ_PARTIAL; + si->ib->pipe->data += ret; + if (si->ib->to_forward) { + unsigned long fwd = ret; + if (si->ib->to_forward != CHN_INFINITE_FORWARD) { + if (fwd > si->ib->to_forward) + fwd = si->ib->to_forward; + si->ib->to_forward -= fwd; + } + } + } + else if (ret == 0 || errno == EAGAIN) { + si->flags |= SI_FL_WAIT_ROOM; + goto fail; + } + } + swp = hterm_buf; /* pretend the operation was performed */ + } + else { + abort_splice: + /* Attempt a zero-copy without splice */ + + /* Note that we cannot use hterm_chunk.str + offset + * below as we'd corrupt the buffer. + */ + hterm_buf->p = hterm_buf->data; + hterm_buf->i = max; + hterm_buf->o = 0; + + swp = bi_swpbuf(si->ib, hterm_buf); + if (swp == hterm_buf) + swp = NULL; + } + } + else if (!hctx->req_chunked && + (si->ib->flags & CF_KERN_SPLICING)) { + /* let the buffer flush */ + si->flags |= SI_FL_WAIT_ROOM; + goto fail; + } + + if (!swp) { /* zero copy failed */ if (bi_putchk(si->ib, &tmp_chunk) == -1) goto fail; @@ -3433,6 +3492,22 @@ int http_handle_httpterm(struct session *s, struct channel *req) hterm_chunk.len = hterm_chunk.size; } + if (unlikely(!hterm_master_pipe && (global.tune.options & GTUNE_USE_SPLICE))) { + hterm_master_pipe = get_pipe(); + if (hterm_master_pipe) { + int total = 0; + int ret; + struct iovec v = { .iov_base = hterm_chunk.str, + .iov_len = hterm_chunk.size, }; + + do { + ret = vmsplice(hterm_master_pipe->prod, &v, 1, SPLICE_F_NONBLOCK); + if (ret > 0) + total += ret; + } while (ret > 0 && (global.tune.pipesize && total < global.tune.pipesize)); + } + } + appctx = si_appctx(si); appctx->st0 = appctx->st1 = appctx->st2 = 0; diff --git a/src/session.c b/src/session.c index be824be..52ab9f6 100644 --- a/src/session.c +++ b/src/session.c @@ -2461,7 +2461,7 @@ struct task *process_session(struct task *t) s->rep->to_forward && (global.tune.options & GTUNE_USE_SPLICE) && (objt_conn(s->si[0].end) && __objt_conn(s->si[0].end)->xprt && __objt_conn(s->si[0].end)->xprt->snd_pipe) && - (objt_conn(s->si[1].end) && __objt_conn(s->si[1].end)->xprt && __objt_conn(s->si[1].end)->xprt->rcv_pipe) && + //(objt_conn(s->si[1].end) && __objt_conn(s->si[1].end)->xprt && __objt_conn(s->si[1].end)->xprt->rcv_pipe) && (pipes_used < global.maxpipes) && (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_RTR) || (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) && -- 1.7.12.1