From 0499e3575c610bbe55c9e19f415ed965fc2d82c2 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 17 Dec 2010 07:13:42 +0100 Subject: [PATCH] [BUG] http: analyser optimizations broke pipelining HTTP pipelining currently needs to monitor the response buffer to wait for some free space to be able to send a response. It was not possible for the HTTP analyser to be called based on response buffer activity. Now we introduce a new buffer flag BF_WAKE_ONCE which is set when the HTTP request analyser is set on the response buffer and some activity is detected. This is not clean at all but once of the only ways to fix the issue before we make it possible to register events for analysers. Also it appeared that one realign condition did not cover all cases. --- include/types/buffers.h | 4 +++- src/proto_http.c | 3 ++- src/session.c | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/types/buffers.h b/include/types/buffers.h index 541e1d145..e7ddea4eb 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -115,13 +115,15 @@ #define BF_EXPECT_MORE 0x2000000 /* more data expected to be sent very soon (one-shoot) */ #define BF_SEND_DONTWAIT 0x4000000 /* don't wait for sending data (one-shoot) */ +#define BF_WAKE_ONCE 0x8000000 /* pretend there is activity on this buffer (one-shoot) */ + /* Use these masks to clear the flags before going back to lower layers */ #define BF_CLEAR_READ (~(BF_READ_NULL|BF_READ_PARTIAL|BF_READ_ERROR|BF_READ_ATTACHED)) #define BF_CLEAR_WRITE (~(BF_WRITE_NULL|BF_WRITE_PARTIAL|BF_WRITE_ERROR)) #define BF_CLEAR_TIMEOUT (~(BF_READ_TIMEOUT|BF_WRITE_TIMEOUT|BF_ANA_TIMEOUT)) /* Masks which define input events for stream analysers */ -#define BF_MASK_ANALYSER (BF_READ_ATTACHED|BF_READ_ACTIVITY|BF_READ_TIMEOUT|BF_ANA_TIMEOUT|BF_WRITE_ACTIVITY) +#define BF_MASK_ANALYSER (BF_READ_ATTACHED|BF_READ_ACTIVITY|BF_READ_TIMEOUT|BF_ANA_TIMEOUT|BF_WRITE_ACTIVITY|BF_WAKE_ONCE) /* Mask for static flags which cause analysers to be woken up when they change */ #define BF_MASK_STATIC (BF_OUT_EMPTY|BF_FULL|BF_SHUTR|BF_SHUTW|BF_SHUTR_NOW|BF_SHUTW_NOW) diff --git a/src/proto_http.c b/src/proto_http.c index 25421bcf8..ed3132324 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2390,7 +2390,7 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit) req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */ return 0; } - if (req->l <= req->size - global.tune.maxrewrite) + if (req->r < req->lr || req->r > req->data + req->size - global.tune.maxrewrite) http_buffer_heavy_realign(req, msg); } @@ -2411,6 +2411,7 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit) /* don't let a connection request be initiated */ buffer_dont_connect(req); s->rep->flags &= ~BF_EXPECT_MORE; /* speed up sending a previous response */ + s->rep->analysers |= an_bit; /* wake us up once it changes */ return 0; } } diff --git a/src/session.c b/src/session.c index c34ed9f65..0f5db314a 100644 --- a/src/session.c +++ b/src/session.c @@ -1506,6 +1506,7 @@ struct task *process_session(struct task *t) rq_prod_last = s->si[0].state; rq_cons_last = s->si[1].state; + s->req->flags &= ~BF_WAKE_ONCE; rqf_last = s->req->flags; if ((s->req->flags ^ flags) & BF_MASK_STATIC) @@ -1543,6 +1544,18 @@ struct task *process_session(struct task *t) s->si[1].state != rp_prod_last) { unsigned int flags = s->rep->flags; + if ((s->rep->flags & BF_MASK_ANALYSER) && + (s->rep->analysers & AN_REQ_WAIT_HTTP)) { + /* Due to HTTP pipelining, the HTTP request analyser might be waiting + * for some free space in the response buffer, so we might need to call + * it when something changes in the response buffer, but still we pass + * it the request buffer. Note that the SI state might very well still + * be zero due to us returning a flow of redirects! + */ + s->rep->analysers &= ~AN_REQ_WAIT_HTTP; + s->req->flags |= BF_WAKE_ONCE; + } + if (s->rep->prod->state >= SI_ST_EST) { int max_loops = global.tune.maxpollevents; unsigned int ana_list; @@ -1617,6 +1630,9 @@ struct task *process_session(struct task *t) if (s->req->analysers & ~req_ana_back) goto resync_request; + if ((s->req->flags & ~rqf_last) & BF_MASK_ANALYSER) + goto resync_request; + /* FIXME: here we should call protocol handlers which rely on * both buffers. */