]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[OPTIM] buffer: new BF_READ_DONTWAIT flag reduces EAGAIN rates
authorWilly Tarreau <w@1wt.eu>
Sat, 21 Mar 2009 20:10:04 +0000 (21:10 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 21 Mar 2009 20:57:30 +0000 (21:57 +0100)
When the reader does not expect to read lots of data, it can
set BF_READ_DONTWAIT on the request buffer. When it is set,
the stream_sock_read callback will not try to perform multiple
reads, it will return after only one, and clear the flag.
That way, we can immediately return when waiting for an HTTP
request without trying to read again.

On pure request/responses schemes such as monitor-uri or
redirects, this has completely eliminated the EAGAIN occurrences
and the epoll_ctl() calls, resulting in a performance increase of
about 10%. Similar effects should be observed once we support
HTTP keep-alive since we'll immediately disable reads once we
get a full request.

include/types/buffers.h
src/client.c
src/proto_http.c
src/proto_uxst.c
src/stream_sock.c

index 3b0c3a12ae9e8be40e0894cf773ee672e85a587b..faad019b2e02465aa47ff54872d5a45592a8ae37 100644 (file)
@@ -84,6 +84,7 @@
 #define BF_ANA_TIMEOUT    0x080000  /* the analyser timeout has expired */
 #define BF_READ_ATTACHED  0x100000  /* the read side is attached for the first time */
 #define BF_KERN_SPLICING  0x200000  /* kernel splicing desired for this buffer */
+#define BF_READ_DONTWAIT  0x400000  /* wake the task up after every read (eg: HTTP request) */
 
 /* 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))
index 765a54b374d347843558d7058cb5f545ab7ca0e5..05ee8d540ce5ec002ac7198e6a5932bd2c5ff182 100644 (file)
@@ -374,8 +374,10 @@ int event_accept(int fd) {
 
                s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */
 
-               if (p->mode == PR_MODE_HTTP) /* reserve some space for header rewriting */
+               if (p->mode == PR_MODE_HTTP) /* reserve some space for header rewriting */
                        s->req->max_len -= MAXREWRITE;
+                       s->req->flags |= BF_READ_DONTWAIT; /* one read is usually enough */
+               }
 
                /* activate default analysers enabled for this listener */
                s->req->analysers = l->analysers;
index 8c8ff634098718dbdfe571c4c8cbdef8cdecd2fa..8ab41992be91031de9845ead10e396a8984ee6b7 100644 (file)
@@ -1648,6 +1648,8 @@ int http_process_request(struct session *s, struct buffer *req)
                }
 
                buffer_write_dis(req);
+               req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
+
                /* just set the request timeout once at the beginning of the request */
                if (!tick_isset(req->analyse_exp))
                        req->analyse_exp = tick_add_ifset(now_ms, s->fe->timeout.httpreq);
index baf91ef1e67264bf01d04b5e29ebb56c6a9c9a67..0edc2aff274b4cfb77caec2e5d135e9a81a31ec5 100644 (file)
@@ -488,6 +488,7 @@ int uxst_event_accept(int fd) {
                s->req->cons = &s->si[1];
                s->si[0].ib = s->si[1].ob = s->req;
                s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */
+               s->req->flags |= BF_READ_DONTWAIT; /* we plan to read small requests */
 
                s->req->analysers = l->analysers;
 
@@ -684,6 +685,7 @@ int uxst_req_analyser_stats(struct session *s, struct buffer *req)
                        return 0;
                }
                /* don't forward nor abort */
+               req->flags |= BF_READ_DONTWAIT; /* we plan to read small requests */
                return 0;
 
        case STATS_ST_REP:
index a942d408178d2eebeaf01230b586bbddd744f758..83c3c8840945e892fe49605e96fcc4f2d0139611 100644 (file)
@@ -421,7 +421,7 @@ int stream_sock_read(int fd) {
                                        break;
                        }
 
-                       if (--read_poll <= 0)
+                       if ((b->flags & BF_READ_DONTWAIT) || --read_poll <= 0)
                                break;
                }
                else if (ret == 0) {
@@ -467,13 +467,14 @@ int stream_sock_read(int fd) {
        /* we have to wake up if there is a special event or if we don't have
         * any more data to forward.
         */
-       if ((b->flags & (BF_READ_NULL|BF_READ_ERROR|BF_SHUTR)) ||
+       if ((b->flags & (BF_READ_NULL|BF_READ_ERROR|BF_SHUTR|BF_READ_DONTWAIT)) ||
            !b->to_forward ||
            si->state != SI_ST_EST ||
            b->cons->state != SI_ST_EST ||
            (si->flags & SI_FL_ERR))
                task_wakeup(si->owner, TASK_WOKEN_IO);
        
+       b->flags &= ~BF_READ_DONTWAIT;
        fdtab[fd].ev &= ~FD_POLL_IN;
        return retval;