diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index d216e49a8..d02c777c0 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include @@ -566,7 +566,7 @@ enum conn_hash_params_t { #define CONN_HASH_PARAMS_TYPE_COUNT 7 #define CONN_HASH_PAYLOAD_LEN \ - (((sizeof(((struct conn_hash_node *)0)->node.key)) * 8) - CONN_HASH_PARAMS_TYPE_COUNT) + (((sizeof(((struct conn_hash_node *)0)->key)) * 8) - CONN_HASH_PARAMS_TYPE_COUNT) #define CONN_HASH_GET_PAYLOAD(hash) \ (((hash) << CONN_HASH_PARAMS_TYPE_COUNT) >> CONN_HASH_PARAMS_TYPE_COUNT) @@ -660,7 +660,8 @@ struct connection { * A connection is identified by a hash generated from its specific parameters */ struct conn_hash_node { - struct eb64_node node; /* contains the hashing key */ + struct ceb_node node; /* indexes the hashing key for safe/idle/avail */ + uint64_t key; /* the hashing key, also used by session-owned */ struct connection *conn; /* connection owner of the node */ }; diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index a401bae06..3609d10aa 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -265,15 +265,17 @@ struct tree_occ { /* Each server will have one occurrence of this structure per thread */ struct srv_per_thread { struct mt_list streams; /* streams using this server (used by "shutdown server sessions") */ - struct eb_root idle_conns; /* Shareable idle connections */ - struct eb_root safe_conns; /* Safe idle connections */ - struct eb_root avail_conns; /* Connections in use, but with still new streams available */ struct mt_list sess_conns; /* Connections attached to a session which cannot be shared across clients */ /* Secondary idle conn storage used in parallel to idle/safe trees. * Used to sort them by last usage and purge them in reverse order. */ struct list idle_conn_list; + + /* connection trees to look them up by name */ + struct ceb_root *idle_conns; /* Shareable idle connections */ + struct ceb_root *safe_conns; /* Safe idle connections */ + struct ceb_root *avail_conns; /* Connections in use, but with still new streams available */ }; /* Each server will have one occurrence of this structure per thread group */ diff --git a/include/haproxy/server.h b/include/haproxy/server.h index 1b311e4a1..968e28599 100644 --- a/include/haproxy/server.h +++ b/include/haproxy/server.h @@ -96,8 +96,8 @@ int snr_resolution_error_cb(struct resolv_requester *requester, int error_code); struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char *ip_family); struct task *srv_cleanup_idle_conns(struct task *task, void *ctx, unsigned int state); void srv_release_conn(struct server *srv, struct connection *conn); -struct connection *srv_lookup_conn(struct eb_root *tree, uint64_t hash); -struct connection *srv_lookup_conn_next(struct connection *conn); +struct connection *srv_lookup_conn(struct ceb_root **tree, uint64_t hash); +struct connection *srv_lookup_conn_next(struct ceb_root **tree, struct connection *conn); void _srv_add_idle(struct server *srv, struct connection *conn, int is_safe); int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_safe); diff --git a/src/backend.c b/src/backend.c index ea3440c37..7b21c85b6 100644 --- a/src/backend.c +++ b/src/backend.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -1365,7 +1365,7 @@ check_tgid: * tree; unsafe requests are looked up in the safe conns tree. */ int search_tree = is_safe ? 1 : 0; // 0 = idle, 1 = safe - struct eb_root *tree; + struct ceb_root **tree; if (!srv->curr_idle_thr[i] || i == tid) continue; @@ -1387,7 +1387,7 @@ check_tgid: found = 1; break; } - conn = srv_lookup_conn_next(conn); + conn = srv_lookup_conn_next(tree, conn); } } while (!found && ++search_tree <= 1); @@ -1477,20 +1477,19 @@ static int do_connect_server(struct stream *s, struct connection *conn) * if any. */ static struct connection * -takeover_random_idle_conn(struct eb_root *root, int curtid) +takeover_random_idle_conn(struct ceb_root **root, int curtid) { struct conn_hash_node *hash_node; struct connection *conn = NULL; - struct eb64_node *node = eb64_first(root); - while (node) { - hash_node = eb64_entry(node, struct conn_hash_node, node); + hash_node = ceb64_item_first(root, node, key, struct conn_hash_node); + while (hash_node) { conn = hash_node->conn; - if (conn && conn->mux->takeover && conn->mux->takeover(conn, curtid, 1) == 0) { + if (conn->mux->takeover && conn->mux->takeover(conn, curtid, 1) == 0) { conn_delete_from_tree(conn, curtid); return conn; } - node = eb64_next(node); + hash_node = ceb64_item_next(root, node, key, hash_node); } return NULL; @@ -1696,7 +1695,7 @@ int be_reuse_connection(int64_t hash, struct session *sess, * Idle conns are necessarily looked up on the same thread so * that there is no concurrency issues. */ - if (!eb_is_empty(&srv->per_thr[tid].avail_conns)) { + if (!ceb_isempty(&srv->per_thr[tid].avail_conns)) { srv_conn = srv_lookup_conn(&srv->per_thr[tid].avail_conns, hash); if (srv_conn) { /* connection cannot be in idle list if used as an avail idle conn. */ @@ -1975,7 +1974,7 @@ int connect_server(struct stream *s) srv_conn->flags |= CO_FL_OPT_TOS; } - srv_conn->hash_node->node.key = hash; + srv_conn->hash_node->key = hash; } else if (srv && (srv->flags & SRV_F_STRICT_MAXCONN)) _HA_ATOMIC_DEC(&srv->curr_total_conns); } diff --git a/src/connection.c b/src/connection.c index 896dbc1a7..238a595e4 100644 --- a/src/connection.c +++ b/src/connection.c @@ -12,7 +12,7 @@ #include -#include +#include #include #include @@ -81,8 +81,26 @@ struct conn_tlv_list *conn_get_tlv(struct connection *conn, int type) */ void conn_delete_from_tree(struct connection *conn, int thr) { - LIST_DEL_INIT(&conn->idle_list); - eb64_delete(&conn->hash_node->node); + struct ceb_root **conn_tree; + struct server *srv = __objt_server(conn->target); + + /* We need to determine where the connection is attached, if at all. + * - if it's in a tree and not in the idle_list, it's the avail_tree + * - if it's in a tree and has CO_FL_SAFE_LIST, it's the safe_tree + * - if it's in a tree and has CO_FL_IDLE_LIST, it's the idle_tree + * - if it's not in a tree and has CO_FL_SESS_IDLE, it's in the + * session's list (but we don't care here). + */ + if (LIST_INLIST(&conn->idle_list)) { + LIST_DEL_INIT(&conn->idle_list); + conn_tree = (conn->flags & CO_FL_SAFE_LIST) ? + &srv->per_thr[thr].safe_conns : + &srv->per_thr[thr].idle_conns; + } else { + conn_tree = &srv->per_thr[thr].avail_conns; + } + + ceb64_item_delete(conn_tree, node, key, conn->hash_node); } int conn_create_mux(struct connection *conn, int *closed_connection) @@ -556,7 +574,7 @@ static void conn_backend_deinit(struct connection *conn) /* Make sure the connection is not left in the idle connection tree */ if (conn->hash_node != NULL) - BUG_ON(conn->hash_node->node.node.leaf_p != NULL); + BUG_ON(ceb_intree(&conn->hash_node->node)); pool_free(pool_head_conn_hash_node, conn->hash_node); conn->hash_node = NULL; @@ -2992,7 +3010,7 @@ int conn_reverse(struct connection *conn) } hash = conn_calculate_hash(&hash_params); - conn->hash_node->node.key = hash; + conn->hash_node->key = hash; conn->target = &srv->obj_type; srv_use_conn(srv, conn); diff --git a/src/mux_fcgi.c b/src/mux_fcgi.c index fc714d5a8..0dac901fe 100644 --- a/src/mux_fcgi.c +++ b/src/mux_fcgi.c @@ -3812,7 +3812,7 @@ static void fcgi_detach(struct sedesc *sd) TRACE_DEVEL("reusable idle connection", FCGI_EV_STRM_END, fconn->conn); return; } - else if (!fconn->conn->hash_node->node.node.leaf_p && + else if (!ceb_intree(&fconn->conn->hash_node->node) && fcgi_avail_streams(fconn->conn) > 0 && objt_server(fconn->conn->target) && !LIST_INLIST(&fconn->conn->sess_el)) { srv_add_to_avail_list(__objt_server(fconn->conn->target), fconn->conn); diff --git a/src/mux_h2.c b/src/mux_h2.c index 309e06e63..f126e6a23 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -5630,7 +5630,7 @@ static void h2_detach(struct sedesc *sd) return; } - else if (!h2c->conn->hash_node->node.node.leaf_p && + else if (!ceb_intree(&h2c->conn->hash_node->node) && h2_avail_streams(h2c->conn) > 0 && objt_server(h2c->conn->target) && !LIST_INLIST(&h2c->conn->sess_el)) { srv_add_to_avail_list(__objt_server(h2c->conn->target), h2c->conn); diff --git a/src/mux_quic.c b/src/mux_quic.c index e51c99fb6..0e660c0af 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -3936,7 +3936,7 @@ static void qmux_strm_detach(struct sedesc *sd) conn = NULL; goto end; } - else if (!conn->hash_node->node.node.leaf_p && + else if (!ceb_intree(&conn->hash_node->node) && qmux_avail_streams(conn) && objt_server(conn->target)) { TRACE_DEVEL("mark connection as available for reuse", QMUX_EV_STRM_END, conn); diff --git a/src/mux_spop.c b/src/mux_spop.c index 2583b3c9e..b14dbc227 100644 --- a/src/mux_spop.c +++ b/src/mux_spop.c @@ -3069,7 +3069,7 @@ static void spop_detach(struct sedesc *sd) TRACE_DEVEL("reusable idle connection", SPOP_EV_STRM_END); return; } - else if (!spop_conn->conn->hash_node->node.node.leaf_p && + else if (!ceb_intree(&spop_conn->conn->hash_node->node) && spop_avail_streams(spop_conn->conn) > 0 && objt_server(spop_conn->conn->target) && !LIST_INLIST(&spop_conn->conn->sess_el)) { srv_add_to_avail_list(__objt_server(spop_conn->conn->target), spop_conn->conn); diff --git a/src/server.c b/src/server.c index 2ce1151be..be1ba5549 100644 --- a/src/server.c +++ b/src/server.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -5976,9 +5977,9 @@ static int srv_init_per_thr(struct server *srv) return -1; for (i = 0; i < global.nbthread; i++) { - srv->per_thr[i].idle_conns = EB_ROOT; - srv->per_thr[i].safe_conns = EB_ROOT; - srv->per_thr[i].avail_conns = EB_ROOT; + srv->per_thr[i].idle_conns = NULL; + srv->per_thr[i].safe_conns = NULL; + srv->per_thr[i].avail_conns = NULL; MT_LIST_INIT(&srv->per_thr[i].sess_conns); MT_LIST_INIT(&srv->per_thr[i].streams); @@ -7272,17 +7273,14 @@ void srv_release_conn(struct server *srv, struct connection *conn) /* retrieve a connection from its in * returns NULL if no connection found */ -struct connection *srv_lookup_conn(struct eb_root *tree, uint64_t hash) +struct connection *srv_lookup_conn(struct ceb_root **tree, uint64_t hash) { - struct eb64_node *node = NULL; + struct conn_hash_node *hash_node; struct connection *conn = NULL; - struct conn_hash_node *hash_node = NULL; - node = eb64_lookup(tree, hash); - if (node) { - hash_node = eb64_entry(node, struct conn_hash_node, node); + hash_node = ceb64_item_lookup(tree, node, key, hash, struct conn_hash_node); + if (hash_node) conn = hash_node->conn; - } return conn; } @@ -7290,19 +7288,15 @@ struct connection *srv_lookup_conn(struct eb_root *tree, uint64_t hash) /* retrieve the next connection sharing the same hash as * returns NULL if no connection found */ -struct connection *srv_lookup_conn_next(struct connection *conn) +struct connection *srv_lookup_conn_next(struct ceb_root **tree, struct connection *conn) { - struct eb64_node *node = NULL; - struct connection *next_conn = NULL; - struct conn_hash_node *hash_node = NULL; + struct conn_hash_node *hash_node; - node = eb64_next_dup(&conn->hash_node->node); - if (node) { - hash_node = eb64_entry(node, struct conn_hash_node, node); - next_conn = hash_node->conn; - } + hash_node = ceb64_item_next_dup(tree, node, key, conn->hash_node); + if (hash_node) + conn = hash_node->conn; - return next_conn; + return conn; } /* Add in idle trees. Set if connection is deemed safe @@ -7317,11 +7311,11 @@ struct connection *srv_lookup_conn_next(struct connection *conn) */ void _srv_add_idle(struct server *srv, struct connection *conn, int is_safe) { - struct eb_root *tree = is_safe ? &srv->per_thr[tid].safe_conns : + struct ceb_root **tree = is_safe ? &srv->per_thr[tid].safe_conns : &srv->per_thr[tid].idle_conns; /* first insert in idle or safe tree. */ - eb64_insert(tree, &conn->hash_node->node); + ceb64_item_insert(tree, node, key, conn->hash_node); /* insert in list sorted by connection usage. */ LIST_APPEND(&srv->per_thr[tid].idle_conn_list, &conn->idle_list); @@ -7344,8 +7338,8 @@ int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_saf ((srv->proxy->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR) && ha_used_fds < global.tune.pool_high_count && (srv->max_idle_conns == -1 || srv->max_idle_conns > srv->curr_idle_conns) && - ((eb_is_empty(&srv->per_thr[tid].safe_conns) && - (is_safe || eb_is_empty(&srv->per_thr[tid].idle_conns))) || + ((ceb_isempty(&srv->per_thr[tid].safe_conns) && + (is_safe || ceb_isempty(&srv->per_thr[tid].idle_conns))) || (ha_used_fds < global.tune.pool_low_count && (srv->curr_used_conns + srv->curr_idle_conns <= MAX(srv->curr_used_conns, srv->est_need_conns) + srv->low_idle_conns || @@ -7403,7 +7397,7 @@ void srv_add_to_avail_list(struct server *srv, struct connection *conn) { /* connection cannot be in idle list if used as an avail idle conn. */ BUG_ON(LIST_INLIST(&conn->idle_list)); - eb64_insert(&srv->per_thr[tid].avail_conns, &conn->hash_node->node); + ceb64_item_insert(&srv->per_thr[tid].avail_conns, node, key, conn->hash_node); } struct task *srv_cleanup_idle_conns(struct task *task, void *context, unsigned int state) @@ -7504,11 +7498,11 @@ remove: */ static void srv_close_idle_conns(struct server *srv) { - struct eb_root **cleaned_tree; + struct ceb_root ***cleaned_tree; int i; for (i = 0; i < global.nbthread; ++i) { - struct eb_root *conn_trees[] = { + struct ceb_root **conn_trees[] = { &srv->per_thr[i].idle_conns, &srv->per_thr[i].safe_conns, &srv->per_thr[i].avail_conns, @@ -7516,11 +7510,10 @@ static void srv_close_idle_conns(struct server *srv) }; for (cleaned_tree = conn_trees; *cleaned_tree; ++cleaned_tree) { - while (!eb_is_empty(*cleaned_tree)) { - struct eb64_node *node = eb64_first(*cleaned_tree); - struct conn_hash_node *conn_hash_node = eb64_entry(node, struct conn_hash_node, node); - struct connection *conn = conn_hash_node->conn; + while (!ceb_isempty(*cleaned_tree)) { + struct connection *conn; + conn = ceb64_item_first(*cleaned_tree, node, key, struct conn_hash_node)->conn; if (conn->ctrl->ctrl_close) conn->ctrl->ctrl_close(conn); conn_delete_from_tree(conn, i); diff --git a/src/session.c b/src/session.c index 103fb159a..a08e08ac9 100644 --- a/src/session.c +++ b/src/session.c @@ -785,7 +785,7 @@ struct connection *session_get_conn(struct session *sess, void *target, int64_t /* Search into pconns for a connection with matching params and available streams. */ list_for_each_entry(srv_conn, &pconns->conn_list, sess_el) { - if ((srv_conn->hash_node && srv_conn->hash_node->node.key == hash) && + if ((srv_conn->hash_node && srv_conn->hash_node->key == hash) && srv_conn->mux && (srv_conn->mux->avail_streams(srv_conn) > 0) && !(srv_conn->flags & CO_FL_WAIT_XPRT)) {