} __attribute__((packed));
+/* node for backend connection in the idle trees for http-reuse
+ * A connection is identified by a hash generated from its specific parameters
+ */
+struct conn_hash_node {
+ struct ceb_node node; /* indexes the hashing key for safe/idle/avail */
+ uint64_t key; /* the hashing key, also used by session-owned */
+};
+
/* This structure describes a connection with its methods and data.
* A connection may be performed to proxy or server via a local or remote
* socket, and can also be made to an internal applet. It can support
/* used to identify a backend connection for http-reuse,
* thus only present if conn.target is of type OBJ_TYPE_SERVER
*/
- struct conn_hash_node *hash_node;
+ struct conn_hash_node hash_node;
/* Members used if connection must be reversed. */
struct {
uint8_t tos; /* set ip tos, if CO_FL_OPT_TOS is set */
};
-/* node for backend connection in the idle trees for http-reuse
- * A connection is identified by a hash generated from its specific parameters
- */
-struct conn_hash_node {
- 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 */
-};
-
struct mux_proto_list {
const struct ist token; /* token name and length. Empty is catch-all */
enum proto_proxy_mode mode;
#include <haproxy/task-t.h>
extern struct pool_head *pool_head_connection;
-extern struct pool_head *pool_head_conn_hash_node;
extern struct pool_head *pool_head_sockaddr;
extern struct pool_head *pool_head_pp_tlv_128;
extern struct pool_head *pool_head_pp_tlv_256;
void conn_free(struct connection *conn);
void conn_release(struct connection *conn);
void conn_set_errno(struct connection *conn, int err);
-struct conn_hash_node *conn_alloc_hash_node(struct connection *conn);
struct sockaddr_storage *sockaddr_alloc(struct sockaddr_storage **sap, const struct sockaddr_storage *orig, socklen_t len);
void sockaddr_free(struct sockaddr_storage **sap);
static struct connection *
takeover_random_idle_conn(struct ceb_root **root, int curtid)
{
- struct conn_hash_node *hash_node;
struct connection *conn = NULL;
- hash_node = ceb64_item_first(root, node, key, struct conn_hash_node);
- while (hash_node) {
- conn = hash_node->conn;
+ conn = ceb64_item_first(root, hash_node.node, hash_node.key, struct connection);
+ while (conn) {
if (conn->mux->takeover && conn->mux->takeover(conn, curtid, 1) == 0) {
conn_delete_from_tree(conn, curtid);
return conn;
}
- hash_node = ceb64_item_next(root, node, key, hash_node);
+ conn = ceb64_item_next(root, hash_node.node, hash_node.key, conn);
}
return NULL;
srv_conn->flags |= CO_FL_OPT_TOS;
}
- srv_conn->hash_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);
}
DECLARE_TYPED_POOL(pool_head_connection, "connection", struct connection, 0, 64);
-DECLARE_TYPED_POOL(pool_head_conn_hash_node, "conn_hash_node", struct conn_hash_node);
DECLARE_TYPED_POOL(pool_head_sockaddr, "sockaddr", struct sockaddr_storage);
DECLARE_TYPED_POOL(pool_head_pp_tlv_128, "pp_tlv_128", struct conn_tlv_list, HA_PP2_TLV_VALUE_128);
DECLARE_TYPED_POOL(pool_head_pp_tlv_256, "pp_tlv_256", struct conn_tlv_list, HA_PP2_TLV_VALUE_256);
conn_tree = &srv->per_thr[thr].avail_conns;
}
- ceb64_item_delete(conn_tree, node, key, conn->hash_node);
+ ceb64_item_delete(conn_tree, hash_node.node, hash_node.key, conn);
}
int conn_create_mux(struct connection *conn, int *closed_connection)
conn->subs = NULL;
conn->src = NULL;
conn->dst = NULL;
- conn->hash_node = NULL;
+ conn->hash_node.key = 0;
+ ceb_init_node(&conn->hash_node.node);
conn->xprt = NULL;
conn->reverse.target = NULL;
conn->reverse.name = BUF_NULL;
if (!sockaddr_alloc(&conn->dst, 0, 0))
return 1;
- conn->hash_node = conn_alloc_hash_node(conn);
- if (unlikely(!conn->hash_node))
- return 1;
-
return 0;
}
}
/* Make sure the connection is not left in the idle connection tree */
- if (conn->hash_node != NULL)
- BUG_ON(ceb_intree(&conn->hash_node->node));
-
- pool_free(pool_head_conn_hash_node, conn->hash_node);
- conn->hash_node = NULL;
+ BUG_ON(ceb_intree(&conn->hash_node.node));
/* Remove from BE purge list. Necessary if conn already scheduled for
* purge but finally freed before by another code path.
}
}
-struct conn_hash_node *conn_alloc_hash_node(struct connection *conn)
-{
- struct conn_hash_node *hash_node = NULL;
-
- hash_node = pool_zalloc(pool_head_conn_hash_node);
- if (unlikely(!hash_node))
- return NULL;
-
- hash_node->conn = conn;
-
- return hash_node;
-}
-
/* Allocates a struct sockaddr from the pool if needed, assigns it to *sap and
* returns it. If <sap> is NULL, the address is always allocated and returned.
* if <sap> is non-null, an address will only be allocated if it points to a
}
hash = conn_calculate_hash(&hash_params);
- conn->hash_node->key = hash;
+ conn->hash_node.key = hash;
conn->target = &srv->obj_type;
srv_use_conn(srv, conn);
TRACE_DEVEL("reusable idle connection", FCGI_EV_STRM_END, fconn->conn);
return;
}
- else if (!ceb_intree(&fconn->conn->hash_node->node) &&
+ 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);
return;
}
- else if (!ceb_intree(&h2c->conn->hash_node->node) &&
+ 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);
conn = NULL;
goto end;
}
- else if (!ceb_intree(&conn->hash_node->node) &&
+ 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);
TRACE_DEVEL("reusable idle connection", SPOP_EV_STRM_END);
return;
}
- else if (!ceb_intree(&spop_conn->conn->hash_node->node) &&
+ 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);
}
/* Remove the connection from any tree (safe, idle or available) */
- if (conn->hash_node) {
+ if (ceb_intree(&conn->hash_node.node)) {
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
conn_delete_from_tree(conn, tid);
conn->flags &= ~CO_FL_LIST_MASK;
*/
struct connection *srv_lookup_conn(struct ceb_root **tree, uint64_t hash)
{
- struct conn_hash_node *hash_node;
- struct connection *conn = NULL;
-
- hash_node = ceb64_item_lookup(tree, node, key, hash, struct conn_hash_node);
- if (hash_node)
- conn = hash_node->conn;
-
- return conn;
+ return ceb64_item_lookup(tree, hash_node.node, hash_node.key, hash, struct connection);
}
/* retrieve the next connection sharing the same hash as <conn>
*/
struct connection *srv_lookup_conn_next(struct ceb_root **tree, struct connection *conn)
{
- struct conn_hash_node *hash_node;
-
- hash_node = ceb64_item_next_dup(tree, node, key, conn->hash_node);
- if (hash_node)
- conn = hash_node->conn;
-
- return conn;
+ return ceb64_item_next_dup(tree, hash_node.node, hash_node.key, conn);
}
/* Add <conn> in <srv> idle trees. Set <is_safe> if connection is deemed safe
&srv->per_thr[tid].idle_conns;
/* first insert in idle or safe tree. */
- ceb64_item_insert(tree, node, key, conn->hash_node);
+ ceb64_item_insert(tree, hash_node.node, hash_node.key, conn);
/* insert in list sorted by connection usage. */
LIST_APPEND(&srv->per_thr[tid].idle_conn_list, &conn->idle_list);
{
/* connection cannot be in idle list if used as an avail idle conn. */
BUG_ON(LIST_INLIST(&conn->idle_list));
- ceb64_item_insert(&srv->per_thr[tid].avail_conns, node, key, conn->hash_node);
+ ceb64_item_insert(&srv->per_thr[tid].avail_conns, hash_node.node, hash_node.key, conn);
}
struct task *srv_cleanup_idle_conns(struct task *task, void *context, unsigned int state)
static void srv_close_idle_conns(struct server *srv)
{
struct ceb_root ***cleaned_tree;
+ struct connection *conn;
int i;
for (i = 0; i < global.nbthread; ++i) {
};
for (cleaned_tree = conn_trees; *cleaned_tree; ++cleaned_tree) {
- while (!ceb_isempty(*cleaned_tree)) {
- struct connection *conn;
-
- conn = ceb64_item_first(*cleaned_tree, node, key, struct conn_hash_node)->conn;
+ while ((conn = ceb64_item_first(*cleaned_tree, hash_node.node,
+ hash_node.key, struct connection))) {
if (conn->ctrl->ctrl_close)
conn->ctrl->ctrl_close(conn);
conn_delete_from_tree(conn, i);
/* 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->key == hash) &&
+ if (srv_conn->hash_node.key == hash &&
srv_conn->mux &&
(srv_conn->mux->avail_streams(srv_conn) > 0) &&
!(srv_conn->flags & CO_FL_WAIT_XPRT)) {