Index: src/backend/postmaster/postmaster.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v retrieving revision 1.285 diff -c -r1.285 postmaster.c *** src/backend/postmaster/postmaster.c 2002/08/18 03:03:25 1.285 --- src/backend/postmaster/postmaster.c 2002/08/27 21:59:04 *************** *** 151,156 **** --- 151,168 ---- */ int MaxBackends = DEF_MAXBACKENDS; + /* + * ReservedBackends is the number of backends reserved for superuser use. + * This number is taken out of the pool size given by MaxBackends so + * number of backend slots available to none super users is + * (MaxBackends - ReservedBackends). Note, existing super user + * connections are not taken into account once this lower limit has + * been reached, i.e. superuser connections made before the lower limit + * is reached always count towards that limit and are not taken from + * ReservedBackends. + */ + int ReservedBackends = 2; + static char *progname = (char *) NULL; *************** *** 566,571 **** --- 578,589 ---- SetDataDir(potential_DataDir); ProcessConfigFile(PGC_POSTMASTER); + + /* + * Force an exit if ReservedBackends is not less than MaxBackends. + */ + if (ReservedBackends >= MaxBackends) + elog(FATAL,"superuser_reserved_connections must be less than max_connections."); /* * Now that we are done processing the postmaster arguments, reset Index: src/backend/storage/ipc/sinval.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/storage/ipc/sinval.c,v retrieving revision 1.49 diff -c -r1.49 sinval.c *** src/backend/storage/ipc/sinval.c 2002/06/20 20:29:35 1.49 --- src/backend/storage/ipc/sinval.c 2002/08/27 21:59:04 *************** *** 538,540 **** --- 538,564 ---- return NULL; } + + /* + * CountEmptyBackendSlots - count empty slots in backend process table + * + * Doesn't count since the procState array could be large and we've already + * allowed for that by running a freeBackends counter in the SI segment. + * Unlike CountActiveBackends() we do not need to interrogate the + * backends to determine the free slot count. + * Goes for a lock despite being a trival look up in case other backends + * are busy starting or exiting since there is scope for confusion. + */ + int + CountEmptyBackendSlots(void) + { + int count; + + LWLockAcquire(SInvalLock, LW_SHARED); + + count = shmInvalBuffer->freeBackends; + + LWLockRelease(SInvalLock); + + return count; + } Index: src/backend/storage/ipc/sinvaladt.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/storage/ipc/sinvaladt.c,v retrieving revision 1.47 diff -c -r1.47 sinvaladt.c *** src/backend/storage/ipc/sinvaladt.c 2002/06/20 20:29:35 1.47 --- src/backend/storage/ipc/sinvaladt.c 2002/08/27 21:59:05 *************** *** 60,65 **** --- 60,66 ---- segP->maxMsgNum = 0; segP->lastBackend = 0; segP->maxBackends = maxBackends; + segP->freeBackends = maxBackends; /* The buffer[] array is initially all unused, so we need not fill it */ *************** *** 91,96 **** --- 92,104 ---- int index; ProcState *stateP = NULL; + if (segP->freeBackends == 0) + { + /* out of procState slots */ + MyBackendId = InvalidBackendId; + return 0; + } + /* Look for a free entry in the procState array */ for (index = 0; index < segP->lastBackend; index++) { *************** *** 103,120 **** if (stateP == NULL) { ! if (segP->lastBackend < segP->maxBackends) ! { ! 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; --- 111,119 ---- if (stateP == NULL) { ! stateP = &segP->procState[segP->lastBackend]; ! Assert(stateP->nextMsgNum < 0); ! segP->lastBackend++; } MyBackendId = (stateP - &segP->procState[0]) + 1; *************** *** 123,128 **** --- 122,130 ---- elog(DEBUG1, "SIBackendInit: backend id %d", MyBackendId); #endif /* INVALIDDEBUG */ + /* Reduce free slot count */ + segP->freeBackends--; + /* mark myself active, with all extant messages already read */ stateP->nextMsgNum = segP->maxMsgNum; stateP->resetState = false; *************** *** 165,170 **** --- 167,175 ---- break; } segP->lastBackend = i; + + /* Adjust free slot count */ + segP->freeBackends++; LWLockRelease(SInvalLock); } Index: src/backend/utils/init/postinit.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/init/postinit.c,v retrieving revision 1.109 diff -c -r1.109 postinit.c *** src/backend/utils/init/postinit.c 2002/07/20 05:16:59 1.109 --- src/backend/utils/init/postinit.c 2002/08/27 21:59:05 *************** *** 402,407 **** --- 402,417 ---- /* close the transaction we started above */ if (!bootstrap) CommitTransactionCommand(); + + /* + * 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"); } /* Index: src/backend/utils/misc/guc.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v retrieving revision 1.84 diff -c -r1.84 guc.c *** src/backend/utils/misc/guc.c 2002/08/26 17:53:59 1.84 --- src/backend/utils/misc/guc.c 2002/08/27 21:59:09 *************** *** 537,547 **** /* * Note: There is some postprocessing done in PostmasterMain() to make * sure the buffers are at least twice the number of backends, so the ! * constraints here are partially unused. */ { { "max_connections", PGC_POSTMASTER }, &MaxBackends, DEF_MAXBACKENDS, 1, INT_MAX, NULL, NULL }, { --- 537,554 ---- /* * Note: There is some postprocessing done in PostmasterMain() to make * sure the buffers are at least twice the number of backends, so the ! * constraints here are partially unused. Similarly, the superuser ! * reserved number is checked to ensure it is less than the max ! * backends number. */ { { "max_connections", PGC_POSTMASTER }, &MaxBackends, DEF_MAXBACKENDS, 1, INT_MAX, NULL, NULL + }, + + { + { "superuser_reserved_connections", PGC_POSTMASTER }, &ReservedBackends, + 2, 0, INT_MAX, NULL, NULL }, { Index: src/backend/utils/misc/postgresql.conf.sample =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/postgresql.conf.sample,v retrieving revision 1.48 diff -c -r1.48 postgresql.conf.sample *** src/backend/utils/misc/postgresql.conf.sample 2002/08/27 14:06:05 1.48 --- src/backend/utils/misc/postgresql.conf.sample 2002/08/27 21:59:09 *************** *** 31,36 **** --- 31,37 ---- #ssl = false #max_connections = 32 + #superuser_reserved_connections = 2 #port = 5432 #hostname_lookup = false Index: src/include/miscadmin.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/miscadmin.h,v retrieving revision 1.106 diff -c -r1.106 miscadmin.h *** src/include/miscadmin.h 2002/06/20 20:29:42 1.106 --- src/include/miscadmin.h 2002/08/27 21:59:11 *************** *** 179,184 **** --- 179,185 ---- extern bool EnableSSL; extern bool SilentMode; extern int MaxBackends; + extern int ReservedBackends; extern int NBuffers; extern int PostPortNumber; extern int Unix_socket_permissions; Index: src/include/storage/sinval.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/storage/sinval.h,v retrieving revision 1.28 diff -c -r1.28 sinval.h *** src/include/storage/sinval.h 2002/06/20 20:29:52 1.28 --- src/include/storage/sinval.h 2002/08/27 21:59:11 *************** *** 89,92 **** --- 89,94 ---- /* Use "struct PGPROC", not PGPROC, to avoid including proc.h here */ extern struct PGPROC *BackendIdGetProc(BackendId procId); + extern int CountEmptyBackendSlots(void); + #endif /* SINVAL_H */ Index: src/include/storage/sinvaladt.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/storage/sinvaladt.h,v retrieving revision 1.32 diff -c -r1.32 sinvaladt.h *** src/include/storage/sinvaladt.h 2002/06/20 20:29:52 1.32 --- src/include/storage/sinvaladt.h 2002/08/27 21:59:11 *************** *** 85,90 **** --- 85,91 ---- int lastBackend; /* index of last active procState entry, * +1 */ int maxBackends; /* size of procState array */ + int freeBackends; /* number of empty procState slots */ /* * Circular buffer holding shared-inval messages