summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane1999-02-19 06:06:39 +0000
committerTom Lane1999-02-19 06:06:39 +0000
commite77b630cf0c1501008b3b72b5621f2951ef82b71 (patch)
tree6b25afa56af95f41ced9eab5e56f12eb58f03d7b /src/backend
parent612b8434e40edc299e38bd6e4d7ac07183513118 (diff)
Allow maximum number of backends to be set at configure time
(--with-maxbackends). Add a postmaster switch (-N backends) that allows the limit to be reduced at postmaster start time. (You can't increase it, sorry to say, because there are still some fixed-size arrays.) Grab the number of semaphores indicated by min(MAXBACKENDS, -N) at postmaster startup, so that this particular form of bogus configuration is exposed immediately rather than under heavy load.
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/postmaster/postmaster.c44
-rw-r--r--src/backend/storage/ipc/ipci.c12
-rw-r--r--src/backend/storage/ipc/sinvaladt.c14
-rw-r--r--src/backend/storage/lmgr/lock.c14
-rw-r--r--src/backend/storage/lmgr/proc.c67
-rw-r--r--src/backend/utils/init/postinit.c4
6 files changed, 110 insertions, 45 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 7dad294bc9..41099d9c05 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.101 1999/02/13 23:17:40 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.102 1999/02/19 06:06:00 tgl Exp $
*
* NOTES
*
@@ -162,8 +162,17 @@ static IpcMemoryKey ipc_key;
* adding to this.
*/
+static int MaxBackends = MAXBACKENDS;
-static int NextBackendId = MAXINT; /* XXX why? */
+ /*
+ * MaxBackends is the actual soft limit on the number of backends
+ * we will start. It defaults to the hard limit established at compilation
+ * time, but can be readjusted with postmaster's xxx switch.
+ * One reason to reduce MaxBackends is to allow startup under a kernel
+ * that won't let us get MAXBACKENDS semaphores!
+ */
+
+static int NextBackendTag = MAXINT; /* XXX why count down not up? */
static char *progname = (char *) NULL;
static char **real_argv;
static int real_argc;
@@ -388,7 +397,7 @@ PostmasterMain(int argc, char *argv[])
DataDir = getenv("PGDATA"); /* default value */
opterr = 0;
- while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:dim:Mno:p:Ss")) != EOF)
+ while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:dim:MN:no:p:Ss")) != EOF)
{
switch (opt)
{
@@ -463,6 +472,17 @@ PostmasterMain(int argc, char *argv[])
* 'postmaster'
*/
break;
+ case 'N':
+ /*
+ * The max number of backends to start.
+ * Can't set to less than 1 or more than compiled-in limit.
+ */
+ MaxBackends = atoi(optarg);
+ if (MaxBackends < 1)
+ MaxBackends = 1;
+ if (MaxBackends > MAXBACKENDS)
+ MaxBackends = MAXBACKENDS;
+ break;
case 'n':
/* Don't reinit shared mem after abnormal exit */
Reinit = false;
@@ -621,6 +641,8 @@ usage(const char *progname)
fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
fprintf(stderr, "\t-d [1|2|3]\tset debugging level\n");
fprintf(stderr, "\t-i \t\tlisten on TCP/IP sockets as well as Unix domain socket\n");
+ fprintf(stderr, "\t-N nprocs\tset max number of backend servers (1..%d)\n",
+ MAXBACKENDS);
fprintf(stderr, "\t-n \t\tdon't reinitialize shared memory after abnormal exit\n");
fprintf(stderr, "\t-o option\tpass 'option' to each backend servers\n");
fprintf(stderr, "\t-p port\tspecify port for postmaster to listen on\n");
@@ -765,7 +787,7 @@ ServerLoop(void)
if (status == STATUS_OK && port->pktInfo.state == Idle)
{
/* Can't start backend if max backend count is exceeded. */
- if (CountChildren() >= MaxBackendId)
+ if (CountChildren() >= MaxBackends)
PacketSendError(&port->pktInfo,
"Sorry, too many clients already");
else
@@ -1009,7 +1031,7 @@ static void
reset_shared(short port)
{
ipc_key = port * 1000 + shmem_seq * 100;
- CreateSharedMemoryAndSemaphores(ipc_key);
+ CreateSharedMemoryAndSemaphores(ipc_key, MaxBackends);
ActiveBackends = FALSE;
shmem_seq += 1;
if (shmem_seq >= 10)
@@ -1272,7 +1294,7 @@ BackendStartup(Port *port)
*/
sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
putenv(envEntry[0]);
- sprintf(envEntry[1], "POSTID=%d", NextBackendId);
+ sprintf(envEntry[1], "POSTID=%d", NextBackendTag);
putenv(envEntry[1]);
sprintf(envEntry[2], "PG_USER=%s", port->user);
putenv(envEntry[2]);
@@ -1348,9 +1370,11 @@ BackendStartup(Port *port)
progname, pid, port->user, port->database,
port->sock);
- /* adjust backend counter */
- /* XXX Don't know why this is done, but for now backend needs it */
- NextBackendId -= 1;
+ /* Generate a new backend tag for every backend we start */
+ /* XXX theoretically this could wrap around, if you have the patience
+ * to start 2^31 backends ...
+ */
+ NextBackendTag -= 1;
/*
* Everything's been successful, it's safe to add this backend to our
@@ -1459,7 +1483,7 @@ DoBackend(Port *port)
/* OK, let's unblock our signals, all together now... */
sigprocmask(SIG_SETMASK, &oldsigmask, 0);
- /* Close the postmater sockets */
+ /* Close the postmaster sockets */
if (NetServer)
StreamClose(ServerSock_INET);
#ifndef __CYGWIN32__
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 0a75af6c3e..fb27b92d22 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.18 1999/02/13 23:18:11 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.19 1999/02/19 06:06:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -44,17 +44,19 @@ SystemPortAddressCreateIPCKey(SystemPortAddress address)
CreateSharedMemoryAndSemaphores
is called exactly *ONCE* by the postmaster.
- It is *NEVER* called by the postgres backend
+ It is *NEVER* called by the postgres backend,
+ except in the case of a standalone backend.
0) destroy any existing semaphores for both buffer
and lock managers.
1) create the appropriate *SHARED* memory segments
for the two resource managers.
+ 2) create shared semaphores as needed.
**************************************************/
void
-CreateSharedMemoryAndSemaphores(IPCKey key)
+CreateSharedMemoryAndSemaphores(IPCKey key, int maxBackends)
{
int size;
@@ -98,7 +100,7 @@ CreateSharedMemoryAndSemaphores(IPCKey key)
* do process table stuff
* ----------------
*/
- InitProcGlobal(key);
+ InitProcGlobal(key, maxBackends);
on_shmem_exit(ProcFreeAllSemaphores, NULL);
CreateSharedInvalidationState(key);
@@ -120,7 +122,7 @@ AttachSharedMemoryAndSemaphores(IPCKey key)
*/
if (key == PrivateIPCKey)
{
- CreateSharedMemoryAndSemaphores(key);
+ CreateSharedMemoryAndSemaphores(key, 1);
return;
}
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index 0eee0c8022..c5dcea61ae 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.16 1999/02/13 23:18:16 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.17 1999/02/19 06:06:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -119,7 +119,7 @@ SIAssignBackendId(SISeg *segInOutP, BackendTag backendTag)
stateP = NULL;
- for (index = 0; index < MaxBackendId; index += 1)
+ for (index = 0; index < MAXBACKENDS; index++)
{
if (segInOutP->procState[index].tag == InvalidBackendTag ||
segInOutP->procState[index].tag == backendTag)
@@ -141,7 +141,7 @@ SIAssignBackendId(SISeg *segInOutP, BackendTag backendTag)
/* verify that all "procState" entries checked for matching tags */
- for (index += 1; index < MaxBackendId; index += 1)
+ for (index++; index < MAXBACKENDS; index++)
{
if (segInOutP->procState[index].tag == backendTag)
{
@@ -565,7 +565,7 @@ SIDecProcLimit(SISeg *segP, int num)
{
int i;
- for (i = 0; i < MaxBackendId; i++)
+ for (i = 0; i < MAXBACKENDS; i++)
{
/* decrement only, if there is a limit > 0 */
if (segP->procState[i].limit > 0)
@@ -622,7 +622,7 @@ SISetProcStateInvalid(SISeg *segP)
{
int i;
- for (i = 0; i < MaxBackendId; i++)
+ for (i = 0; i < MAXBACKENDS; i++)
{
if (segP->procState[i].limit == 0)
{
@@ -696,7 +696,7 @@ SIDelExpiredDataEntries(SISeg *segP)
h;
min = 9999999;
- for (i = 0; i < MaxBackendId; i++)
+ for (i = 0; i < MAXBACKENDS; i++)
{
h = SIGetProcStateLimit(segP, i);
if (h >= 0)
@@ -740,7 +740,7 @@ SISegInit(SISeg *segP)
SISetEndEntryChain(segP, InvalidOffset);
SISetNumEntries(segP, 0);
SISetMaxNumEntries(segP, MAXNUMMESSAGES);
- for (i = 0; i < MaxBackendId; i++)
+ for (i = 0; i < MAXBACKENDS; i++)
{
segP->procState[i].limit = -1; /* no backend active !! */
segP->procState[i].resetState = false;
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 39fac457a1..06f6fe7b4d 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.41 1999/02/13 23:18:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.42 1999/02/19 06:06:06 tgl Exp $
*
* NOTES
* Outside modules can create a lock table and acquire/release
@@ -1492,8 +1492,8 @@ LockShmemSize()
nXidBuckets = 1 << (int) my_log2((NLOCKS_PER_XACT - 1) / DEF_FFACTOR + 1);
nXidSegs = 1 << (int) my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
- size += MAXALIGN(NBACKENDS * sizeof(PROC)); /* each MyProc */
- size += MAXALIGN(NBACKENDS * sizeof(LOCKMETHODCTL)); /* each
+ size += MAXALIGN(MAXBACKENDS * sizeof(PROC)); /* each MyProc */
+ size += MAXALIGN(MAXBACKENDS * sizeof(LOCKMETHODCTL)); /* each
* lockMethodTable->ctl */
size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
@@ -1504,10 +1504,10 @@ LockShmemSize()
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(sizeof(LOCK))); /* contains hash key */
- size += MAXALIGN(my_log2(NBACKENDS) * sizeof(void *));
+ size += MAXALIGN(my_log2(MAXBACKENDS) * sizeof(void *));
size += MAXALIGN(sizeof(HHDR));
size += nXidSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
- size += NBACKENDS * /* XXX not multiple of BUCKET_ALLOC_INCR? */
+ size += MAXBACKENDS * /* XXX not multiple of BUCKET_ALLOC_INCR? */
(MAXALIGN(sizeof(BUCKET_INDEX)) +
MAXALIGN(sizeof(XIDLookupEnt))); /* contains hash key */
@@ -1552,7 +1552,7 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
HTAB *xidTable;
bool found;
- static PROC *checked_procs[MaxBackendId];
+ static PROC *checked_procs[MAXBACKENDS];
static int nprocs;
static bool MyNHolding;
@@ -1674,7 +1674,7 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check)
if (j >= nprocs && lock != findlock)
{
checked_procs[nprocs++] = proc;
- Assert(nprocs <= MaxBackendId);
+ Assert(nprocs <= MAXBACKENDS);
/*
* For non-MyProc entries, we are looking only
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index de09b4a5b0..ae8fb17fca 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.48 1999/02/13 23:18:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.49 1999/02/19 06:06:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,7 +46,7 @@
* This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95
*
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.48 1999/02/13 23:18:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.49 1999/02/19 06:06:08 tgl Exp $
*/
#include <sys/time.h>
#include <unistd.h>
@@ -108,13 +108,24 @@ static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
/*
* InitProcGlobal -
* initializes the global process table. We put it here so that
- * the postmaster can do this initialization. (ProcFreeAllSem needs
+ * the postmaster can do this initialization. (ProcFreeAllSemaphores needs
* to read this table on exiting the postmaster. If we have the first
* backend do this, starting up and killing the postmaster without
* starting any backends will be a problem.)
+ *
+ * We also allocate all the per-process semaphores we will need to support
+ * the requested number of backends. We used to allocate semaphores
+ * only when backends were actually started up, but that is bad because
+ * it lets Postgres fail under load --- a lot of Unix systems are
+ * (mis)configured with small limits on the number of semaphores, and
+ * running out when trying to start another backend is a common failure.
+ * So, now we grab enough semaphores to support the desired max number
+ * of backends immediately at initialization --- if the sysadmin has set
+ * MaxBackends higher than his kernel will support, he'll find out sooner
+ * rather than later.
*/
void
-InitProcGlobal(IPCKey key)
+InitProcGlobal(IPCKey key, int maxBackends)
{
bool found = false;
@@ -134,6 +145,24 @@ InitProcGlobal(IPCKey key)
ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
ProcGlobal->freeSemMap[i] = 0;
+ /* Pre-create the semaphores for the first maxBackends processes */
+ for (i = 0;
+ i < (maxBackends+PROC_NSEMS_PER_SET-1) / PROC_NSEMS_PER_SET;
+ i++)
+ {
+ IPCKey semKey = ProcGlobal->currKey + i;
+ int semId;
+ int semstat;
+
+ semId = IpcSemaphoreCreate(semKey,
+ PROC_NSEMS_PER_SET,
+ IPCProtection,
+ IpcSemaphoreDefaultStartValue,
+ 0,
+ &semstat);
+ /* mark this sema set allocated */
+ ProcGlobal->freeSemMap[i] = (1 << PROC_NSEMS_PER_SET);
+ }
}
}
@@ -222,6 +251,11 @@ InitProcess(IPCKey key)
ProcGetNewSemKeyAndNum(&semKey, &semNum);
+ /* Note: because of the pre-allocation done in InitProcGlobal,
+ * this call should always attach to an existing semaphore.
+ * It will (try to) create a new group of semaphores only if
+ * the postmaster tries to start more backends than it said it would.
+ */
semId = IpcSemaphoreCreate(semKey,
PROC_NSEMS_PER_SET,
IPCProtection,
@@ -823,20 +857,20 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
{
int i;
int32 *freeSemMap = ProcGlobal->freeSemMap;
- unsigned int fullmask;
+ int32 fullmask = (1 << (PROC_NSEMS_PER_SET+1)) - 1;
/*
* we hold ProcStructLock when entering this routine. We scan through
* the bitmap to look for a free semaphore.
*/
- fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
+
for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
{
int mask = 1;
int j;
if (freeSemMap[i] == fullmask)
- continue; /* none free for this set */
+ continue; /* this set is fully allocated */
for (j = 0; j < PROC_NSEMS_PER_SET; j++)
{
@@ -845,8 +879,9 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
/*
* a free semaphore found. Mark it as allocated.
+ * Also set the bit indicating whole set is allocated.
*/
- freeSemMap[i] |= mask;
+ freeSemMap[i] |= mask + (1 << PROC_NSEMS_PER_SET);
*key = ProcGlobal->currKey + i;
*semNum = j;
@@ -862,8 +897,7 @@ ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
/*
* ProcFreeSem -
- * free up our semaphore in the semaphore set. If we're the last one
- * in the set, also remove the semaphore set.
+ * free up our semaphore in the semaphore set.
*/
static void
ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
@@ -876,14 +910,19 @@ ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
mask = ~(1 << semNum);
freeSemMap[i] &= mask;
- if (freeSemMap[i] == 0)
- IpcSemaphoreKill(semKey);
+ /* Formerly we'd release a semaphore set if it was now completely unused,
+ * but now we keep the semaphores to ensure we won't run out when
+ * starting new backends --- cf. InitProcGlobal. Note that the
+ * PROC_NSEMS_PER_SET+1'st bit of the freeSemMap entry remains set to
+ * indicate it is still allocated; ProcFreeAllSemaphores() needs that.
+ */
}
/*
* ProcFreeAllSemaphores -
- * on exiting the postmaster, we free up all the semaphores allocated
- * to the lmgrs of the backends.
+ * called at shmem_exit time, ie when exiting the postmaster or
+ * destroying shared state for a failed set of backends.
+ * Free up all the semaphores allocated to the lmgrs of the backends.
*/
void
ProcFreeAllSemaphores()
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 5f94168334..0d60403e32 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.37 1999/02/13 23:20:02 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.38 1999/02/19 06:06:10 tgl Exp $
*
* NOTES
* InitPostgres() is the function called from PostgresMain
@@ -571,7 +571,7 @@ InitPostgres(char *name) /* database name */
*/
InitProcess(PostgresIpcKey);
- if (MyBackendId > MaxBackendId || MyBackendId <= 0)
+ if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
{
elog(FATAL, "cinit2: bad backend id %d (%d)",
MyBackendTag,