mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 22:01:31 +02:00
[MEDIUM] add the SN_CURR_SESS flag to the session to track open sessions
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.
This commit is contained in:
parent
cff6411f9a
commit
1e62de615b
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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,36 +1047,34 @@ 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);
|
||||
}
|
||||
|
||||
/* 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 (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);
|
||||
}
|
||||
|
||||
if (s->srv) {
|
||||
/* 3: When a server-side connection is released, we have to
|
||||
* count it and check for pending connections on this server.
|
||||
*/
|
||||
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 */
|
||||
rqf_cli = rqf_srv = ~s->req->flags;
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user