extern const char* li_status_st[LI_STATE_COUNT];
enum li_status get_li_status(struct listener *l);
+/* number of times an accepted connection resulted in maxconn being reached */
+extern ullong maxconn_reached;
+
static inline uint accept_queue_ring_len(const struct accept_queue_ring *ring)
{
uint idx, head, tail, len;
/* list of the temporarily limited listeners because of lack of resource */
static struct mt_list global_listener_queue = MT_LIST_HEAD_INIT(global_listener_queue);
static struct task *global_listener_queue_task;
+/* number of times an accepted connection resulted in maxconn being reached */
+ullong maxconn_reached = 0;
__decl_thread(static HA_RWLOCK_T global_listener_rwlock);
/* listener status for stats */
_HA_ATOMIC_INC(&activity[tid].accepted);
+ /* count the number of times an accepted connection resulted in
+ * maxconn being reached.
+ */
+ if (unlikely(_HA_ATOMIC_LOAD(&actconn) + 1 >= global.maxconn))
+ _HA_ATOMIC_INC(&maxconn_reached);
+
/* past this point, l->bind_conf->accept() will automatically decrement
* l->nbconn, feconn and actconn once done. Setting next_*conn=0
* allows the error path not to rollback on nbconn. It's more
[INF_BUILD_INFO] = { .name = "Build info", .desc = "Build info" },
[INF_TAINTED] = { .name = "Tainted", .desc = "Experimental features used" },
[INF_WARNINGS] = { .name = "TotalWarnings", .desc = "Total warnings issued" },
+ [INF_MAXCONN_REACHED] = { .name = "MaxconnReached", .desc = "Number of times an accepted connection resulted in Maxconn being reached" },
};
const struct name_desc stat_fields[ST_F_TOTAL_FIELDS] = {
"<p><b>pid = </b> %d (process #%d, nbproc = %d, nbthread = %d)<br>\n"
"<b>uptime = </b> %dd %dh%02dm%02ds; warnings = %u<br>\n"
"<b>system limits:</b> memmax = %s%s; ulimit-n = %d<br>\n"
- "<b>maxsock = </b> %d; <b>maxconn = </b> %d; <b>maxpipes = </b> %d<br>\n"
+ "<b>maxsock = </b> %d; <b>maxconn = </b> %d; <b>reached = </b> %llu; <b>maxpipes = </b> %d<br>\n"
"current conns = %d; current pipes = %d/%d; conn rate = %d/sec; bit rate = %.3f %cbps<br>\n"
"Running tasks: %d/%d; idle = %d %%<br>\n"
"</td><td align=\"center\" nowrap>\n"
global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
global.rlimit_memmax ? " MB" : "",
global.rlimit_nofile,
- global.maxsock, global.maxconn, global.maxpipes,
+ global.maxsock, global.maxconn, HA_ATOMIC_LOAD(&maxconn_reached), global.maxpipes,
actconn, pipes_used, pipes_used+pipes_free, read_freq_ctr(&global.conn_per_sec),
bps >= 1000000000UL ? (bps / 1000000000.0) : bps >= 1000000UL ? (bps / 1000000.0) : (bps / 1000.0),
bps >= 1000000000UL ? 'G' : bps >= 1000000UL ? 'M' : 'k',
info[INF_TAINTED] = mkf_str(FO_STATUS, chunk_newstr(out));
info[INF_WARNINGS] = mkf_u32(FN_COUNTER, HA_ATOMIC_LOAD(&tot_warnings));
+ info[INF_MAXCONN_REACHED] = mkf_u32(FN_COUNTER, HA_ATOMIC_LOAD(&maxconn_reached));
chunk_appendf(out, "%#x", get_tainted());
return 1;