From 2917f0a5dd041295bd7e19f6bf868827640d44b0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 16 Jun 2001 22:58:17 +0000 Subject: [PATCH] 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. --- src/backend/postmaster/postmaster.c | 26 ++++++-------- src/backend/storage/ipc/sinval.c | 14 ++++---- src/backend/storage/ipc/sinvaladt.c | 14 ++++---- src/backend/storage/lmgr/proc.c | 52 +++++++++++----------------- src/backend/utils/init/postinit.c | 68 +++++++++++++++++++++---------------- src/include/storage/proc.h | 3 +- 6 files changed, 85 insertions(+), 92 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 1a71378a2e..3cb9e2938e 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -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); diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c index d60e6198f5..9177a81604 100644 --- a/src/backend/storage/ipc/sinval.c +++ b/src/backend/storage/ipc/sinval.c @@ -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)) - { - SpinRelease(SInvalLock); - elog(FATAL, "Backend cache invalidation initialization failed"); - } + flag = SIBackendInit(shmInvalBuffer); SpinRelease(SInvalLock); + if (flag < 0) /* unexpected problem */ + elog(FATAL, "Backend cache invalidation initialization failed"); + if (flag == 0) /* expected problem: MaxBackends exceeded */ + elog(FATAL, "Sorry, too many clients already"); } /* diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c index 06ba354d94..63bc037bc9 100644 --- a/src/backend/storage/ipc/sinvaladt.c +++ b/src/backend/storage/ipc/sinvaladt.c @@ -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; } diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index e64d3886aa..d2a8fe10df 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -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 diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index c3c3ad946e..dedd9a8e76 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -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 { @@ -260,6 +263,28 @@ InitPostgres(const char *dbname, const char *username) */ /* + * 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 * we do this. @@ -282,26 +307,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. diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 8118cf0e5c..a35c8f4481 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -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, -- 2.11.0