Commit 2917f0a5 authored by Tom Lane's avatar Tom Lane

Tweak startup sequence so that running out of PROC array slots is

detected sooner in backend startup, and is treated as an expected error
(it gives 'Sorry, too many clients already' now).  This allows us not
to have to enforce the MaxBackends limit exactly in the postmaster.
Also, remove ProcRemove() and fold its functionality into ProcKill().
There's no good reason for a backend not to be responsible for removing
its PROC entry, and there are lots of good reasons for the postmaster
not to be touching shared-memory data structures.
parent 668db147
......@@ -28,7 +28,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.220 2001/06/14 19:59:24 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.221 2001/06/16 22:58:12 tgl Exp $
*
* NOTES
*
......@@ -1280,8 +1280,16 @@ canAcceptConnections(void)
return "The Data Base System is starting up";
if (FatalError)
return "The Data Base System is in recovery mode";
/* Can't start backend if max backend count is exceeded. */
if (CountChildren() >= MaxBackends)
/*
* Don't start too many children.
*
* We allow more connections than we can have backends here because
* some might still be authenticating; they might fail auth, or some
* existing backend might exit before the auth cycle is completed.
* The exact MaxBackends limit is enforced when a new backend tries
* to join the shared-inval backend array.
*/
if (CountChildren() >= 2 * MaxBackends)
return "Sorry, too many clients already";
return NULL;
......@@ -1738,12 +1746,6 @@ CleanupProc(int pid,
GetRedoRecPtr();
}
}
else
{
/* Why is this done here, and not by the backend itself? */
if (!FatalError)
ProcRemove(pid);
}
return;
}
......@@ -1765,7 +1767,6 @@ CleanupProc(int pid,
bp = (Backend *) DLE_VAL(curr);
if (bp->pid != pid)
{
/*
* This backend is still alive. Unless we did so already,
* tell it to commit hara-kiri.
......@@ -1786,13 +1787,8 @@ CleanupProc(int pid,
}
else
{
/*
* Found entry for freshly-dead backend, so remove it.
*
* Don't call ProcRemove() here, since shmem may be corrupted! We
* are going to reinitialize shmem and semaphores anyway once
* all the children are dead, so no need for it.
*/
DLRemove(curr);
free(bp);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.32 2001/06/01 20:07:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.33 2001/06/16 22:58:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -43,13 +43,15 @@ CreateSharedInvalidationState(int maxBackends)
void
InitBackendSharedInvalidationState(void)
{
int flag;
SpinAcquire(SInvalLock);
if (!SIBackendInit(shmInvalBuffer))
{
flag = SIBackendInit(shmInvalBuffer);
SpinRelease(SInvalLock);
if (flag < 0) /* unexpected problem */
elog(FATAL, "Backend cache invalidation initialization failed");
}
SpinRelease(SInvalLock);
if (flag == 0) /* expected problem: MaxBackends exceeded */
elog(FATAL, "Sorry, too many clients already");
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.38 2001/03/22 03:59:45 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.39 2001/06/16 22:58:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -79,6 +79,11 @@ SIBufferInit(int maxBackends)
* SIBackendInit
* Initialize a new backend to operate on the sinval buffer
*
* Returns:
* >0 A-OK
* 0 Failed to find a free procState slot (ie, MaxBackends exceeded)
* <0 Some other failure (not currently used)
*
* NB: this routine, and all following ones, must be executed with the
* SInvalLock spinlock held, since there may be multiple backends trying
* to access the buffer.
......@@ -109,12 +114,7 @@ SIBackendInit(SISeg *segP)
}
else
{
/*
* elog() with spinlock held is probably not too cool, but
* this condition should never happen anyway.
*/
elog(NOTICE, "SIBackendInit: no free procState slot available");
/* out of procState slots */
MyBackendId = InvalidBackendId;
return 0;
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.102 2001/05/25 15:45:33 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.103 2001/06/16 22:58:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -390,45 +390,16 @@ ProcReleaseLocks(bool isCommit)
!isCommit, GetCurrentTransactionId());
}
/*
* ProcRemove -
* called by the postmaster to clean up the global tables after a
* backend exits. This also frees up the proc's wait semaphore.
*/
bool
ProcRemove(int pid)
{
SHMEM_OFFSET location;
PROC *proc;
location = ShmemPIDDestroy(pid);
if (location == INVALID_OFFSET)
return FALSE;
proc = (PROC *) MAKE_PTR(location);
SpinAcquire(ProcStructLock);
ProcFreeSem(proc->sem.semId, proc->sem.semNum);
/* Add PROC struct to freelist so space can be recycled in future */
proc->links.next = ProcGlobal->freeProcs;
ProcGlobal->freeProcs = MAKE_OFFSET(proc);
SpinRelease(ProcStructLock);
return TRUE;
}
/*
* ProcKill() -- Destroy the per-proc data structure for
* this process. Release any of its held spin locks.
*
* This is done inside the backend process before it exits.
* ProcRemove, above, will be done by the postmaster afterwards.
*/
static void
ProcKill(void)
{
SHMEM_OFFSET location;
Assert(MyProc);
/* Release any spinlocks I am holding */
......@@ -445,9 +416,26 @@ ProcKill(void)
LockReleaseAll(USER_LOCKMETHOD, MyProc, true, InvalidTransactionId);
#endif
/* Remove my PROC struct from the shmem hash table */
location = ShmemPIDDestroy(MyProcPid);
Assert(location != INVALID_OFFSET);
Assert(MyProc == (PROC *) MAKE_PTR(location));
SpinAcquire(ProcStructLock);
/* Free up my wait semaphore */
ProcFreeSem(MyProc->sem.semId, MyProc->sem.semNum);
/* Add PROC struct to freelist so space can be recycled in future */
MyProc->links.next = ProcGlobal->freeProcs;
ProcGlobal->freeProcs = MAKE_OFFSET(MyProc);
SpinRelease(ProcStructLock);
MyProc = NULL;
}
/*
* ProcQueue package: routines for putting processes to sleep
* and waking them up
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.86 2001/05/30 20:52:32 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.87 2001/06/16 22:58:16 tgl Exp $
*
*
*-------------------------------------------------------------------------
......@@ -148,13 +148,11 @@ ReverifyMyDatabase(const char *name)
static void
InitCommunication(void)
{
/*
* initialize shared memory and semaphores appropriately.
*/
if (!IsUnderPostmaster) /* postmaster already did this */
{
/*
* we're running a postgres backend by itself with no front end or
* postmaster. Create private "shmem" and semaphores. Setting
......@@ -168,11 +166,16 @@ InitCommunication(void)
/*
* Early initialization of a backend (either standalone or under postmaster).
* This happens even before InitPostgres.
*
* If you're wondering why this is separate from InitPostgres at all:
* the critical distinction is that this stuff has to happen before we can
* run XLOG-related initialization, which is done before InitPostgres --- in
* fact, for cases such as checkpoint creation processes, InitPostgres may
* never be done at all.
*/
void
BaseInit(void)
{
/*
* Attach to shared memory and semaphores, and initialize our
* input/output/debugging file descriptors.
......@@ -184,8 +187,6 @@ BaseInit(void)
smgrinit();
InitBufferPoolAccess();
InitLocalBuffer();
EnablePortalManager(); /* memory for portal/transaction stuff */
}
......@@ -202,16 +203,18 @@ InitPostgres(const char *dbname, const char *username)
{
bool bootstrap = IsBootstrapProcessingMode();
SetDatabaseName(dbname);
/*
* initialize the database id used for system caches and lock tables
* Set up the global variables holding database name, id, and path.
*
* We take a shortcut in the bootstrap case, otherwise we have to look up
* the db name in pg_database.
*/
SetDatabaseName(dbname);
if (bootstrap)
{
MyDatabaseId = TemplateDbOid;
SetDatabasePath(GetDatabasePath(MyDatabaseId));
LockDisable(true);
}
else
{
......@@ -259,6 +262,28 @@ InitPostgres(const char *dbname, const char *username)
* Code after this point assumes we are in the proper directory!
*/
/*
* Set up my per-backend PROC struct in shared memory. (We need to
* know MyDatabaseId before we can do this, since it's entered into
* the PROC struct.)
*/
InitProcess();
/*
* Initialize my entry in the shared-invalidation manager's array of
* per-backend data. (Formerly this came before InitProcess, but now
* it must happen after, because it uses MyProc.) Once I have done
* this, I am visible to other backends!
*
* Sets up MyBackendId, a unique backend identifier.
*/
MyBackendId = InvalidBackendId;
InitBackendSharedInvalidationState();
if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
elog(FATAL, "InitPostgres: bad backend id %d", MyBackendId);
/*
* Initialize the transaction system and the relation descriptor
* cache. Note we have to make certain the lock manager is off while
......@@ -281,26 +306,6 @@ InitPostgres(const char *dbname, const char *username)
LockDisable(false);
/*
* Set up my per-backend PROC struct in shared memory.
*/
InitProcess();
/*
* Initialize my entry in the shared-invalidation manager's array of
* per-backend data. (Formerly this came before InitProcess, but now
* it must happen after, because it uses MyProc.) Once I have done
* this, I am visible to other backends!
*
* Sets up MyBackendId, a unique backend identifier.
*/
MyBackendId = InvalidBackendId;
InitBackendSharedInvalidationState();
if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
elog(FATAL, "cinit2: bad backend id %d", MyBackendId);
/*
* Initialize the access methods. Does not touch files (?) - thomas
* 1997-11-01
......@@ -315,6 +320,9 @@ InitPostgres(const char *dbname, const char *username)
*/
InitCatalogCache();
/* Initialize portal manager */
EnablePortalManager();
/*
* Initialize the deferred trigger manager --- must happen before
* first transaction start.
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: proc.h,v 1.43 2001/05/25 15:45:34 momjian Exp $
* $Id: proc.h,v 1.44 2001/06/16 22:58:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -129,7 +129,6 @@ typedef struct procglobal
extern void InitProcGlobal(int maxBackends);
extern void InitProcess(void);
extern void ProcReleaseLocks(bool isCommit);
extern bool ProcRemove(int pid);
extern void ProcQueueInit(PROC_QUEUE *queue);
extern int ProcSleep(LOCKMETHODTABLE *lockMethodTable, LOCKMODE lockmode,
......
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