37
37
*
38
38
*
39
39
* IDENTIFICATION
40
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.580 2009/05/04 02:46:36 tgl Exp $
40
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.581 2009/05/05 19:59:00 tgl Exp $
41
41
*
42
42
* NOTES
43
43
*
135
135
* Also, "dead_end" children are in it: these are children launched just
136
136
* for the purpose of sending a friendly rejection message to a would-be
137
137
* client. We must track them because they are attached to shared memory,
138
- * but we know they will never become live backends.
138
+ * but we know they will never become live backends. dead_end children are
139
+ * not assigned a PMChildSlot.
139
140
*/
140
141
typedef struct bkend
141
142
{
142
143
pid_t pid ; /* process id of backend */
143
144
long cancel_key ; /* cancel key for cancels for this backend */
145
+ int child_slot ; /* PMChildSlot for this backend, if any */
144
146
bool is_autovacuum ; /* is it an autovacuum process? */
145
147
bool dead_end ; /* is it going to send an error and quit? */
146
148
Dlelem elem ; /* list link in BackendList */
@@ -149,15 +151,6 @@ typedef struct bkend
149
151
static Dllist * BackendList ;
150
152
151
153
#ifdef EXEC_BACKEND
152
- /*
153
- * Number of entries in the shared-memory backend table. This table is used
154
- * only for sending cancels, and therefore only includes children we allow
155
- * cancels on: regular backends and autovac workers. In particular we exclude
156
- * dead_end children, allowing the table to have a known maximum size, to wit
157
- * the same too-many-children limit enforced by canAcceptConnections().
158
- */
159
- #define NUM_BACKENDARRAY_ELEMS (2*MaxBackends)
160
-
161
154
static Backend * ShmemBackendArray ;
162
155
#endif
163
156
@@ -404,6 +397,7 @@ typedef struct
404
397
char DataDir [MAXPGPATH ];
405
398
int ListenSocket [MAXLISTEN ];
406
399
long MyCancelKey ;
400
+ int MyPMChildSlot ;
407
401
unsigned long UsedShmemSegID ;
408
402
void * UsedShmemSegAddr ;
409
403
slock_t * ShmemLock ;
@@ -413,6 +407,7 @@ typedef struct
413
407
slock_t * ProcStructLock ;
414
408
PROC_HDR * ProcGlobal ;
415
409
PGPROC * AuxiliaryProcs ;
410
+ PMSignalData * PMSignalState ;
416
411
InheritableSocket pgStatSock ;
417
412
pid_t PostmasterPid ;
418
413
TimestampTz PgStartTime ;
@@ -443,7 +438,7 @@ static bool save_backend_variables(BackendParameters * param, Port *port,
443
438
#endif
444
439
445
440
static void ShmemBackendArrayAdd (Backend * bn );
446
- static void ShmemBackendArrayRemove (pid_t pid );
441
+ static void ShmemBackendArrayRemove (Backend * bn );
447
442
#endif /* EXEC_BACKEND */
448
443
449
444
#define StartupDataBase () StartChildProcess(StartupProcess)
@@ -1771,7 +1766,7 @@ processCancelRequest(Port *port, void *pkt)
1771
1766
{
1772
1767
bp = (Backend * ) DLE_VAL (curr );
1773
1768
#else
1774
- for (i = 0 ; i < NUM_BACKENDARRAY_ELEMS ; i ++ )
1769
+ for (i = MaxLivePostmasterChildren () - 1 ; i >= 0 ; i -- )
1775
1770
{
1776
1771
bp = (Backend * ) & ShmemBackendArray [i ];
1777
1772
#endif
@@ -1836,10 +1831,10 @@ canAcceptConnections(void)
1836
1831
* MaxBackends limit is enforced when a new backend tries to join the
1837
1832
* shared-inval backend array.
1838
1833
*
1839
- * In the EXEC_BACKEND case, the limit here must match the size of the
1840
- * ShmemBackendArray, since all these processes will have cancel codes .
1834
+ * The limit here must match the sizes of the per-child-process arrays;
1835
+ * see comments for MaxLivePostmasterChildren() .
1841
1836
*/
1842
- if (CountChildren () >= 2 * MaxBackends )
1837
+ if (CountChildren () >= MaxLivePostmasterChildren () )
1843
1838
return CAC_TOOMANY ;
1844
1839
1845
1840
return CAC_OK ;
@@ -2439,8 +2434,8 @@ CleanupBackend(int pid,
2439
2434
/*
2440
2435
* If a backend dies in an ugly way then we must signal all other backends
2441
2436
* to quickdie. If exit status is zero (normal) or one (FATAL exit), we
2442
- * assume everything is all right and simply remove the backend from the
2443
- * active backend list.
2437
+ * assume everything is all right and proceed to remove the backend from
2438
+ * the active backend list.
2444
2439
*/
2445
2440
if (!EXIT_STATUS_0 (exitstatus ) && !EXIT_STATUS_1 (exitstatus ))
2446
2441
{
@@ -2454,10 +2449,21 @@ CleanupBackend(int pid,
2454
2449
2455
2450
if (bp -> pid == pid )
2456
2451
{
2457
- #ifdef EXEC_BACKEND
2458
2452
if (!bp -> dead_end )
2459
- ShmemBackendArrayRemove (pid );
2453
+ {
2454
+ if (!ReleasePostmasterChildSlot (bp -> child_slot ))
2455
+ {
2456
+ /*
2457
+ * Uh-oh, the child failed to clean itself up. Treat
2458
+ * as a crash after all.
2459
+ */
2460
+ HandleChildCrash (pid , exitstatus , _ ("server process" ));
2461
+ return ;
2462
+ }
2463
+ #ifdef EXEC_BACKEND
2464
+ ShmemBackendArrayRemove (bp );
2460
2465
#endif
2466
+ }
2461
2467
DLRemove (curr );
2462
2468
free (bp );
2463
2469
break ;
@@ -2500,10 +2506,13 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
2500
2506
/*
2501
2507
* Found entry for freshly-dead backend, so remove it.
2502
2508
*/
2503
- #ifdef EXEC_BACKEND
2504
2509
if (!bp -> dead_end )
2505
- ShmemBackendArrayRemove (pid );
2510
+ {
2511
+ (void ) ReleasePostmasterChildSlot (bp -> child_slot );
2512
+ #ifdef EXEC_BACKEND
2513
+ ShmemBackendArrayRemove (bp );
2506
2514
#endif
2515
+ }
2507
2516
DLRemove (curr );
2508
2517
free (bp );
2509
2518
/* Keep looping so we can signal remaining backends */
@@ -2931,14 +2940,7 @@ BackendStartup(Port *port)
2931
2940
pid_t pid ;
2932
2941
2933
2942
/*
2934
- * Compute the cancel key that will be assigned to this backend. The
2935
- * backend will have its own copy in the forked-off process' value of
2936
- * MyCancelKey, so that it can transmit the key to the frontend.
2937
- */
2938
- MyCancelKey = PostmasterRandom ();
2939
-
2940
- /*
2941
- * Make room for backend data structure. Better before the fork() so we
2943
+ * Create backend data structure. Better before the fork() so we
2942
2944
* can handle failure cleanly.
2943
2945
*/
2944
2946
bn = (Backend * ) malloc (sizeof (Backend ));
@@ -2950,8 +2952,26 @@ BackendStartup(Port *port)
2950
2952
return STATUS_ERROR ;
2951
2953
}
2952
2954
2955
+ /*
2956
+ * Compute the cancel key that will be assigned to this backend. The
2957
+ * backend will have its own copy in the forked-off process' value of
2958
+ * MyCancelKey, so that it can transmit the key to the frontend.
2959
+ */
2960
+ MyCancelKey = PostmasterRandom ();
2961
+ bn -> cancel_key = MyCancelKey ;
2962
+
2953
2963
/* Pass down canAcceptConnections state */
2954
2964
port -> canAcceptConnections = canAcceptConnections ();
2965
+ bn -> dead_end = (port -> canAcceptConnections != CAC_OK &&
2966
+ port -> canAcceptConnections != CAC_WAITBACKUP );
2967
+
2968
+ /*
2969
+ * Unless it's a dead_end child, assign it a child slot number
2970
+ */
2971
+ if (!bn -> dead_end )
2972
+ bn -> child_slot = MyPMChildSlot = AssignPostmasterChildSlot ();
2973
+ else
2974
+ bn -> child_slot = 0 ;
2955
2975
2956
2976
#ifdef EXEC_BACKEND
2957
2977
pid = backend_forkexec (port );
@@ -3009,10 +3029,7 @@ BackendStartup(Port *port)
3009
3029
* of backends.
3010
3030
*/
3011
3031
bn -> pid = pid ;
3012
- bn -> cancel_key = MyCancelKey ;
3013
3032
bn -> is_autovacuum = false;
3014
- bn -> dead_end = (port -> canAcceptConnections != CAC_OK &&
3015
- port -> canAcceptConnections != CAC_WAITBACKUP );
3016
3033
DLInitElem (& bn -> elem , bn );
3017
3034
DLAddHead (BackendList , & bn -> elem );
3018
3035
#ifdef EXEC_BACKEND
@@ -4271,23 +4288,26 @@ StartAutovacuumWorker(void)
4271
4288
*/
4272
4289
if (canAcceptConnections () == CAC_OK )
4273
4290
{
4274
- /*
4275
- * Compute the cancel key that will be assigned to this session. We
4276
- * probably don't need cancel keys for autovac workers, but we'd
4277
- * better have something random in the field to prevent unfriendly
4278
- * people from sending cancels to them.
4279
- */
4280
- MyCancelKey = PostmasterRandom ();
4281
-
4282
4291
bn = (Backend * ) malloc (sizeof (Backend ));
4283
4292
if (bn )
4284
4293
{
4294
+ /*
4295
+ * Compute the cancel key that will be assigned to this session. We
4296
+ * probably don't need cancel keys for autovac workers, but we'd
4297
+ * better have something random in the field to prevent unfriendly
4298
+ * people from sending cancels to them.
4299
+ */
4300
+ MyCancelKey = PostmasterRandom ();
4301
+ bn -> cancel_key = MyCancelKey ;
4302
+
4303
+ /* Autovac workers are not dead_end and need a child slot */
4304
+ bn -> dead_end = false;
4305
+ bn -> child_slot = MyPMChildSlot = AssignPostmasterChildSlot ();
4306
+
4285
4307
bn -> pid = StartAutoVacWorker ();
4286
4308
if (bn -> pid > 0 )
4287
4309
{
4288
- bn -> cancel_key = MyCancelKey ;
4289
4310
bn -> is_autovacuum = true;
4290
- bn -> dead_end = false;
4291
4311
DLInitElem (& bn -> elem , bn );
4292
4312
DLAddHead (BackendList , & bn -> elem );
4293
4313
#ifdef EXEC_BACKEND
@@ -4353,6 +4373,24 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
4353
4373
}
4354
4374
4355
4375
4376
+ /*
4377
+ * MaxLivePostmasterChildren
4378
+ *
4379
+ * This reports the number of entries needed in per-child-process arrays
4380
+ * (the PMChildFlags array, and if EXEC_BACKEND the ShmemBackendArray).
4381
+ * These arrays include regular backends and autovac workers, but not special
4382
+ * children nor dead_end children. This allows the arrays to have a fixed
4383
+ * maximum size, to wit the same too-many-children limit enforced by
4384
+ * canAcceptConnections(). The exact value isn't too critical as long as
4385
+ * it's more than MaxBackends.
4386
+ */
4387
+ int
4388
+ MaxLivePostmasterChildren (void )
4389
+ {
4390
+ return 2 * MaxBackends ;
4391
+ }
4392
+
4393
+
4356
4394
#ifdef EXEC_BACKEND
4357
4395
4358
4396
/*
@@ -4364,6 +4402,7 @@ extern LWLock *LWLockArray;
4364
4402
extern slock_t * ProcStructLock ;
4365
4403
extern PROC_HDR * ProcGlobal ;
4366
4404
extern PGPROC * AuxiliaryProcs ;
4405
+ extern PMSignalData * PMSignalState ;
4367
4406
extern int pgStatSock ;
4368
4407
4369
4408
#ifndef WIN32
@@ -4395,6 +4434,7 @@ save_backend_variables(BackendParameters * param, Port *port,
4395
4434
memcpy (& param -> ListenSocket , & ListenSocket , sizeof (ListenSocket ));
4396
4435
4397
4436
param -> MyCancelKey = MyCancelKey ;
4437
+ param -> MyPMChildSlot = MyPMChildSlot ;
4398
4438
4399
4439
param -> UsedShmemSegID = UsedShmemSegID ;
4400
4440
param -> UsedShmemSegAddr = UsedShmemSegAddr ;
@@ -4407,6 +4447,7 @@ save_backend_variables(BackendParameters * param, Port *port,
4407
4447
param -> ProcStructLock = ProcStructLock ;
4408
4448
param -> ProcGlobal = ProcGlobal ;
4409
4449
param -> AuxiliaryProcs = AuxiliaryProcs ;
4450
+ param -> PMSignalState = PMSignalState ;
4410
4451
write_inheritable_socket (& param -> pgStatSock , pgStatSock , childPid );
4411
4452
4412
4453
param -> PostmasterPid = PostmasterPid ;
@@ -4601,6 +4642,7 @@ restore_backend_variables(BackendParameters * param, Port *port)
4601
4642
memcpy (& ListenSocket , & param -> ListenSocket , sizeof (ListenSocket ));
4602
4643
4603
4644
MyCancelKey = param -> MyCancelKey ;
4645
+ MyPMChildSlot = param -> MyPMChildSlot ;
4604
4646
4605
4647
UsedShmemSegID = param -> UsedShmemSegID ;
4606
4648
UsedShmemSegAddr = param -> UsedShmemSegAddr ;
@@ -4613,6 +4655,7 @@ restore_backend_variables(BackendParameters * param, Port *port)
4613
4655
ProcStructLock = param -> ProcStructLock ;
4614
4656
ProcGlobal = param -> ProcGlobal ;
4615
4657
AuxiliaryProcs = param -> AuxiliaryProcs ;
4658
+ PMSignalState = param -> PMSignalState ;
4616
4659
read_inheritable_socket (& pgStatSock , & param -> pgStatSock );
4617
4660
4618
4661
PostmasterPid = param -> PostmasterPid ;
@@ -4642,7 +4685,7 @@ restore_backend_variables(BackendParameters * param, Port *port)
4642
4685
Size
4643
4686
ShmemBackendArraySize (void )
4644
4687
{
4645
- return mul_size (NUM_BACKENDARRAY_ELEMS , sizeof (Backend ));
4688
+ return mul_size (MaxLivePostmasterChildren () , sizeof (Backend ));
4646
4689
}
4647
4690
4648
4691
void
@@ -4658,41 +4701,23 @@ ShmemBackendArrayAllocation(void)
4658
4701
static void
4659
4702
ShmemBackendArrayAdd (Backend * bn )
4660
4703
{
4661
- int i ;
4662
-
4663
- /* Find an empty slot */
4664
- for (i = 0 ; i < NUM_BACKENDARRAY_ELEMS ; i ++ )
4665
- {
4666
- if (ShmemBackendArray [i ].pid == 0 )
4667
- {
4668
- ShmemBackendArray [i ] = * bn ;
4669
- return ;
4670
- }
4671
- }
4704
+ /* The array slot corresponding to my PMChildSlot should be free */
4705
+ int i = bn -> child_slot - 1 ;
4672
4706
4673
- ereport ( FATAL ,
4674
- ( errmsg_internal ( "no free slots in shmem backend array" ))) ;
4707
+ Assert ( ShmemBackendArray [ i ]. pid == 0 );
4708
+ ShmemBackendArray [ i ] = * bn ;
4675
4709
}
4676
4710
4677
4711
static void
4678
- ShmemBackendArrayRemove (pid_t pid )
4712
+ ShmemBackendArrayRemove (Backend * bn )
4679
4713
{
4680
- int i ;
4681
-
4682
- for (i = 0 ; i < NUM_BACKENDARRAY_ELEMS ; i ++ )
4683
- {
4684
- if (ShmemBackendArray [i ].pid == pid )
4685
- {
4686
- /* Mark the slot as empty */
4687
- ShmemBackendArray [i ].pid = 0 ;
4688
- return ;
4689
- }
4690
- }
4714
+ int i = bn -> child_slot - 1 ;
4691
4715
4692
- ereport ( WARNING ,
4693
- ( errmsg_internal ( "could not find backend entry with pid %d" ,
4694
- ( int ) pid ))) ;
4716
+ Assert ( ShmemBackendArray [ i ]. pid == bn -> pid );
4717
+ /* Mark the slot as empty */
4718
+ ShmemBackendArray [ i ]. pid = 0 ;
4695
4719
}
4720
+
4696
4721
#endif /* EXEC_BACKEND */
4697
4722
4698
4723
0 commit comments