aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/lmgr/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/lmgr/proc.c')
-rw-r--r--src/backend/storage/lmgr/proc.c67
1 files changed, 53 insertions, 14 deletions
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index de09b4a5b05..ae8fb17fcab 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()