I recently started getting the "sorry, too many clients already" error.
There are currently four places that can generate it, but fortunately
log_error_verbosity was set to verbose so I was able to see that in this
case the warning was generated by proc.c:InitProcess().
But it's still not much, because there are three different lists you can
run out of and get the same error message from InitProcess(). I was
lucky to be able to rule out two of them. max_connections is set to much
more than the sum of possible connections from all relevant pgBouncer
instances we have, so it's not hitting max_connections. Also, this is on
9.4 and we don't use any funny extensions, so it's probably not running
out of bgworkerFreeProcs either. autovacFreeProcs is what's left but
this is still just a guess and I'd prefer to actually know.
I've made a hack for myself (attached diff against 9.4) which adds a
DETAIL-level message telling me which proc list was saturated. It's not
committable in its current form because of a C99 feature and perhaps for
other reasons.
By the way, I've also noticed that the InitProcess() can segfault upon
hitting set_spins_per_delay(procglobal->spins_per_delay). This only
happens when I run REL9_4_STABLE under gdb, set a breakpoint on
InitProcess, see an autovacuum launcher hit the breakpoint and tell gdb
to continue. "p procglobal->spins_per_delay" says "Cannot access memory
at address 0xf01b2f90". Maybe this means nothing.
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e608198..613b36a 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -279,6 +279,14 @@ InitProcess(void)
{
/* use volatile pointer to prevent code rearrangement */
volatile PROC_HDR *procglobal = ProcGlobal;
+#define LIST_TYPE_ENTRY(e) [(e)] = (#e)
+ enum listType { autovac, bgworker, backend } which;
+ char const * const listTypeNames[] = {
+ LIST_TYPE_ENTRY(autovac),
+ LIST_TYPE_ENTRY(bgworker),
+ LIST_TYPE_ENTRY(backend)
+ };
+#undef LIST_TYPE_ENTRY
/*
* ProcGlobal should be set up already (if we are a backend, we inherit
@@ -309,11 +317,11 @@ InitProcess(void)
set_spins_per_delay(procglobal->spins_per_delay);
if (IsAnyAutoVacuumProcess())
- MyProc = procglobal->autovacFreeProcs;
+ which = autovac, MyProc = procglobal->autovacFreeProcs;
else if (IsBackgroundWorker)
- MyProc = procglobal->bgworkerFreeProcs;
+ which = bgworker, MyProc = procglobal->bgworkerFreeProcs;
else
- MyProc = procglobal->freeProcs;
+ which = backend, MyProc = procglobal->freeProcs;
if (MyProc != NULL)
{
@@ -330,13 +338,13 @@ InitProcess(void)
/*
* If we reach here, all the PGPROCs are in use. This is one of the
* possible places to detect "too many backends", so give the standard
- * error message. XXX do we need to give a different failure message
- * in the autovacuum case?
+ * error message.
*/
SpinLockRelease(ProcStructLock);
ereport(FATAL,
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
- errmsg("sorry, too many clients already")));
+ errmsg("sorry, too many clients already"),
+ errdetail("%s proc list saturated", listTypeNames[which])));
}
MyPgXact = &ProcGlobal->allPgXact[MyProc->pgprocno];
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers