Commit f1169ab5 authored by Andrew Dunstan's avatar Andrew Dunstan

Don't count background workers against a user's connection limit.

Doing so doesn't seem to be within the purpose of the per user
connection limits, and has particularly unfortunate effects in
conjunction with parallel queries.

Backpatch to 9.6 where parallel queries were introduced.

David Rowley, reviewed by Robert Haas and Albe Laurenz.
parent aedd554f
...@@ -258,7 +258,8 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> ...@@ -258,7 +258,8 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
The <literal>CONNECTION LIMIT</> option is only enforced approximately; The <literal>CONNECTION LIMIT</> option is only enforced approximately;
if two new sessions start at about the same time when just one if two new sessions start at about the same time when just one
connection <quote>slot</> remains for the database, it is possible that connection <quote>slot</> remains for the database, it is possible that
both will fail. Also, the limit is not enforced against superusers. both will fail. Also, the limit is not enforced against superusers or
background worker processes.
</para> </para>
</refsect1> </refsect1>
......
...@@ -198,7 +198,10 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac ...@@ -198,7 +198,10 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
<listitem> <listitem>
<para> <para>
If role can log in, this specifies how many concurrent connections If role can log in, this specifies how many concurrent connections
the role can make. -1 (the default) means no limit. the role can make. -1 (the default) means no limit. Note that only
normal connections are counted towards this limit. Neither prepared
transactions nor background worker connections are counted towards
this limit.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -420,6 +420,7 @@ MarkAsPreparing(TransactionId xid, const char *gid, ...@@ -420,6 +420,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
proc->backendId = InvalidBackendId; proc->backendId = InvalidBackendId;
proc->databaseId = databaseid; proc->databaseId = databaseid;
proc->roleId = owner; proc->roleId = owner;
proc->isBackgroundWorker = false;
proc->lwWaiting = false; proc->lwWaiting = false;
proc->lwWaitMode = 0; proc->lwWaitMode = 0;
proc->waitLock = NULL; proc->waitLock = NULL;
......
...@@ -2744,6 +2744,38 @@ CountDBBackends(Oid databaseid) ...@@ -2744,6 +2744,38 @@ CountDBBackends(Oid databaseid)
return count; return count;
} }
/*
* CountDBConnections --- counts database backends ignoring any background
* worker processes
*/
int
CountDBConnections(Oid databaseid)
{
ProcArrayStruct *arrayP = procArray;
int count = 0;
int index;
LWLockAcquire(ProcArrayLock, LW_SHARED);
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
if (proc->pid == 0)
continue; /* do not count prepared xacts */
if (proc->isBackgroundWorker)
continue; /* do not count background workers */
if (!OidIsValid(databaseid) ||
proc->databaseId == databaseid)
count++;
}
LWLockRelease(ProcArrayLock);
return count;
}
/* /*
* CancelDBBackends --- cancel backends that are using specified database * CancelDBBackends --- cancel backends that are using specified database
*/ */
...@@ -2803,6 +2835,8 @@ CountUserBackends(Oid roleid) ...@@ -2803,6 +2835,8 @@ CountUserBackends(Oid roleid)
if (proc->pid == 0) if (proc->pid == 0)
continue; /* do not count prepared xacts */ continue; /* do not count prepared xacts */
if (proc->isBackgroundWorker)
continue; /* do not count background workers */
if (proc->roleId == roleid) if (proc->roleId == roleid)
count++; count++;
} }
......
...@@ -370,6 +370,7 @@ InitProcess(void) ...@@ -370,6 +370,7 @@ InitProcess(void)
MyProc->backendId = InvalidBackendId; MyProc->backendId = InvalidBackendId;
MyProc->databaseId = InvalidOid; MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid; MyProc->roleId = InvalidOid;
MyProc->isBackgroundWorker = IsBackgroundWorker;
MyPgXact->delayChkpt = false; MyPgXact->delayChkpt = false;
MyPgXact->vacuumFlags = 0; MyPgXact->vacuumFlags = 0;
/* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */ /* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */
...@@ -542,6 +543,7 @@ InitAuxiliaryProcess(void) ...@@ -542,6 +543,7 @@ InitAuxiliaryProcess(void)
MyProc->backendId = InvalidBackendId; MyProc->backendId = InvalidBackendId;
MyProc->databaseId = InvalidOid; MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid; MyProc->roleId = InvalidOid;
MyProc->isBackgroundWorker = IsBackgroundWorker;
MyPgXact->delayChkpt = false; MyPgXact->delayChkpt = false;
MyPgXact->vacuumFlags = 0; MyPgXact->vacuumFlags = 0;
MyProc->lwWaiting = false; MyProc->lwWaiting = false;
......
...@@ -350,7 +350,7 @@ CheckMyDatabase(const char *name, bool am_superuser) ...@@ -350,7 +350,7 @@ CheckMyDatabase(const char *name, bool am_superuser)
*/ */
if (dbform->datconnlimit >= 0 && if (dbform->datconnlimit >= 0 &&
!am_superuser && !am_superuser &&
CountDBBackends(MyDatabaseId) > dbform->datconnlimit) CountDBConnections(MyDatabaseId) > dbform->datconnlimit)
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_TOO_MANY_CONNECTIONS), (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("too many connections for database \"%s\"", errmsg("too many connections for database \"%s\"",
......
...@@ -103,6 +103,8 @@ struct PGPROC ...@@ -103,6 +103,8 @@ struct PGPROC
Oid databaseId; /* OID of database this backend is using */ Oid databaseId; /* OID of database this backend is using */
Oid roleId; /* OID of role using this backend */ Oid roleId; /* OID of role using this backend */
bool isBackgroundWorker; /* true if background worker. */
/* /*
* While in hot standby mode, shows that a conflict signal has been sent * While in hot standby mode, shows that a conflict signal has been sent
* for the current transaction. Set/cleared while holding ProcArrayLock, * for the current transaction. Set/cleared while holding ProcArrayLock,
......
...@@ -73,6 +73,7 @@ extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReaso ...@@ -73,6 +73,7 @@ extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReaso
extern bool MinimumActiveBackends(int min); extern bool MinimumActiveBackends(int min);
extern int CountDBBackends(Oid databaseid); extern int CountDBBackends(Oid databaseid);
extern int CountDBConnections(Oid databaseid);
extern void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending); extern void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending);
extern int CountUserBackends(Oid roleid); extern int CountUserBackends(Oid roleid);
extern bool CountOtherDBBackends(Oid databaseId, extern bool CountOtherDBBackends(Oid databaseId,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment