Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita78af04

Browse files
committed
Assign a child slot to every postmaster child process
Previously, only backends, autovacuum workers, and background workershad an entry in the PMChildFlags array. With this commit, allpostmaster child processes, including all the aux processes, have anentry. Dead-end backends still don't get an entry, though, and otherprocesses that don't touch shared memory will never mark theirPMChildFlags entry as active.We now maintain separate freelists for different kinds of childprocesses. That ensures that there are always slots available forautovacuum and background workers. Previously, pre-authenticationbackends could prevent autovacuum or background workers from startingup, by using up all the slots.The code to manage the slots in the postmaster process is in a newpmchild.c source file. Because postmaster.c is just so large.Assigning pmsignal slot numbers is now pmchild.c's responsibility.This replaces the PMChildInUse array in pmsignal.c.Some of the comments in postmaster.c still talked about the "statsprocess", but that was removed in commit5891c7a. Fix those whilewe're at it.Reviewed-by: Andres Freund <andres@anarazel.de>Discussion:https://www.postgresql.org/message-id/a102f15f-eac4-4ff2-af02-f9ff209ec66f@iki.fi
1 parentbb86141 commita78af04

File tree

15 files changed

+785
-594
lines changed

15 files changed

+785
-594
lines changed

‎src/backend/bootstrap/bootstrap.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include"miscadmin.h"
3232
#include"nodes/makefuncs.h"
3333
#include"pg_getopt.h"
34+
#include"postmaster/postmaster.h"
3435
#include"storage/bufpage.h"
3536
#include"storage/ipc.h"
3637
#include"storage/proc.h"
@@ -309,6 +310,13 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
309310

310311
InitializeMaxBackends();
311312

313+
/*
314+
* Even though bootstrapping runs in single-process mode, initialize
315+
* postmaster child slots array so that --check can detect running out of
316+
* shared memory or other resources if max_connections is set too high.
317+
*/
318+
InitPostmasterChildSlots();
319+
312320
InitializeFastPathLocks();
313321

314322
CreateSharedMemoryAndSemaphores();

‎src/backend/postmaster/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ OBJS = \
2222
interrupt.o\
2323
launch_backend.o\
2424
pgarch.o\
25+
pmchild.o\
2526
postmaster.o\
2627
startup.o\
2728
syslogger.o\

‎src/backend/postmaster/launch_backend.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ typedef struct
118118
boolquery_id_enabled;
119119
intmax_safe_fds;
120120
intMaxBackends;
121+
intnum_pmchild_slots;
121122
#ifdefWIN32
122123
HANDLEPostmasterHandle;
123124
HANDLEinitial_signal_pipe;
@@ -735,6 +736,7 @@ save_backend_variables(BackendParameters *param, ClientSocket *client_sock,
735736
param->max_safe_fds=max_safe_fds;
736737

737738
param->MaxBackends=MaxBackends;
739+
param->num_pmchild_slots=num_pmchild_slots;
738740

739741
#ifdefWIN32
740742
param->PostmasterHandle=PostmasterHandle;
@@ -994,6 +996,7 @@ restore_backend_variables(BackendParameters *param)
994996
max_safe_fds=param->max_safe_fds;
995997

996998
MaxBackends=param->MaxBackends;
999+
num_pmchild_slots=param->num_pmchild_slots;
9971000

9981001
#ifdefWIN32
9991002
PostmasterHandle=param->PostmasterHandle;

‎src/backend/postmaster/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ backend_sources += files(
1010
'interrupt.c',
1111
'launch_backend.c',
1212
'pgarch.c',
13+
'pmchild.c',
1314
'postmaster.c',
1415
'startup.c',
1516
'syslogger.c',

‎src/backend/postmaster/pmchild.c

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* pmchild.c
4+
* Functions for keeping track of postmaster child processes.
5+
*
6+
* Postmaster keeps track of all child processes so that when a process exits,
7+
* it knows what kind of a process it was and can clean up accordingly. Every
8+
* child process is allocated a PMChild struct from a fixed pool of structs.
9+
* The size of the pool is determined by various settings that configure how
10+
* many worker processes and backend connections are allowed, i.e.
11+
* autovacuum_max_workers, max_worker_processes, max_wal_senders, and
12+
* max_connections.
13+
*
14+
* Dead-end backends are handled slightly differently. There is no limit
15+
* on the number of dead-end backends, and they do not need unique IDs, so
16+
* their PMChild structs are allocated dynamically, not from a pool.
17+
*
18+
* The structures and functions in this file are private to the postmaster
19+
* process. But note that there is an array in shared memory, managed by
20+
* pmsignal.c, that mirrors this.
21+
*
22+
*
23+
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
24+
* Portions Copyright (c) 1994, Regents of the University of California
25+
*
26+
* IDENTIFICATION
27+
* src/backend/postmaster/pmchild.c
28+
*
29+
*-------------------------------------------------------------------------
30+
*/
31+
32+
#include"postgres.h"
33+
34+
#include"miscadmin.h"
35+
#include"postmaster/autovacuum.h"
36+
#include"postmaster/postmaster.h"
37+
#include"replication/walsender.h"
38+
#include"storage/pmsignal.h"
39+
#include"storage/proc.h"
40+
41+
/*
42+
* Freelists for different kinds of child processes. We maintain separate
43+
* pools for each, so that for example launching a lot of regular backends
44+
* cannot prevent autovacuum or an aux process from launching.
45+
*/
46+
typedefstructPMChildPool
47+
{
48+
intsize;/* number of PMChild slots reserved for this
49+
* kind of processes */
50+
intfirst_slotno;/* first slot belonging to this pool */
51+
dlist_headfreelist;/* currently unused PMChild entries */
52+
}PMChildPool;
53+
54+
staticPMChildPoolpmchild_pools[BACKEND_NUM_TYPES];
55+
NON_EXEC_STATICintnum_pmchild_slots=0;
56+
57+
/*
58+
* List of active child processes. This includes dead-end children.
59+
*/
60+
dlist_headActiveChildList;
61+
62+
/*
63+
* MaxLivePostmasterChildren
64+
*
65+
* This reports the number of postmaster child processes that can be active.
66+
* It includes all children except for dead-end children. This allows the
67+
* array in shared memory (PMChildFlags) to have a fixed maximum size.
68+
*/
69+
int
70+
MaxLivePostmasterChildren(void)
71+
{
72+
if (num_pmchild_slots==0)
73+
elog(ERROR,"PM child array not initialized yet");
74+
returnnum_pmchild_slots;
75+
}
76+
77+
/*
78+
* Initialize at postmaster startup
79+
*
80+
* Note: This is not called on crash restart. We rely on PMChild entries to
81+
* remain valid through the restart process. This is important because the
82+
* syslogger survives through the crash restart process, so we must not
83+
* invalidate its PMChild slot.
84+
*/
85+
void
86+
InitPostmasterChildSlots(void)
87+
{
88+
intslotno;
89+
PMChild*slots;
90+
91+
/*
92+
* We allow more connections here than we can have backends because some
93+
* might still be authenticating; they might fail auth, or some existing
94+
* backend might exit before the auth cycle is completed. The exact
95+
* MaxConnections limit is enforced when a new backend tries to join the
96+
* PGPROC array.
97+
*
98+
* WAL senders start out as regular backends, so they share the same pool.
99+
*/
100+
pmchild_pools[B_BACKEND].size=2* (MaxConnections+max_wal_senders);
101+
102+
pmchild_pools[B_AUTOVAC_WORKER].size=autovacuum_max_workers;
103+
pmchild_pools[B_BG_WORKER].size=max_worker_processes;
104+
105+
/*
106+
* There can be only one of each of these running at a time. They each
107+
* get their own pool of just one entry.
108+
*/
109+
pmchild_pools[B_AUTOVAC_LAUNCHER].size=1;
110+
pmchild_pools[B_SLOTSYNC_WORKER].size=1;
111+
pmchild_pools[B_ARCHIVER].size=1;
112+
pmchild_pools[B_BG_WRITER].size=1;
113+
pmchild_pools[B_CHECKPOINTER].size=1;
114+
pmchild_pools[B_STARTUP].size=1;
115+
pmchild_pools[B_WAL_RECEIVER].size=1;
116+
pmchild_pools[B_WAL_SUMMARIZER].size=1;
117+
pmchild_pools[B_WAL_WRITER].size=1;
118+
pmchild_pools[B_LOGGER].size=1;
119+
120+
/* The rest of the pmchild_pools are left at zero size */
121+
122+
/* Count the total number of slots */
123+
num_pmchild_slots=0;
124+
for (inti=0;i<BACKEND_NUM_TYPES;i++)
125+
num_pmchild_slots+=pmchild_pools[i].size;
126+
127+
/* Initialize them */
128+
slots=palloc(num_pmchild_slots*sizeof(PMChild));
129+
slotno=0;
130+
for (intbtype=0;btype<BACKEND_NUM_TYPES;btype++)
131+
{
132+
pmchild_pools[btype].first_slotno=slotno+1;
133+
dlist_init(&pmchild_pools[btype].freelist);
134+
135+
for (intj=0;j<pmchild_pools[btype].size;j++)
136+
{
137+
slots[slotno].pid=0;
138+
slots[slotno].child_slot=slotno+1;
139+
slots[slotno].bkend_type=B_INVALID;
140+
slots[slotno].rw=NULL;
141+
slots[slotno].bgworker_notify= false;
142+
dlist_push_tail(&pmchild_pools[btype].freelist,&slots[slotno].elem);
143+
slotno++;
144+
}
145+
}
146+
Assert(slotno==num_pmchild_slots);
147+
148+
/* Initialize other structures */
149+
dlist_init(&ActiveChildList);
150+
}
151+
152+
/*
153+
* Allocate a PMChild entry for a postmaster child process of given type.
154+
*
155+
* The entry is taken from the right pool for the type.
156+
*
157+
* pmchild->child_slot in the returned struct is unique among all active child
158+
* processes.
159+
*/
160+
PMChild*
161+
AssignPostmasterChildSlot(BackendTypebtype)
162+
{
163+
dlist_head*freelist;
164+
PMChild*pmchild;
165+
166+
if (pmchild_pools[btype].size==0)
167+
elog(ERROR,"cannot allocate a PMChild slot for backend type %d",btype);
168+
169+
freelist=&pmchild_pools[btype].freelist;
170+
if (dlist_is_empty(freelist))
171+
returnNULL;
172+
173+
pmchild=dlist_container(PMChild,elem,dlist_pop_head_node(freelist));
174+
pmchild->pid=0;
175+
pmchild->bkend_type=btype;
176+
pmchild->rw=NULL;
177+
pmchild->bgworker_notify= true;
178+
179+
/*
180+
* pmchild->child_slot for each entry was initialized when the array of
181+
* slots was allocated. Sanity check it.
182+
*/
183+
if (!(pmchild->child_slot >=pmchild_pools[btype].first_slotno&&
184+
pmchild->child_slot<pmchild_pools[btype].first_slotno+pmchild_pools[btype].size))
185+
{
186+
elog(ERROR,"pmchild freelist for backend type %d is corrupt",
187+
pmchild->bkend_type);
188+
}
189+
190+
dlist_push_head(&ActiveChildList,&pmchild->elem);
191+
192+
/* Update the status in the shared memory array */
193+
MarkPostmasterChildSlotAssigned(pmchild->child_slot);
194+
195+
elog(DEBUG2,"assigned pm child slot %d for %s",
196+
pmchild->child_slot,PostmasterChildName(btype));
197+
198+
returnpmchild;
199+
}
200+
201+
/*
202+
* Allocate a PMChild struct for a dead-end backend. Dead-end children are
203+
* not assigned a child_slot number. The struct is palloc'd; returns NULL if
204+
* out of memory.
205+
*/
206+
PMChild*
207+
AllocDeadEndChild(void)
208+
{
209+
PMChild*pmchild;
210+
211+
elog(DEBUG2,"allocating dead-end child");
212+
213+
pmchild= (PMChild*)palloc_extended(sizeof(PMChild),MCXT_ALLOC_NO_OOM);
214+
if (pmchild)
215+
{
216+
pmchild->pid=0;
217+
pmchild->child_slot=0;
218+
pmchild->bkend_type=B_DEAD_END_BACKEND;
219+
pmchild->rw=NULL;
220+
pmchild->bgworker_notify= false;
221+
222+
dlist_push_head(&ActiveChildList,&pmchild->elem);
223+
}
224+
225+
returnpmchild;
226+
}
227+
228+
/*
229+
* Release a PMChild slot, after the child process has exited.
230+
*
231+
* Returns true if the child detached cleanly from shared memory, false
232+
* otherwise (see MarkPostmasterChildSlotUnassigned).
233+
*/
234+
bool
235+
ReleasePostmasterChildSlot(PMChild*pmchild)
236+
{
237+
dlist_delete(&pmchild->elem);
238+
if (pmchild->bkend_type==B_DEAD_END_BACKEND)
239+
{
240+
elog(DEBUG2,"releasing dead-end backend");
241+
pfree(pmchild);
242+
return true;
243+
}
244+
else
245+
{
246+
PMChildPool*pool;
247+
248+
elog(DEBUG2,"releasing pm child slot %d",pmchild->child_slot);
249+
250+
/* WAL senders start out as regular backends, and share the pool */
251+
if (pmchild->bkend_type==B_WAL_SENDER)
252+
pool=&pmchild_pools[B_BACKEND];
253+
else
254+
pool=&pmchild_pools[pmchild->bkend_type];
255+
256+
/* sanity check that we return the entry to the right pool */
257+
if (!(pmchild->child_slot >=pool->first_slotno&&
258+
pmchild->child_slot<pool->first_slotno+pool->size))
259+
{
260+
elog(ERROR,"pmchild freelist for backend type %d is corrupt",
261+
pmchild->bkend_type);
262+
}
263+
264+
dlist_push_head(&pool->freelist,&pmchild->elem);
265+
returnMarkPostmasterChildSlotUnassigned(pmchild->child_slot);
266+
}
267+
}
268+
269+
/*
270+
* Find the PMChild entry of a running child process by PID.
271+
*/
272+
PMChild*
273+
FindPostmasterChildByPid(intpid)
274+
{
275+
dlist_iteriter;
276+
277+
dlist_foreach(iter,&ActiveChildList)
278+
{
279+
PMChild*bp=dlist_container(PMChild,elem,iter.cur);
280+
281+
if (bp->pid==pid)
282+
returnbp;
283+
}
284+
returnNULL;
285+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp