diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 1a71378a2e342f5f756eb3f7580d1a4594d09183..3cb9e2938e8fae4a5a07685443184a063b6bb4bf 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 d60e6198f51334bc138177eb0f8bc79c4fbd9e93..9177a81604b894b7efd8b8e6023129caf7d7c7ae 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 06ba354d94a2ea4b9c11ba71da0fe096985e12bb..63bc037bc9a5d3db5b5a17578c5e0838cadd40c9 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 e64d3886aa46865f38a8a984599490c170787417..d2a8fe10df845ea74d7b64bda8a807db98c42542 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 c3c3ad946ec4880f4eedeef19a394fad7730dcb0..dedd9a8e7654dde06ac98eb06df6ad5bf15357da 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 { @@ -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. diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 8118cf0e5cecbfbea95ae953b2f7b81b8503c1cb..a35c8f4481ecfd4fa8d5ce7ed310af91705f188a 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,