diff options
| author | Tom Lane | 1999-02-19 06:06:39 +0000 |
|---|---|---|
| committer | Tom Lane | 1999-02-19 06:06:39 +0000 |
| commit | e77b630cf0c1501008b3b72b5621f2951ef82b71 (patch) | |
| tree | 6b25afa56af95f41ced9eab5e56f12eb58f03d7b /src/backend | |
| parent | 612b8434e40edc299e38bd6e4d7ac07183513118 (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.c | 44 | ||||
| -rw-r--r-- | src/backend/storage/ipc/ipci.c | 12 | ||||
| -rw-r--r-- | src/backend/storage/ipc/sinvaladt.c | 14 | ||||
| -rw-r--r-- | src/backend/storage/lmgr/lock.c | 14 | ||||
| -rw-r--r-- | src/backend/storage/lmgr/proc.c | 67 | ||||
| -rw-r--r-- | src/backend/utils/init/postinit.c | 4 |
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, |
