Commit 8362be35 authored by Tom Lane's avatar Tom Lane

Code review for superuser_reserved_connections patch. Don't try to do

database access outside a transaction; revert bogus performance improvement
in SIBackendInit(); improve comments; add documentation (this part courtesy
Neil Conway).
parent 02d83d75
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.157 2002/11/21 00:42:18 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.158 2002/11/21 06:36:08 tgl Exp $
--> -->
<Chapter Id="runtime"> <Chapter Id="runtime">
...@@ -1902,6 +1902,28 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir' ...@@ -1902,6 +1902,28 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>SUPERUSER_RESERVED_CONNECTIONS</varname>
(<type>integer</type>)</term>
<listitem>
<para>
Determines the number of <quote>connection slots</quote> that
are reserved for connections by <productname>PostgreSQL</>
superusers. At most <varname>max_connections</> connections can
ever be active simultaneously. Whenever the number of active
concurrent connections is at least <varname>max_connections</> minus
<varname>superuser_reserved_connections</varname>, new connections
will be accepted only from superuser accounts.
</para>
<para>
The default value is 2. The value must be less than the value of
<varname>max_connections</varname>. This parameter can only be
set at server start.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>TCPIP_SOCKET</varname> (<type>boolean</type>)</term> <term><varname>TCPIP_SOCKET</varname> (<type>boolean</type>)</term>
<listitem> <listitem>
...@@ -2952,24 +2974,25 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput ...@@ -2952,24 +2974,25 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
</para> </para>
<para> <para>
With SSL support compiled in, the <productname>PostgreSQL</> server With <acronym>SSL</> support compiled in, the
can be started with SSL support by setting the parameter <productname>PostgreSQL</> server can be started with
<varname>ssl</varname> to on in <acronym>SSL</> support by setting the parameter
<filename>postgresql.conf</filename>. When starting in SSL mode, <varname>ssl</varname> to on in <filename>postgresql.conf</>. When
the server will look for the files <filename>server.key</> and starting in <acronym>SSL</> mode, the server will look for the
<filename>server.crt</> in the data directory. These files should files <filename>server.key</> and <filename>server.crt</> in the
contain the server private key and certificate respectively. These data directory. These files should contain the server private key
files must be set up correctly before an SSL-enabled server can and certificate respectively. These files must be set up correctly
start. If the private key is protected with a passphrase, the before an <acronym>SSL</>-enabled server can start. If the private key is
server will prompt for the passphrase and will not start until it protected with a passphrase, the server will prompt for the
has been entered. passphrase and will not start until it has been entered.
</para> </para>
<para> <para>
The server will listen for both standard and SSL connections on the The server will listen for both standard and <acronym>SSL</>
same TCP/IP port, and will negotiate with any connecting client on connections on the same TCP/IP port, and will negotiate with any
whether to use SSL. See <xref linkend="client-authentication"> about connecting client on whether to use <acronym>SSL</>. See <xref
how to force the server to only use of SSL for certain connections. linkend="client-authentication"> about how to force the server to
require use of <acronym>SSL</> for certain connections.
</para> </para>
<para> <para>
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.298 2002/11/18 00:40:46 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.299 2002/11/21 06:36:08 tgl Exp $
* *
* NOTES * NOTES
* *
...@@ -154,12 +154,11 @@ int MaxBackends = DEF_MAXBACKENDS; ...@@ -154,12 +154,11 @@ int MaxBackends = DEF_MAXBACKENDS;
/* /*
* ReservedBackends is the number of backends reserved for superuser use. * ReservedBackends is the number of backends reserved for superuser use.
* This number is taken out of the pool size given by MaxBackends so * This number is taken out of the pool size given by MaxBackends so
* number of backend slots available to none super users is * number of backend slots available to non-superusers is
* (MaxBackends - ReservedBackends). Note, existing super user * (MaxBackends - ReservedBackends). Note what this really means is
* connections are not taken into account once this lower limit has * "if there are <= ReservedBackends connections available, only superusers
* been reached, i.e. superuser connections made before the lower limit * can make new connections" --- pre-existing superuser connections don't
* is reached always count towards that limit and are not taken from * count against the limit.
* ReservedBackends.
*/ */
int ReservedBackends = 2; int ReservedBackends = 2;
...@@ -568,7 +567,15 @@ PostmasterMain(int argc, char *argv[]) ...@@ -568,7 +567,15 @@ PostmasterMain(int argc, char *argv[])
} }
/* /*
* Check for invalid combinations of switches * Now we can set the data directory, and then read postgresql.conf.
*/
checkDataDir(potential_DataDir); /* issues error messages */
SetDataDir(potential_DataDir);
ProcessConfigFile(PGC_POSTMASTER);
/*
* Check for invalid combinations of GUC settings.
*/ */
if (NBuffers < 2 * MaxBackends || NBuffers < 16) if (NBuffers < 2 * MaxBackends || NBuffers < 16)
{ {
...@@ -581,16 +588,11 @@ PostmasterMain(int argc, char *argv[]) ...@@ -581,16 +588,11 @@ PostmasterMain(int argc, char *argv[])
ExitPostmaster(1); ExitPostmaster(1);
} }
checkDataDir(potential_DataDir); /* issues error messages */
SetDataDir(potential_DataDir);
ProcessConfigFile(PGC_POSTMASTER);
/*
* Force an exit if ReservedBackends is not less than MaxBackends.
*/
if (ReservedBackends >= MaxBackends) if (ReservedBackends >= MaxBackends)
elog(FATAL, "superuser_reserved_connections must be less than max_connections."); {
postmaster_error("superuser_reserved_connections must be less than max_connections.");
ExitPostmaster(1);
}
/* /*
* Now that we are done processing the postmaster arguments, reset * Now that we are done processing the postmaster arguments, reset
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.52 2002/09/04 20:31:25 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.53 2002/11/21 06:36:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -542,12 +542,11 @@ BackendIdGetProc(BackendId procId) ...@@ -542,12 +542,11 @@ BackendIdGetProc(BackendId procId)
/* /*
* CountEmptyBackendSlots - count empty slots in backend process table * CountEmptyBackendSlots - count empty slots in backend process table
* *
* Doesn't count since the procState array could be large and we've already * We don't actually need to count, since sinvaladt.c maintains a
* allowed for that by running a freeBackends counter in the SI segment. * freeBackends counter in the SI segment.
* Unlike CountActiveBackends() we do not need to interrogate the *
* backends to determine the free slot count. * Acquiring the lock here is almost certainly overkill, but just in
* Goes for a lock despite being a trival look up in case other backends * case fetching an int is not atomic on your machine ...
* are busy starting or exiting since there is scope for confusion.
*/ */
int int
CountEmptyBackendSlots(void) CountEmptyBackendSlots(void)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.48 2002/08/29 21:02:12 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.49 2002/11/21 06:36:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -92,13 +92,6 @@ SIBackendInit(SISeg *segP) ...@@ -92,13 +92,6 @@ SIBackendInit(SISeg *segP)
int index; int index;
ProcState *stateP = NULL; ProcState *stateP = NULL;
if (segP->freeBackends == 0)
{
/* out of procState slots */
MyBackendId = InvalidBackendId;
return 0;
}
/* Look for a free entry in the procState array */ /* Look for a free entry in the procState array */
for (index = 0; index < segP->lastBackend; index++) for (index = 0; index < segP->lastBackend; index++)
{ {
...@@ -111,9 +104,18 @@ SIBackendInit(SISeg *segP) ...@@ -111,9 +104,18 @@ SIBackendInit(SISeg *segP)
if (stateP == NULL) if (stateP == NULL)
{ {
stateP = &segP->procState[segP->lastBackend]; if (segP->lastBackend < segP->maxBackends)
Assert(stateP->nextMsgNum < 0); {
segP->lastBackend++; stateP = &segP->procState[segP->lastBackend];
Assert(stateP->nextMsgNum < 0);
segP->lastBackend++;
}
else
{
/* out of procState slots */
MyBackendId = InvalidBackendId;
return 0;
}
} }
MyBackendId = (stateP - &segP->procState[0]) + 1; MyBackendId = (stateP - &segP->procState[0]) + 1;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.117 2002/10/03 19:19:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.118 2002/11/21 06:36:08 tgl Exp $
* *
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -377,6 +377,18 @@ InitPostgres(const char *dbname, const char *username) ...@@ -377,6 +377,18 @@ InitPostgres(const char *dbname, const char *username)
*/ */
RelationCacheInitializePhase3(); RelationCacheInitializePhase3();
/*
* Check a normal user hasn't connected to a superuser reserved slot.
* We can't do this till after we've read the user information, and
* we must do it inside a transaction since checking superuserness
* may require database access. The superuser check is probably the
* most expensive part; don't do it until necessary.
*/
if (ReservedBackends > 0 &&
CountEmptyBackendSlots() < ReservedBackends &&
!superuser())
elog(FATAL, "Non-superuser connection limit exceeded");
/* /*
* Initialize various default states that can't be set up until we've * Initialize various default states that can't be set up until we've
* selected the active user and done ReverifyMyDatabase. * selected the active user and done ReverifyMyDatabase.
...@@ -397,17 +409,6 @@ InitPostgres(const char *dbname, const char *username) ...@@ -397,17 +409,6 @@ InitPostgres(const char *dbname, const char *username)
/* close the transaction we started above */ /* close the transaction we started above */
if (!bootstrap) if (!bootstrap)
CommitTransactionCommand(true); CommitTransactionCommand(true);
/*
* Check a normal user hasn't connected to a superuser reserved slot.
* Do this here since we need the user information and that only
* happens after we've started bringing the shared memory online. So
* we wait until we've registered exit handlers and potentially shut
* an open transaction down for an as safety conscious rejection as
* possible.
*/
if (CountEmptyBackendSlots() < ReservedBackends && !superuser())
elog(ERROR, "Non-superuser connection limit exceeded");
} }
/* /*
......
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