]> granicus.if.org Git - postgresql/commitdiff
Don't count background workers against a user's connection limit.
authorAndrew Dunstan <andrew@dunslane.net>
Wed, 1 Feb 2017 22:52:35 +0000 (17:52 -0500)
committerAndrew Dunstan <andrew@dunslane.net>
Wed, 1 Feb 2017 22:59:53 +0000 (17:59 -0500)
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.

doc/src/sgml/ref/create_database.sgml
doc/src/sgml/ref/create_role.sgml
src/backend/access/transam/twophase.c
src/backend/storage/ipc/procarray.c
src/backend/storage/lmgr/proc.c
src/backend/utils/init/postinit.c
src/include/storage/proc.h
src/include/storage/procarray.h

index cf33746c1e23c96f0b6e875400927c93a96ba03d..cf0d53b3014bda73cd561c88c9b747fb7aa772af 100644 (file)
@@ -258,7 +258,8 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
    The <literal>CONNECTION LIMIT</> option is only enforced approximately;
    if two new sessions start at about the same time when just one
    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>
  </refsect1>
 
index a3b8ed9ab4c8e62bb6f963cbf1129a849d18e51c..2ae576ede696c16a1b7e9d52736d422b63b60fa7 100644 (file)
@@ -198,7 +198,10 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
       <listitem>
        <para>
         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>
       </listitem>
      </varlistentry>
index 5415604993a75170444bdf0a4e931e8c1edffb49..ea7bfa0578be785d1f86658808fe8e5106646936 100644 (file)
@@ -420,6 +420,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
        proc->backendId = InvalidBackendId;
        proc->databaseId = databaseid;
        proc->roleId = owner;
+       proc->isBackgroundWorker = false;
        proc->lwWaiting = false;
        proc->lwWaitMode = 0;
        proc->waitLock = NULL;
index 4adb286d5b5278308e5a4b48ca3f2ef66f339552..651c561dfd50bba325cb593e0d41b29d47c876d0 100644 (file)
@@ -2751,6 +2751,38 @@ CountDBBackends(Oid databaseid)
        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
  */
@@ -2810,6 +2842,8 @@ CountUserBackends(Oid roleid)
 
                if (proc->pid == 0)
                        continue;                       /* do not count prepared xacts */
+               if (proc->isBackgroundWorker)
+                       continue;                       /* do not count background workers */
                if (proc->roleId == roleid)
                        count++;
        }
index 9a758bd91600b0839afadf3e3907e06a0902f8d5..cb6e1e3e5bc68fb4d4e7d9608decbad4268fed9f 100644 (file)
@@ -372,6 +372,7 @@ InitProcess(void)
        MyProc->backendId = InvalidBackendId;
        MyProc->databaseId = InvalidOid;
        MyProc->roleId = InvalidOid;
+       MyProc->isBackgroundWorker = IsBackgroundWorker;
        MyPgXact->delayChkpt = false;
        MyPgXact->vacuumFlags = 0;
        /* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */
@@ -544,6 +545,7 @@ InitAuxiliaryProcess(void)
        MyProc->backendId = InvalidBackendId;
        MyProc->databaseId = InvalidOid;
        MyProc->roleId = InvalidOid;
+       MyProc->isBackgroundWorker = IsBackgroundWorker;
        MyPgXact->delayChkpt = false;
        MyPgXact->vacuumFlags = 0;
        MyProc->lwWaiting = false;
index 824d5abf11fefb0f51a49423fbcbc3ad5893cfcc..cde4a798b620e2542a13bc5a38f637e77e0fb7a5 100644 (file)
@@ -350,7 +350,7 @@ CheckMyDatabase(const char *name, bool am_superuser)
                 */
                if (dbform->datconnlimit >= 0 &&
                        !am_superuser &&
-                       CountDBBackends(MyDatabaseId) > dbform->datconnlimit)
+                       CountDBConnections(MyDatabaseId) > dbform->datconnlimit)
                        ereport(FATAL,
                                        (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
                                         errmsg("too many connections for database \"%s\"",
index 775c66a197136640512ef22be42b2025811cdf14..c44d82b90c0b0ef9b9c25dc86786dca9b8922866 100644 (file)
@@ -102,6 +102,8 @@ struct PGPROC
        Oid                     databaseId;             /* OID of database this backend is using */
        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
         * for the current transaction. Set/cleared while holding ProcArrayLock,
index dd37c0cb07086fc916fb731ca6ecc150b7d290de..ecc3c4a4f63bac5361d1df066b2183c48244e334 100644 (file)
@@ -73,6 +73,7 @@ extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReaso
 
 extern bool MinimumActiveBackends(int min);
 extern int     CountDBBackends(Oid databaseid);
+extern int     CountDBConnections(Oid databaseid);
 extern void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending);
 extern int     CountUserBackends(Oid roleid);
 extern bool CountOtherDBBackends(Oid databaseId,