/* flags for appctx->state */
/* Room for per-command context (mostly CLI commands but not only) */
-#define APPLET_MAX_SVCCTX 128
+#define APPLET_MAX_SVCCTX 256
/* Appctx Flags */
#define APPCTX_FL_INBLK_ALLOC 0x00000001
enum srv_ws_mode ws; /* configure the protocol selection for websocket */
/* 3 bytes hole here */
+ struct mt_list watcher_list; /* list of elems which currently references this server instance */
uint refcount; /* refcount used to remove a server at runtime */
/* The elements below may be changed on every single request by any
int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */
int st_code; /* the status code returned by an action */
struct buffer chunk; /* temporary buffer which holds a single-line output */
+ struct watcher srv_watch; /* watcher to automatically update obj2 on server deletion */
enum stat_state state; /* phase of output production */
};
ctx->flags |= STAT_F_FMT_HTML; /* assume HTML mode by default */
if ((msg->flags & HTTP_MSGF_VER_11) && (txn->meth != HTTP_METH_HEAD))
ctx->flags |= STAT_F_CHUNKED;
+ watcher_init(&ctx->srv_watch, &ctx->obj2, offsetof(struct server, watcher_list));
htx = htxbuf(&req->buf);
sl = http_get_stline(htx);
MT_LIST_INIT(&srv->sess_conns);
guid_init(&srv->guid);
+ MT_LIST_INIT(&srv->watcher_list);
srv->extra_counters = NULL;
#ifdef USE_OPENSSL
struct ist be_name, sv_name;
struct mt_list back;
struct sess_priv_conns *sess_conns = NULL;
+ struct watcher *srv_watch;
const char *msg;
int ret, i;
if (srv->agent.state & CHK_ST_CONFIGURED)
check_purge(&srv->agent);
+ while (!MT_LIST_ISEMPTY(&srv->watcher_list)) {
+ srv_watch = MT_LIST_NEXT(&srv->watcher_list, struct watcher *, el);
+ BUG_ON(srv->next && srv->next->flags & SRV_F_DELETED);
+ watcher_next(srv_watch, srv->next);
+ }
+
/* detach the server from the proxy linked list
* The proxy servers list is currently not protected by a lock, so this
* requires thread_isolate/release.
static void http_stats_release(struct appctx *appctx)
{
struct show_stat_ctx *ctx = appctx->svcctx;
-
- if (ctx->px_st == STAT_PX_ST_SV)
- srv_drop(ctx->obj2);
+ if (ctx->px_st == STAT_PX_ST_SV && ctx->obj2)
+ watcher_detach(&ctx->srv_watch);
}
struct applet http_stats_applet = {
struct listener *l;
struct uri_auth *uri = NULL;
int current_field;
- int px_st = ctx->px_st;
if (ctx->http_px)
uri = ctx->http_px->uri_auth;
current_field = 0;
}
- ctx->obj2 = px->srv; /* may be NULL */
+ /* for servers ctx.obj2 is set via watcher_attach() */
+ watcher_attach(&ctx->srv_watch, px->srv);
ctx->px_st = STAT_PX_ST_SV;
+
__fallthrough;
case STAT_PX_ST_SV:
- /* check for dump resumption */
- if (px_st == STAT_PX_ST_SV) {
- struct server *cur = ctx->obj2;
-
- /* re-entrant dump */
- BUG_ON(!cur);
- if (cur->flags & SRV_F_DELETED) {
- /* the server could have been marked as deleted
- * between two dumping attempts, skip it.
- */
- cur = cur->next;
- }
- srv_drop(ctx->obj2); /* drop old srv taken on last dumping attempt */
- ctx->obj2 = cur; /* could be NULL */
- /* back to normal */
- }
-
- /* obj2 points to servers list as initialized above.
- *
- * A server may be removed during the stats dumping.
- * Temporarily increment its refcount to prevent its
- * anticipated cleaning. Call srv_drop() to release it.
- */
- for (; ctx->obj2 != NULL;
- ctx->obj2 = srv_drop(sv)) {
-
- sv = ctx->obj2;
- srv_take(sv);
+ /* obj2 is updated and returned through watcher_next() */
+ for (sv = ctx->obj2; sv;
+ sv = watcher_next(&ctx->srv_watch, sv->next)) {
if (stats_is_full(appctx, buf, htx))
goto full;
if (ctx->flags & STAT_F_BOUND) {
if (!(ctx->type & (1 << STATS_TYPE_SV))) {
- srv_drop(sv);
+ watcher_detach(&ctx->srv_watch);
break;
}
ctx->scope_len = 0;
ctx->http_px = NULL; // not under http context
ctx->flags = STAT_F_SHNODE | STAT_F_SHDESC;
+ watcher_init(&ctx->srv_watch, &ctx->obj2, offsetof(struct server, watcher_list));
if ((strm_li(appctx_strm(appctx))->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER)
ctx->flags |= STAT_F_SHLGNDS;
static void cli_io_handler_release_stat(struct appctx *appctx)
{
struct show_stat_ctx *ctx = appctx->svcctx;
-
- if (ctx->px_st == STAT_PX_ST_SV)
- srv_drop(ctx->obj2);
+ if (ctx->px_st == STAT_PX_ST_SV && ctx->obj2)
+ watcher_detach(&ctx->srv_watch);
}
static int cli_io_handler_dump_json_schema(struct appctx *appctx)
ctx->chunk = b_make(trash.area, trash.size, 0, 0);
ctx->domain = STATS_DOMAIN_PROXY;
ctx->flags |= STAT_F_FMT_FILE;
+ watcher_init(&ctx->srv_watch, &ctx->obj2, offsetof(struct server, watcher_list));
return 0;
}
static void cli_io_handler_release_dump_stat_file(struct appctx *appctx)
{
struct show_stat_ctx *ctx = appctx->svcctx;
-
- if (ctx->px_st == STAT_PX_ST_SV)
- srv_drop(ctx->obj2);
+ if (ctx->px_st == STAT_PX_ST_SV && ctx->obj2)
+ watcher_detach(&ctx->srv_watch);
}
int stats_allocate_proxy_counters_internal(struct extra_counters **counters,