]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add the SN_CURR_SESS flag to the session to track open sessions
authorWilly Tarreau <w@1wt.eu>
Tue, 11 Nov 2008 19:20:02 +0000 (20:20 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 11 Nov 2008 19:26:58 +0000 (20:26 +0100)
It is quite hard to track when the current session has already been counted
or discounted from the server's total number of established sessions. For
this reason, we introduce a new session flag, SN_CURR_SESS, which indicates
if the current session is one of those reported by the server or not. It
simplifies session accounting and makes it far more robust. It also makes
it possible to perform a last-minute cleanup during session_free().

Right now, with this fix and a few more buffer transitions fixes, no session
were found to remain after a test.

include/types/session.h
src/backend.c
src/proto_http.c
src/session.c

index 8b87be21af36d72fce8ae5c4b19aaf7c02b86719..1177924c571fc301e23555314bed4375ab9bc22e 100644 (file)
@@ -47,7 +47,7 @@
 #define SN_BE_ASSIGNED 0x00000008      /* a backend was assigned. Conns are accounted. */
 #define SN_CONN_CLOSED 0x00000010      /* "Connection: close" was present or added */
 #define SN_MONITOR     0x00000020      /* this session comes from a monitoring system */
-/* unused:              0x00000040 */
+#define SN_CURR_SESS   0x00000040      /* a connection is currently being counted on the server */
 #define SN_FRT_ADDR_SET        0x00000080      /* set if the frontend address has been filled */
 #define SN_REDISP      0x00000100      /* set if this session was redispatched from one server to another */
 #define SN_CONN_TAR    0x00000200      /* set if this session is turning around before reconnecting */
index de0537a198fdff076b6641fdcfc786fd457c63a0..0d6fef12f221a7d90a92b4d3f788fc9ea8f82756 100644 (file)
@@ -1820,6 +1820,7 @@ int connect_server(struct session *s)
 
        s->req->cons->state = SI_ST_CON;
        if (s->srv) {
+               s->flags |= SN_CURR_SESS;
                s->srv->cur_sess++;
                if (s->srv->cur_sess > s->srv->cur_sess_max)
                        s->srv->cur_sess_max = s->srv->cur_sess;
index 6f2dab3cf1a9c298c2406916ef8e7ab92cdf2dc3..fe59841a60a97117c8601825e1c06cc650e73471 100644 (file)
@@ -963,8 +963,8 @@ void process_session(struct task *t, int *next)
         * upper by setting flags into the buffers. Note that the side towards
         * the client cannot have connect (hence retryable) errors.
         */
-       if (unlikely(s->si[0].state == SI_ST_EST)) {
-               if (s->si[0].flags & SI_FL_ERR) {
+       if (s->si[0].state == SI_ST_EST) {
+               if (unlikely(s->si[0].flags & SI_FL_ERR)) {
                        s->si[0].state = SI_ST_CLO;
                        fd_delete(s->si[0].fd);
                        stream_int_report_error(&s->si[0]);
@@ -972,10 +972,13 @@ void process_session(struct task *t, int *next)
        }
 
        if (s->si[1].state == SI_ST_EST) {
-               if (s->si[1].flags & SI_FL_ERR) {
+               if (unlikely(s->si[1].flags & SI_FL_ERR)) {
                        s->si[1].state = SI_ST_CLO;
                        fd_delete(s->si[1].fd);
                        stream_int_report_error(&s->si[1]);
+                       s->be->failed_resp++;
+                       if (s->srv)
+                               s->srv->failed_resp++;
                }
        }
        else if (s->si[1].state != SI_ST_INI && s->si[1].state != SI_ST_CLO) {
@@ -1044,35 +1047,33 @@ void process_session(struct task *t, int *next)
                s->req->cons->shutw(s->req->cons);
        }
 
+       if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTW)) {
+               /* write closed on server side, let's forward it to the client */
+               buffer_shutr_now(s->req);
+               s->req->prod->shutr(s->req->prod);
+       }
+
        if (unlikely((s->rep->flags & (BF_SHUTW|BF_EMPTY|BF_HIJACK|BF_WRITE_ENA|BF_SHUTR)) == (BF_EMPTY|BF_WRITE_ENA|BF_SHUTR)) ||
            unlikely((s->rep->flags & (BF_SHUTW|BF_SHUTW_NOW)) == BF_SHUTW_NOW)) {
                buffer_shutw(s->rep);
                s->rep->cons->shutw(s->rep->cons);
        }
 
+       if (unlikely((s->rep->flags & (BF_SHUTW|BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTW)) {
+               /* write closed on client side, let's forward it to the server */
+               buffer_shutr_now(s->rep);
+               s->rep->prod->shutr(s->rep->prod);
+       }
+
        /* 3: When a server-side connection is released, we have to
         * count it and check for pending connections on this server.
-        * FIXME: the test below is not accurate. An audit is needed
-        * to find all uncaught transitions. We need a way to ensure
-        * that shutdowns called right after connect() after TAR will
-        * correctly be caught for instance. In fact we need a way to
-        * track when the connection is assigned to the server.
         */
-       if (unlikely(s->req->cons->state == SI_ST_CLO &&
-                    (s->req->cons->prev_state == SI_ST_EST || s->req->cons->prev_state == SI_ST_CON))) {
-               /* Count server-side errors (but not timeouts). */
-               if (s->req->flags & BF_WRITE_ERROR) {
-                       s->be->failed_resp++;
-                       if (s->srv)
-                               s->srv->failed_resp++;
-               }
-
-               if (s->srv) {
-                       s->srv->cur_sess--;
-                       sess_change_server(s, NULL);
-                       if (may_dequeue_tasks(s->srv, s->be))
-                               process_srv_queue(s->srv);
-               }
+       if (unlikely(s->req->cons->state == SI_ST_CLO && s->srv && (s->flags & SN_CURR_SESS))) {
+               s->flags &= ~SN_CURR_SESS;
+               s->srv->cur_sess--;
+               sess_change_server(s, NULL);
+               if (may_dequeue_tasks(s->srv, s->be))
+                       process_srv_queue(s->srv);
        }
 
        /* Dirty trick: force one first pass everywhere */
@@ -1153,7 +1154,8 @@ void process_session(struct task *t, int *next)
                                         * count it and check for pending connections on this server.
                                         */
                                        if (s->req->cons->state == SI_ST_CLO) {
-                                               if (s->srv) {
+                                               if (s->srv && (s->flags & SN_CURR_SESS)) {
+                                                       s->flags &= ~SN_CURR_SESS;
                                                        s->srv->cur_sess--;
                                                        sess_change_server(s, NULL);
                                                        if (may_dequeue_tasks(s->srv, s->be))
@@ -3734,7 +3736,8 @@ int sess_update_st_con_tcp(struct session *s, struct stream_interface *si)
                si->state = SI_ST_CER;
                fd_delete(si->fd);
 
-               if (s->srv) {
+               if (s->srv && (s->flags & SN_CURR_SESS)) {
+                       s->flags &= ~SN_CURR_SESS;
                        s->srv->cur_sess--;
                        sess_change_server(s, NULL);
                        si->err_loc = s->srv;
@@ -3759,7 +3762,8 @@ int sess_update_st_con_tcp(struct session *s, struct stream_interface *si)
                /* give up */
                req->wex = TICK_ETERNITY;
                fd_delete(si->fd);
-               if (s->srv) {
+               if (s->srv && (s->flags & SN_CURR_SESS)) {
+                       s->flags &= ~SN_CURR_SESS;
                        s->srv->cur_sess--;
                        sess_change_server(s, NULL);
                }
index ceef0b7dfe7edc99c2afc6b0c161f43f0a6a2a7d..fb7de4a3b5bc62beac9f6d207a1f1036ead4e04c 100644 (file)
@@ -37,8 +37,13 @@ void session_free(struct session *s)
 
        if (s->pend_pos)
                pendconn_free(s->pend_pos);
-       if (s->srv)  /* there may be requests left pending in queue */
+       if (s->srv) { /* there may be requests left pending in queue */
+               if (s->flags & SN_CURR_SESS) {
+                       s->flags &= ~SN_CURR_SESS;
+                       s->srv->cur_sess--;
+               }
                process_srv_queue(s->srv);
+       }
        if (unlikely(s->srv_conn)) {
                /* the session still has a reserved slot on a server, but
                 * it should normally be only the same as the one above,