struct server *next_full; /* next server in the temporary full list */
unsigned int last_other_tgrp_served; /* Last other tgrp we dequeued from */
unsigned int self_served; /* Number of connection we dequeued from our own queue */
+ unsigned int nb_strm; /* nb streams in this tgroup referencing this server */
unsigned int dequeuing; /* non-zero = dequeuing in progress (atomic) */
unsigned int next_takeover; /* thread ID to try to steal connections from next time */
struct eb_root *lb_tree; /* For LB algos with split between thread groups, the tree to be used, for each group */
#include <haproxy/obj_type.h>
#include <haproxy/pool-t.h>
#include <haproxy/queue.h>
+#include <haproxy/server.h>
#include <haproxy/session.h>
#include <haproxy/stconn.h>
#include <haproxy/stick_table.h>
sc->term_evts_log = tevt_report_event(sc->term_evts_log, loc, type);
}
+/*
+ * Sets the stream's target, and take care of nb_strm and sv_tgcounters if
+ * the target is a server.
+ */
+static inline void stream_set_target(struct stream *s, enum obj_type *target)
+{
+ struct server *o = objt_server(s->target);
+ struct server *n = objt_server(target);
+
+ if (o != n) {
+ if (n) {
+ _HA_ATOMIC_INC(&n->per_tgrp[tgid - 1].nb_strm);
+ s->sv_tgcounters = n->counters.shared.tg ? n->counters.shared.tg[tgid - 1] : NULL;
+ }
+ else
+ s->sv_tgcounters = NULL;
+ if (o)
+ _HA_ATOMIC_DEC(&o->per_tgrp[tgid - 1].nb_strm);
+ }
+ s->target = target;
+}
+
+/* Convenience wrapper of stream_set_target() for callers that already hold a
+ * struct server, so they can pass it directly.
+ */
static inline void stream_set_srv_target(struct stream *s, struct server *srv)
{
- s->target = &srv->obj_type;
- s->sv_tgcounters = srv->counters.shared.tg[tgid - 1];
+ stream_set_target(s, &srv->obj_type);
}
int stream_set_timeout(struct stream *s, enum act_timeout_name name, int timeout);
*/
srv = NULL;
- s->target = NULL;
+ stream_set_target(s, NULL);
if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI &&
((s->sess->flags & SESS_FL_PREFER_LAST) ||
if (*p != '.')
goto no_cookie;
- s->target = NULL;
+ stream_set_target(s, NULL);
while (srv) {
if (srv->addr.ss_family == AF_INET &&
port == srv->svc_port &&
return ACT_RET_CONT;
}
+ /* This runs before any server assignment, so s->target holds no
+ * server here and there is no nb_strm reference to drop.
+ */
s->target = &http_cache_applet.obj_type;
if ((appctx = sc_applet_create(s->scb, objt_applet(s->target)))) {
struct cache_appctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
else
target_pid = pcli->next_pid;
/* we can connect now */
- s->target = pcli_pid_to_server(target_pid);
- if (objt_server(s->target)) {
- struct server *srv = __objt_server(s->target);
-
- if (srv->counters.shared.tg)
- s->sv_tgcounters = srv->counters.shared.tg[tgid - 1];
- else
- s->sv_tgcounters = NULL;
- }
+ stream_set_target(s, pcli_pid_to_server(target_pid));
if (!s->target)
goto server_disconnect;
process_srv_queue(__objt_server(s->target));
}
- s->target = NULL;
+ stream_set_target(s, NULL);
/* Always release our endpoint */
s->srv_conn = NULL;
s->logs.logwait = strm_fe(s)->to_log;
s->logs.level = 0;
stream_del_srv_conn(s);
- s->target = NULL;
+ stream_set_target(s, NULL);
/* re-init store persistence */
s->store_count = 0;
s->uniq_id = _HA_ATOMIC_FETCH_ADD(&global.req_count, 1);
* reqdeny can still block them. This clearly needs to change in 1.6!
*/
if (!s->target && http_stats_check_uri(s, txn, px)) {
+ /* s->target was NULL (checked above), no nb_strm reference to drop */
s->target = &http_stats_applet.obj_type;
if (unlikely(!sc_applet_create(s->scb, objt_applet(s->target)))) {
s->logs.request_ts = now_ns;
}
s = appctx_strm(appctx);
- s->target = target;
- if (objt_server(s->target)) {
- struct server *srv = __objt_server(s->target);
-
- if (srv->counters.shared.tg)
- s->sv_tgcounters = __objt_server(s->target)->counters.shared.tg[tgid - 1];
- else
- s->sv_tgcounters = NULL;
- }
+ stream_set_target(s, target);
/* set the "timeout server" */
s->scb->ioto = hc->timeout_server;
/* Returns 1 if the server has streams pointing to it, and 0 otherwise. */
static int srv_has_streams(struct server *srv)
{
- return !!_HA_ATOMIC_LOAD(&srv->served);
+ int i;
+
+ for (i = 0; i < global.nbtgroups; i++) {
+ if (_HA_ATOMIC_LOAD(&srv->per_tgrp[i].nb_strm))
+ return 1;
+ }
+ return 0;
}
/* Shutdown all connections of a server. The caller must pass a termination
}
}
+ stream_set_target(s, NULL);
+
pool_free(pool_head_stream, s);
/* We may want to free the maximum amount of pools if the proxy is stopping */
/* Initialises the applet if it is required. */
if (flags & ACT_OPT_FIRST) {
/* Register applet. this function schedules the applet. */
- s->target = &rule->applet.obj_type;
+ stream_set_target(s, &rule->applet.obj_type);
appctx = sc_applet_create(s->scb, objt_applet(s->target));
if (unlikely(!appctx))
return ACT_RET_ERR;