int session_check_idle_conn(struct session *sess, struct connection *conn);
struct connection *session_get_conn(struct session *sess, void *target, int64_t hash);
void session_unown_conn(struct session *sess, struct connection *conn);
+int session_detach_idle_conn(struct session *sess, struct connection *conn);
/* Remove the refcount from the session to the tracked counters, and clear the
* pointer to ensure this is only performed once. The caller is responsible for
((conn->flags ^ old_flags) & CO_FL_NOTIFY_DONE) ||
((old_flags & CO_FL_WAIT_XPRT) && !(conn->flags & CO_FL_WAIT_XPRT))) &&
conn->mux && conn->mux->wake) {
- uint conn_in_list = conn->flags & CO_FL_LIST_MASK;
+ uint conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
struct server *srv = objt_server(conn->target);
if (conn_in_list) {
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
- conn_delete_from_tree(conn);
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_detach_idle_conn(conn->owner, conn))
+ conn_in_list = 0;
+ }
+ else {
+ conn_delete_from_tree(conn);
+ }
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
}
conn = fconn->conn;
TRACE_POINT(FCGI_EV_FCONN_WAKE, conn);
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
- if (conn_in_list)
- conn_delete_from_tree(conn);
+ conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
+ if (conn_in_list) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_detach_idle_conn(conn->owner, conn))
+ conn_in_list = 0;
+ }
+ else {
+ conn_delete_from_tree(conn);
+ }
+ }
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
} else {
*/
if (fconn->conn->flags & CO_FL_LIST_MASK)
conn_delete_from_tree(fconn->conn);
+ else if (fconn->conn->flags & CO_FL_SESS_IDLE)
+ session_detach_idle_conn(fconn->conn->owner, fconn->conn);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
/* Remove the connection from the list, to be sure nobody attempts
* to use it while we handle the I/O events
*/
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
- if (conn_in_list)
- conn_delete_from_tree(conn);
+ conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
+ if (conn_in_list) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_detach_idle_conn(conn->owner, conn))
+ conn_in_list = 0;
+ }
+ else {
+ conn_delete_from_tree(conn);
+ }
+ }
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
} else {
/* Remove the connection from the list, to be sure nobody attempts
* to use it while we handle the I/O events
*/
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
- if (conn_in_list)
- conn_delete_from_tree(conn);
+ conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
+ if (conn_in_list) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_detach_idle_conn(conn->owner, conn))
+ conn_in_list = 0;
+ }
+ else {
+ conn_delete_from_tree(conn);
+ }
+ }
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
} else {
*/
if (h2c->conn->flags & CO_FL_LIST_MASK)
conn_delete_from_tree(h2c->conn);
+ else if (h2c->conn->flags & CO_FL_SESS_IDLE)
+ session_detach_idle_conn(h2c->conn->owner, h2c->conn);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
conn = spop_conn->conn;
TRACE_POINT(SPOP_EV_SPOP_CONN_WAKE, conn);
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
- if (conn_in_list)
- conn_delete_from_tree(conn);
+ conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
+ if (conn_in_list) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_detach_idle_conn(conn->owner, conn))
+ conn_in_list = 0;
+ }
+ else {
+ conn_delete_from_tree(conn);
+ }
+ }
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
} else {
*/
if (spop_conn->conn->flags & CO_FL_LIST_MASK)
conn_delete_from_tree(spop_conn->conn);
+ else if (spop_conn->conn->flags & CO_FL_SESS_IDLE)
+ session_detach_idle_conn(spop_conn->conn->owner, spop_conn->conn);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
}
+/* Remove <conn> connection from <sess> session. Contrary to
+ * session_unown_conn(), this function is not protected by a lock, so the
+ * caller is responsible to properly use idle_conns_lock prior to calling it.
+ *
+ * Another notable difference is that <owner> member of <conn> is not resetted.
+ * This is a convenience as this function usage is generally coupled with a
+ * following session_reinsert_idle_conn().
+ *
+ * Must be called with idle_conns_lock held.
+ *
+ * Returns true on connection removal, false if it was already not stored.
+ */
+int session_detach_idle_conn(struct session *sess, struct connection *conn)
+{
+ struct sess_priv_conns *pconns;
+
+ if (!LIST_INLIST(&conn->sess_el))
+ return 0;
+
+ /* This function is reserved for idle private connections. */
+ BUG_ON(!(conn->flags & CO_FL_SESS_IDLE));
+
+ --sess->idle_conns;
+ LIST_DEL_INIT(&conn->sess_el);
+
+ pconns = sess_get_sess_conns(sess, conn->target);
+ BUG_ON(!pconns); /* if conn is attached to session, its sess_conn must exists. */
+ if (LIST_ISEMPTY(&pconns->conn_list)) {
+ /* Remove sess_conn element as no connection left in it. */
+ LIST_DELETE(&pconns->sess_el);
+ MT_LIST_DELETE(&pconns->srv_el);
+ pool_free(pool_head_sess_priv_conns, pconns);
+ }
+
+ return 1;
+}
+
/*
* Local variables:
}
ctx = context;
conn = ctx->conn;
- conn_in_list = conn->flags & CO_FL_LIST_MASK;
- if (conn_in_list)
- conn_delete_from_tree(conn);
+
+ /* Remove the connection from the list, to be sure nobody attempts
+ * to use it while we handle the I/O events
+ */
+ conn_in_list = conn->flags & (CO_FL_LIST_MASK|CO_FL_SESS_IDLE);
+ if (conn_in_list) {
+ if (conn->flags & CO_FL_SESS_IDLE) {
+ if (!session_detach_idle_conn(conn->owner, conn))
+ conn_in_list = 0;
+ }
+ else {
+ conn_delete_from_tree(conn);
+ }
+ }
+
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
} else {
ctx = context;