Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2917f0a

Browse files
committed
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.
1 parent 668db14 commit 2917f0a

File tree

6 files changed

+85
-92
lines changed

6 files changed

+85
-92
lines changed

src/backend/postmaster/postmaster.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
*
2929
*
3030
* IDENTIFICATION
31-
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.220 2001/06/14 19:59:24 tgl Exp $
31+
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.221 2001/06/16 22:58:12 tgl Exp $
3232
*
3333
* NOTES
3434
*
@@ -1280,8 +1280,16 @@ canAcceptConnections(void)
12801280
return "The Data Base System is starting up";
12811281
if (FatalError)
12821282
return "The Data Base System is in recovery mode";
1283-
/* Can't start backend if max backend count is exceeded. */
1284-
if (CountChildren() >= MaxBackends)
1283+
/*
1284+
* Don't start too many children.
1285+
*
1286+
* We allow more connections than we can have backends here because
1287+
* some might still be authenticating; they might fail auth, or some
1288+
* existing backend might exit before the auth cycle is completed.
1289+
* The exact MaxBackends limit is enforced when a new backend tries
1290+
* to join the shared-inval backend array.
1291+
*/
1292+
if (CountChildren() >= 2 * MaxBackends)
12851293
return "Sorry, too many clients already";
12861294

12871295
return NULL;
@@ -1738,12 +1746,6 @@ CleanupProc(int pid,
17381746
GetRedoRecPtr();
17391747
}
17401748
}
1741-
else
1742-
{
1743-
/* Why is this done here, and not by the backend itself? */
1744-
if (!FatalError)
1745-
ProcRemove(pid);
1746-
}
17471749

17481750
return;
17491751
}
@@ -1765,7 +1767,6 @@ CleanupProc(int pid,
17651767
bp = (Backend *) DLE_VAL(curr);
17661768
if (bp->pid != pid)
17671769
{
1768-
17691770
/*
17701771
* This backend is still alive. Unless we did so already,
17711772
* tell it to commit hara-kiri.
@@ -1786,13 +1787,8 @@ CleanupProc(int pid,
17861787
}
17871788
else
17881789
{
1789-
17901790
/*
17911791
* Found entry for freshly-dead backend, so remove it.
1792-
*
1793-
* Don't call ProcRemove() here, since shmem may be corrupted! We
1794-
* are going to reinitialize shmem and semaphores anyway once
1795-
* all the children are dead, so no need for it.
17961792
*/
17971793
DLRemove(curr);
17981794
free(bp);

src/backend/storage/ipc/sinval.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.32 2001/06/01 20:07:16 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.33 2001/06/16 22:58:13 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -43,13 +43,15 @@ CreateSharedInvalidationState(int maxBackends)
4343
void
4444
InitBackendSharedInvalidationState(void)
4545
{
46+
int flag;
47+
4648
SpinAcquire(SInvalLock);
47-
if (!SIBackendInit(shmInvalBuffer))
48-
{
49-
SpinRelease(SInvalLock);
50-
elog(FATAL, "Backend cache invalidation initialization failed");
51-
}
49+
flag = SIBackendInit(shmInvalBuffer);
5250
SpinRelease(SInvalLock);
51+
if (flag < 0) /* unexpected problem */
52+
elog(FATAL, "Backend cache invalidation initialization failed");
53+
if (flag == 0) /* expected problem: MaxBackends exceeded */
54+
elog(FATAL, "Sorry, too many clients already");
5355
}
5456

5557
/*

src/backend/storage/ipc/sinvaladt.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.38 2001/03/22 03:59:45 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.39 2001/06/16 22:58:15 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -79,6 +79,11 @@ SIBufferInit(int maxBackends)
7979
* SIBackendInit
8080
* Initialize a new backend to operate on the sinval buffer
8181
*
82+
* Returns:
83+
* >0 A-OK
84+
* 0 Failed to find a free procState slot (ie, MaxBackends exceeded)
85+
* <0 Some other failure (not currently used)
86+
*
8287
* NB: this routine, and all following ones, must be executed with the
8388
* SInvalLock spinlock held, since there may be multiple backends trying
8489
* to access the buffer.
@@ -109,12 +114,7 @@ SIBackendInit(SISeg *segP)
109114
}
110115
else
111116
{
112-
113-
/*
114-
* elog() with spinlock held is probably not too cool, but
115-
* this condition should never happen anyway.
116-
*/
117-
elog(NOTICE, "SIBackendInit: no free procState slot available");
117+
/* out of procState slots */
118118
MyBackendId = InvalidBackendId;
119119
return 0;
120120
}

src/backend/storage/lmgr/proc.c

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.102 2001/05/25 15:45:33 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.103 2001/06/16 22:58:16 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -390,45 +390,16 @@ ProcReleaseLocks(bool isCommit)
390390
!isCommit, GetCurrentTransactionId());
391391
}
392392

393-
/*
394-
* ProcRemove -
395-
* called by the postmaster to clean up the global tables after a
396-
* backend exits. This also frees up the proc's wait semaphore.
397-
*/
398-
bool
399-
ProcRemove(int pid)
400-
{
401-
SHMEM_OFFSET location;
402-
PROC *proc;
403-
404-
location = ShmemPIDDestroy(pid);
405-
if (location == INVALID_OFFSET)
406-
return FALSE;
407-
proc = (PROC *) MAKE_PTR(location);
408-
409-
SpinAcquire(ProcStructLock);
410-
411-
ProcFreeSem(proc->sem.semId, proc->sem.semNum);
412-
413-
/* Add PROC struct to freelist so space can be recycled in future */
414-
proc->links.next = ProcGlobal->freeProcs;
415-
ProcGlobal->freeProcs = MAKE_OFFSET(proc);
416-
417-
SpinRelease(ProcStructLock);
418-
419-
return TRUE;
420-
}
421393

422394
/*
423395
* ProcKill() -- Destroy the per-proc data structure for
424396
* this process. Release any of its held spin locks.
425-
*
426-
* This is done inside the backend process before it exits.
427-
* ProcRemove, above, will be done by the postmaster afterwards.
428397
*/
429398
static void
430399
ProcKill(void)
431400
{
401+
SHMEM_OFFSET location;
402+
432403
Assert(MyProc);
433404

434405
/* Release any spinlocks I am holding */
@@ -445,9 +416,26 @@ ProcKill(void)
445416
LockReleaseAll(USER_LOCKMETHOD, MyProc, true, InvalidTransactionId);
446417
#endif
447418

419+
/* Remove my PROC struct from the shmem hash table */
420+
location = ShmemPIDDestroy(MyProcPid);
421+
Assert(location != INVALID_OFFSET);
422+
Assert(MyProc == (PROC *) MAKE_PTR(location));
423+
424+
SpinAcquire(ProcStructLock);
425+
426+
/* Free up my wait semaphore */
427+
ProcFreeSem(MyProc->sem.semId, MyProc->sem.semNum);
428+
429+
/* Add PROC struct to freelist so space can be recycled in future */
430+
MyProc->links.next = ProcGlobal->freeProcs;
431+
ProcGlobal->freeProcs = MAKE_OFFSET(MyProc);
432+
433+
SpinRelease(ProcStructLock);
434+
448435
MyProc = NULL;
449436
}
450437

438+
451439
/*
452440
* ProcQueue package: routines for putting processes to sleep
453441
* and waking them up

src/backend/utils/init/postinit.c

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.86 2001/05/30 20:52:32 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.87 2001/06/16 22:58:16 tgl Exp $
1212
*
1313
*
1414
*-------------------------------------------------------------------------
@@ -148,13 +148,11 @@ ReverifyMyDatabase(const char *name)
148148
static void
149149
InitCommunication(void)
150150
{
151-
152151
/*
153152
* initialize shared memory and semaphores appropriately.
154153
*/
155154
if (!IsUnderPostmaster) /* postmaster already did this */
156155
{
157-
158156
/*
159157
* we're running a postgres backend by itself with no front end or
160158
* postmaster. Create private "shmem" and semaphores. Setting
@@ -168,11 +166,16 @@ InitCommunication(void)
168166
/*
169167
* Early initialization of a backend (either standalone or under postmaster).
170168
* This happens even before InitPostgres.
169+
*
170+
* If you're wondering why this is separate from InitPostgres at all:
171+
* the critical distinction is that this stuff has to happen before we can
172+
* run XLOG-related initialization, which is done before InitPostgres --- in
173+
* fact, for cases such as checkpoint creation processes, InitPostgres may
174+
* never be done at all.
171175
*/
172176
void
173177
BaseInit(void)
174178
{
175-
176179
/*
177180
* Attach to shared memory and semaphores, and initialize our
178181
* input/output/debugging file descriptors.
@@ -184,8 +187,6 @@ BaseInit(void)
184187
smgrinit();
185188
InitBufferPoolAccess();
186189
InitLocalBuffer();
187-
188-
EnablePortalManager(); /* memory for portal/transaction stuff */
189190
}
190191

191192

@@ -202,16 +203,18 @@ InitPostgres(const char *dbname, const char *username)
202203
{
203204
bool bootstrap = IsBootstrapProcessingMode();
204205

205-
SetDatabaseName(dbname);
206-
207206
/*
208-
* initialize the database id used for system caches and lock tables
207+
* Set up the global variables holding database name, id, and path.
208+
*
209+
* We take a shortcut in the bootstrap case, otherwise we have to look up
210+
* the db name in pg_database.
209211
*/
212+
SetDatabaseName(dbname);
213+
210214
if (bootstrap)
211215
{
212216
MyDatabaseId = TemplateDbOid;
213217
SetDatabasePath(GetDatabasePath(MyDatabaseId));
214-
LockDisable(true);
215218
}
216219
else
217220
{
@@ -259,6 +262,28 @@ InitPostgres(const char *dbname, const char *username)
259262
* Code after this point assumes we are in the proper directory!
260263
*/
261264

265+
/*
266+
* Set up my per-backend PROC struct in shared memory. (We need to
267+
* know MyDatabaseId before we can do this, since it's entered into
268+
* the PROC struct.)
269+
*/
270+
InitProcess();
271+
272+
/*
273+
* Initialize my entry in the shared-invalidation manager's array of
274+
* per-backend data. (Formerly this came before InitProcess, but now
275+
* it must happen after, because it uses MyProc.) Once I have done
276+
* this, I am visible to other backends!
277+
*
278+
* Sets up MyBackendId, a unique backend identifier.
279+
*/
280+
MyBackendId = InvalidBackendId;
281+
282+
InitBackendSharedInvalidationState();
283+
284+
if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
285+
elog(FATAL, "InitPostgres: bad backend id %d", MyBackendId);
286+
262287
/*
263288
* Initialize the transaction system and the relation descriptor
264289
* cache. Note we have to make certain the lock manager is off while
@@ -281,26 +306,6 @@ InitPostgres(const char *dbname, const char *username)
281306

282307
LockDisable(false);
283308

284-
/*
285-
* Set up my per-backend PROC struct in shared memory.
286-
*/
287-
InitProcess();
288-
289-
/*
290-
* Initialize my entry in the shared-invalidation manager's array of
291-
* per-backend data. (Formerly this came before InitProcess, but now
292-
* it must happen after, because it uses MyProc.) Once I have done
293-
* this, I am visible to other backends!
294-
*
295-
* Sets up MyBackendId, a unique backend identifier.
296-
*/
297-
MyBackendId = InvalidBackendId;
298-
299-
InitBackendSharedInvalidationState();
300-
301-
if (MyBackendId > MAXBACKENDS || MyBackendId <= 0)
302-
elog(FATAL, "cinit2: bad backend id %d", MyBackendId);
303-
304309
/*
305310
* Initialize the access methods. Does not touch files (?) - thomas
306311
* 1997-11-01
@@ -315,6 +320,9 @@ InitPostgres(const char *dbname, const char *username)
315320
*/
316321
InitCatalogCache();
317322

323+
/* Initialize portal manager */
324+
EnablePortalManager();
325+
318326
/*
319327
* Initialize the deferred trigger manager --- must happen before
320328
* first transaction start.

src/include/storage/proc.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: proc.h,v 1.43 2001/05/25 15:45:34 momjian Exp $
10+
* $Id: proc.h,v 1.44 2001/06/16 22:58:17 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -129,7 +129,6 @@ typedef struct procglobal
129129
extern void InitProcGlobal(int maxBackends);
130130
extern void InitProcess(void);
131131
extern void ProcReleaseLocks(bool isCommit);
132-
extern bool ProcRemove(int pid);
133132

134133
extern void ProcQueueInit(PROC_QUEUE *queue);
135134
extern int ProcSleep(LOCKMETHODTABLE *lockMethodTable, LOCKMODE lockmode,

0 commit comments

Comments
 (0)