mirror of
https://github.com/postgres/postgres.git
synced 2025-07-23 03:21:12 +03:00
Add new GUC reserved_connections.
This provides a way to reserve connection slots for non-superusers. The slots reserved via the new GUC are available only to users who have the new predefined role pg_use_reserved_connections. superuser_reserved_connections remains as a final reserve in case reserved_connections has been exhausted. Patch by Nathan Bossart. Reviewed by Tushar Ahuja and by me. Discussion: http://postgr.es/m/20230119194601.GA4105788@nathanxps13
This commit is contained in:
@ -708,6 +708,37 @@ include_dir 'conf.d'
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="guc-reserved-connections" xreflabel="reserved_connections">
|
||||||
|
<term><varname>reserved_connections</varname> (<type>integer</type>)
|
||||||
|
<indexterm>
|
||||||
|
<primary><varname>reserved_connections</varname> configuration parameter</primary>
|
||||||
|
</indexterm>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Determines the number of connection <quote>slots</quote> that are
|
||||||
|
reserved for connections by roles with privileges of the
|
||||||
|
<link linkend="predefined-roles-table"><literal>pg_used_reserved_connections</literal></link>
|
||||||
|
role. Whenever the number of free connection slots is greater than
|
||||||
|
<xref linkend="guc-superuser-reserved-connections"/> but less than or
|
||||||
|
equal to the sum of <varname>superuser_reserved_connections</varname>
|
||||||
|
and <varname>reserved_connections</varname>, new connections will be
|
||||||
|
accepted only for superusers and roles with privileges of
|
||||||
|
<literal>pg_use_reserved_connections</literal>. If
|
||||||
|
<varname>superuser_reserved_connections</varname> or fewer connection
|
||||||
|
slots are available, new connections will be accepted only for
|
||||||
|
superusers.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The default value is zero connections. The value must be less than
|
||||||
|
<varname>max_connections</varname> minus
|
||||||
|
<varname>superuser_reserved_connections</varname>. This parameter can
|
||||||
|
only be set at server start.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="guc-superuser-reserved-connections"
|
<varlistentry id="guc-superuser-reserved-connections"
|
||||||
xreflabel="superuser_reserved_connections">
|
xreflabel="superuser_reserved_connections">
|
||||||
<term><varname>superuser_reserved_connections</varname>
|
<term><varname>superuser_reserved_connections</varname>
|
||||||
@ -725,12 +756,16 @@ include_dir 'conf.d'
|
|||||||
number of active concurrent connections is at least
|
number of active concurrent connections is at least
|
||||||
<varname>max_connections</varname> minus
|
<varname>max_connections</varname> minus
|
||||||
<varname>superuser_reserved_connections</varname>, new
|
<varname>superuser_reserved_connections</varname>, new
|
||||||
connections will be accepted only for superusers.
|
connections will be accepted only for superusers. The connection slots
|
||||||
|
reserved by this parameter are intended as final reserve for emergency
|
||||||
|
use after the slots reserved by
|
||||||
|
<xref linkend="guc-reserved-connections"/> have been exhausted.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The default value is three connections. The value must be less
|
The default value is three connections. The value must be less
|
||||||
than <varname>max_connections</varname>.
|
than <varname>max_connections</varname> minus
|
||||||
|
<varname>reserved_connections</varname>.
|
||||||
This parameter can only be set at server start.
|
This parameter can only be set at server start.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
@ -689,6 +689,11 @@ DROP ROLE doomed_role;
|
|||||||
and <link linkend="sql-lock"><command>LOCK TABLE</command></link> on all
|
and <link linkend="sql-lock"><command>LOCK TABLE</command></link> on all
|
||||||
relations.</entry>
|
relations.</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>pg_use_reserved_connections</entry>
|
||||||
|
<entry>Allow use of connection slots reserved via
|
||||||
|
<xref linkend="guc-reserved-connections"/>.</entry>
|
||||||
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
@ -205,14 +205,24 @@ char *ListenAddresses;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* SuperuserReservedConnections is the number of backends reserved for
|
* SuperuserReservedConnections is the number of backends reserved for
|
||||||
* superuser use. This number is taken out of the pool size given by
|
* superuser use, and ReservedConnections is the number of backends reserved
|
||||||
* MaxConnections so number of backend slots available to non-superusers is
|
* for use by roles with privileges of the pg_use_reserved_connections
|
||||||
* (MaxConnections - SuperuserReservedConnections). Note what this really
|
* predefined role. These are taken out of the pool of MaxConnections backend
|
||||||
* means is "if there are <= SuperuserReservedConnections connections
|
* slots, so the number of backend slots available for roles that are neither
|
||||||
* available, only superusers can make new connections" --- pre-existing
|
* superuser nor have privileges of pg_use_reserved_connections is
|
||||||
* superuser connections don't count against the limit.
|
* (MaxConnections - SuperuserReservedConnections - ReservedConnections).
|
||||||
|
*
|
||||||
|
* If the number of remaining slots is less than or equal to
|
||||||
|
* SuperuserReservedConnections, only superusers can make new connections. If
|
||||||
|
* the number of remaining slots is greater than SuperuserReservedConnections
|
||||||
|
* but less than or equal to
|
||||||
|
* (SuperuserReservedConnections + ReservedConnections), only superusers and
|
||||||
|
* roles with privileges of pg_use_reserved_connections can make new
|
||||||
|
* connections. Note that pre-existing superuser and
|
||||||
|
* pg_use_reserved_connections connections don't count against the limits.
|
||||||
*/
|
*/
|
||||||
int SuperuserReservedConnections;
|
int SuperuserReservedConnections;
|
||||||
|
int ReservedConnections;
|
||||||
|
|
||||||
/* The socket(s) we're listening to. */
|
/* The socket(s) we're listening to. */
|
||||||
#define MAXLISTEN 64
|
#define MAXLISTEN 64
|
||||||
@ -908,11 +918,12 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Check for invalid combinations of GUC settings.
|
* Check for invalid combinations of GUC settings.
|
||||||
*/
|
*/
|
||||||
if (SuperuserReservedConnections >= MaxConnections)
|
if (SuperuserReservedConnections + ReservedConnections >= MaxConnections)
|
||||||
{
|
{
|
||||||
write_stderr("%s: superuser_reserved_connections (%d) must be less than max_connections (%d)\n",
|
write_stderr("%s: superuser_reserved_connections (%d) plus reserved_connections (%d) must be less than max_connections (%d)\n",
|
||||||
progname,
|
progname,
|
||||||
SuperuserReservedConnections, MaxConnections);
|
SuperuserReservedConnections, ReservedConnections,
|
||||||
|
MaxConnections);
|
||||||
ExitPostmaster(1);
|
ExitPostmaster(1);
|
||||||
}
|
}
|
||||||
if (XLogArchiveMode > ARCHIVE_MODE_OFF && wal_level == WAL_LEVEL_MINIMAL)
|
if (XLogArchiveMode > ARCHIVE_MODE_OFF && wal_level == WAL_LEVEL_MINIMAL)
|
||||||
|
@ -645,27 +645,33 @@ GetStartupBufferPinWaitBufId(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether there are at least N free PGPROC objects.
|
* Check whether there are at least N free PGPROC objects. If false is
|
||||||
|
* returned, *nfree will be set to the number of free PGPROC objects.
|
||||||
|
* Otherwise, *nfree will be set to n.
|
||||||
*
|
*
|
||||||
* Note: this is designed on the assumption that N will generally be small.
|
* Note: this is designed on the assumption that N will generally be small.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
HaveNFreeProcs(int n)
|
HaveNFreeProcs(int n, int *nfree)
|
||||||
{
|
{
|
||||||
dlist_iter iter;
|
dlist_iter iter;
|
||||||
|
|
||||||
|
Assert(n > 0);
|
||||||
|
Assert(nfree);
|
||||||
|
|
||||||
SpinLockAcquire(ProcStructLock);
|
SpinLockAcquire(ProcStructLock);
|
||||||
|
|
||||||
|
*nfree = 0;
|
||||||
dlist_foreach(iter, &ProcGlobal->freeProcs)
|
dlist_foreach(iter, &ProcGlobal->freeProcs)
|
||||||
{
|
{
|
||||||
n--;
|
(*nfree)++;
|
||||||
if (n == 0)
|
if (*nfree == n)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpinLockRelease(ProcStructLock);
|
SpinLockRelease(ProcStructLock);
|
||||||
|
|
||||||
return (n <= 0);
|
return (*nfree == n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -719,6 +719,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
|
|||||||
bool am_superuser;
|
bool am_superuser;
|
||||||
char *fullpath;
|
char *fullpath;
|
||||||
char dbname[NAMEDATALEN];
|
char dbname[NAMEDATALEN];
|
||||||
|
int nfree = 0;
|
||||||
|
|
||||||
elog(DEBUG3, "InitPostgres");
|
elog(DEBUG3, "InitPostgres");
|
||||||
|
|
||||||
@ -922,16 +923,30 @@ InitPostgres(const char *in_dbname, Oid dboid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The last few connection slots are reserved for superusers. Replication
|
* The last few connection slots are reserved for superusers and roles with
|
||||||
* connections are drawn from slots reserved with max_wal_senders and not
|
* privileges of pg_use_reserved_connections. Replication connections are
|
||||||
* limited by max_connections or superuser_reserved_connections.
|
* drawn from slots reserved with max_wal_senders and are not limited by
|
||||||
|
* max_connections, superuser_reserved_connections, or
|
||||||
|
* reserved_connections.
|
||||||
|
*
|
||||||
|
* Note: At this point, the new backend has already claimed a proc struct,
|
||||||
|
* so we must check whether the number of free slots is strictly less than
|
||||||
|
* the reserved connection limits.
|
||||||
*/
|
*/
|
||||||
if (!am_superuser && !am_walsender &&
|
if (!am_superuser && !am_walsender &&
|
||||||
SuperuserReservedConnections > 0 &&
|
(SuperuserReservedConnections + ReservedConnections) > 0 &&
|
||||||
!HaveNFreeProcs(SuperuserReservedConnections))
|
!HaveNFreeProcs(SuperuserReservedConnections + ReservedConnections, &nfree))
|
||||||
ereport(FATAL,
|
{
|
||||||
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
|
if (nfree < SuperuserReservedConnections)
|
||||||
errmsg("remaining connection slots are reserved for superusers")));
|
ereport(FATAL,
|
||||||
|
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
|
||||||
|
errmsg("remaining connection slots are reserved for superusers")));
|
||||||
|
|
||||||
|
if (!has_privs_of_role(GetUserId(), ROLE_PG_USE_RESERVED_CONNECTIONS))
|
||||||
|
ereport(FATAL,
|
||||||
|
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
|
||||||
|
errmsg("remaining connection slots are reserved for roles with privileges of pg_use_reserved_connections")));
|
||||||
|
}
|
||||||
|
|
||||||
/* Check replication permissions needed for walsender processes. */
|
/* Check replication permissions needed for walsender processes. */
|
||||||
if (am_walsender)
|
if (am_walsender)
|
||||||
|
@ -2168,6 +2168,17 @@ struct config_int ConfigureNamesInt[] =
|
|||||||
NULL, NULL, NULL
|
NULL, NULL, NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
{"reserved_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
|
||||||
|
gettext_noop("Sets the number of connection slots reserved for roles "
|
||||||
|
"with privileges of pg_use_reserved_connections."),
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
&ReservedConnections,
|
||||||
|
0, 0, MAX_BACKENDS,
|
||||||
|
NULL, NULL, NULL
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{"min_dynamic_shared_memory", PGC_POSTMASTER, RESOURCES_MEM,
|
{"min_dynamic_shared_memory", PGC_POSTMASTER, RESOURCES_MEM,
|
||||||
gettext_noop("Amount of dynamic shared memory reserved at startup."),
|
gettext_noop("Amount of dynamic shared memory reserved at startup."),
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
#port = 5432 # (change requires restart)
|
#port = 5432 # (change requires restart)
|
||||||
#max_connections = 100 # (change requires restart)
|
#max_connections = 100 # (change requires restart)
|
||||||
|
#reserved_connections = 0 # (change requires restart)
|
||||||
#superuser_reserved_connections = 3 # (change requires restart)
|
#superuser_reserved_connections = 3 # (change requires restart)
|
||||||
#unix_socket_directories = '/tmp' # comma-separated list of directories
|
#unix_socket_directories = '/tmp' # comma-separated list of directories
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
|
@ -89,5 +89,10 @@
|
|||||||
rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
|
rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
|
||||||
rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
|
rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
|
||||||
rolpassword => '_null_', rolvaliduntil => '_null_' },
|
rolpassword => '_null_', rolvaliduntil => '_null_' },
|
||||||
|
{ oid => '4550', oid_symbol => 'ROLE_PG_USE_RESERVED_CONNECTIONS',
|
||||||
|
rolname => 'pg_use_reserved_connections', rolsuper => 'f', rolinherit => 't',
|
||||||
|
rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
|
||||||
|
rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
|
||||||
|
rolpassword => '_null_', rolvaliduntil => '_null_' },
|
||||||
|
|
||||||
]
|
]
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
/* GUC options */
|
/* GUC options */
|
||||||
extern PGDLLIMPORT bool EnableSSL;
|
extern PGDLLIMPORT bool EnableSSL;
|
||||||
extern PGDLLIMPORT int SuperuserReservedConnections;
|
extern PGDLLIMPORT int SuperuserReservedConnections;
|
||||||
|
extern PGDLLIMPORT int ReservedConnections;
|
||||||
extern PGDLLIMPORT int PostPortNumber;
|
extern PGDLLIMPORT int PostPortNumber;
|
||||||
extern PGDLLIMPORT int Unix_socket_permissions;
|
extern PGDLLIMPORT int Unix_socket_permissions;
|
||||||
extern PGDLLIMPORT char *Unix_socket_group;
|
extern PGDLLIMPORT char *Unix_socket_group;
|
||||||
|
@ -445,7 +445,7 @@ extern void InitAuxiliaryProcess(void);
|
|||||||
extern void SetStartupBufferPinWaitBufId(int bufid);
|
extern void SetStartupBufferPinWaitBufId(int bufid);
|
||||||
extern int GetStartupBufferPinWaitBufId(void);
|
extern int GetStartupBufferPinWaitBufId(void);
|
||||||
|
|
||||||
extern bool HaveNFreeProcs(int n);
|
extern bool HaveNFreeProcs(int n, int *nfree);
|
||||||
extern void ProcReleaseLocks(bool isCommit);
|
extern void ProcReleaseLocks(bool isCommit);
|
||||||
|
|
||||||
extern ProcWaitStatus ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable);
|
extern ProcWaitStatus ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable);
|
||||||
|
Reference in New Issue
Block a user