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

Commit001a573

Browse files
committed
Allow on-detach callbacks for dynamic shared memory segments.
Just as backends must clean up their shared memory state (releasinglwlocks, buffer pins, etc.) before exiting, they must also performany similar cleanups related to dynamic shared memory segments theyhave mapped before unmapping those segments. So add a mechanism toensure that.Existing on_shmem_exit hooks include both "user level" cleanup suchas transaction abort and removal of leftover temporary relations andalso "low level" cleanup that forcibly released leftover sharedmemory resources. On-detach callbacks should run after the firstgroup but before the second group, so create a new before_shmem_exitfunction for registering the early callbacks and keep on_shmem_exitfor the regular callbacks. (An earlier draft of this patch added anadditional argument to on_shmem_exit, but that had a much largerfootprint and probably a substantially higher risk of breaking thirdparty code for no real gain.)Patch by me, reviewed by KaiGai Kohei and Andres Freund.
1 parent613c6d2 commit001a573

File tree

8 files changed

+192
-46
lines changed

8 files changed

+192
-46
lines changed

‎src/backend/bootstrap/bootstrap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,8 @@ AuxiliaryProcessMain(int argc, char *argv[])
402402
/* finish setting up bufmgr.c */
403403
InitBufferPoolBackend();
404404

405-
/* register a shutdown callback for LWLock cleanup */
406-
on_shmem_exit(ShutdownAuxiliaryProcess,0);
405+
/* register abefore-shutdown callback for LWLock cleanup */
406+
before_shmem_exit(ShutdownAuxiliaryProcess,0);
407407
}
408408

409409
/*

‎src/backend/catalog/namespace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3681,7 +3681,7 @@ AtEOXact_Namespace(bool isCommit)
36813681
if (myTempNamespaceSubID!=InvalidSubTransactionId)
36823682
{
36833683
if (isCommit)
3684-
on_shmem_exit(RemoveTempRelationsCallback,0);
3684+
before_shmem_exit(RemoveTempRelationsCallback,0);
36853685
else
36863686
{
36873687
myTempNamespace=InvalidOid;

‎src/backend/commands/async.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,7 @@ Exec_ListenPreCommit(void)
921921
*/
922922
if (!unlistenExitRegistered)
923923
{
924-
on_shmem_exit(Async_UnlistenOnExit,0);
924+
before_shmem_exit(Async_UnlistenOnExit,0);
925925
unlistenExitRegistered= true;
926926
}
927927

‎src/backend/storage/ipc/dsm.c

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@
5858

5959
#defineINVALID_CONTROL_SLOT((uint32) -1)
6060

61+
/* Backend-local tracking for on-detach callbacks. */
62+
typedefstructdsm_segment_detach_callback
63+
{
64+
on_dsm_detach_callbackfunction;
65+
Datumarg;
66+
slist_nodenode;
67+
}dsm_segment_detach_callback;
68+
6169
/* Backend-local state for a dynamic shared memory segment. */
6270
structdsm_segment
6371
{
@@ -68,6 +76,7 @@ struct dsm_segment
6876
void*impl_private;/* Implementation-specific private data. */
6977
void*mapped_address;/* Mapping address, or NULL if unmapped. */
7078
Sizemapped_size;/* Size of our mapping. */
79+
slist_headon_detach;/* On-detach callbacks. */
7180
};
7281

7382
/* Shared-memory state for a dynamic shared memory segment. */
@@ -91,7 +100,6 @@ static void dsm_cleanup_for_mmap(void);
91100
staticbooldsm_read_state_file(dsm_handle*h);
92101
staticvoiddsm_write_state_file(dsm_handleh);
93102
staticvoiddsm_postmaster_shutdown(intcode,Datumarg);
94-
staticvoiddsm_backend_shutdown(intcode,Datumarg);
95103
staticdsm_segment*dsm_create_descriptor(void);
96104
staticbooldsm_control_segment_sane(dsm_control_header*control,
97105
Sizemapped_size);
@@ -556,9 +564,6 @@ dsm_backend_startup(void)
556564
}
557565
#endif
558566

559-
/* Arrange to detach segments on exit. */
560-
on_shmem_exit(dsm_backend_shutdown,0);
561-
562567
dsm_init_done= true;
563568
}
564569

@@ -718,8 +723,8 @@ dsm_attach(dsm_handle h)
718723
/*
719724
* At backend shutdown time, detach any segments that are still attached.
720725
*/
721-
staticvoid
722-
dsm_backend_shutdown(intcode,Datumarg)
726+
void
727+
dsm_backend_shutdown(void)
723728
{
724729
while (!dlist_is_empty(&dsm_segment_list))
725730
{
@@ -774,6 +779,27 @@ dsm_remap(dsm_segment *seg)
774779
void
775780
dsm_detach(dsm_segment*seg)
776781
{
782+
/*
783+
* Invoke registered callbacks. Just in case one of those callbacks
784+
* throws a further error that brings us back here, pop the callback
785+
* before invoking it, to avoid infinite error recursion.
786+
*/
787+
while (!slist_is_empty(&seg->on_detach))
788+
{
789+
slist_node*node;
790+
dsm_segment_detach_callback*cb;
791+
on_dsm_detach_callbackfunction;
792+
Datumarg;
793+
794+
node=slist_pop_head_node(&seg->on_detach);
795+
cb=slist_container(dsm_segment_detach_callback,node,node);
796+
function=cb->function;
797+
arg=cb->arg;
798+
pfree(cb);
799+
800+
function(seg,arg);
801+
}
802+
777803
/*
778804
* Try to remove the mapping, if one exists. Normally, there will be,
779805
* but maybe not, if we failed partway through a create or attach
@@ -915,6 +941,44 @@ dsm_segment_handle(dsm_segment *seg)
915941
returnseg->handle;
916942
}
917943

944+
/*
945+
* Register an on-detach callback for a dynamic shared memory segment.
946+
*/
947+
void
948+
on_dsm_detach(dsm_segment*seg,on_dsm_detach_callbackfunction,Datumarg)
949+
{
950+
dsm_segment_detach_callback*cb;
951+
952+
cb=MemoryContextAlloc(TopMemoryContext,
953+
sizeof(dsm_segment_detach_callback));
954+
cb->function=function;
955+
cb->arg=arg;
956+
slist_push_head(&seg->on_detach,&cb->node);
957+
}
958+
959+
/*
960+
* Unregister an on-detach callback for a dynamic shared memory segment.
961+
*/
962+
void
963+
cancel_on_dsm_detach(dsm_segment*seg,on_dsm_detach_callbackfunction,
964+
Datumarg)
965+
{
966+
slist_mutable_iteriter;
967+
968+
slist_foreach_modify(iter,&seg->on_detach)
969+
{
970+
dsm_segment_detach_callback*cb;
971+
972+
cb=slist_container(dsm_segment_detach_callback,node,iter.cur);
973+
if (cb->function==function&&cb->arg==arg)
974+
{
975+
slist_delete_current(&iter);
976+
pfree(cb);
977+
break;
978+
}
979+
}
980+
}
981+
918982
/*
919983
* Create a segment descriptor.
920984
*/
@@ -937,6 +1001,8 @@ dsm_create_descriptor(void)
9371001
seg->resowner=CurrentResourceOwner;
9381002
ResourceOwnerRememberDSM(CurrentResourceOwner,seg);
9391003

1004+
slist_init(&seg->on_detach);
1005+
9401006
returnseg;
9411007
}
9421008

‎src/backend/storage/ipc/ipc.c

Lines changed: 95 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#ifdefPROFILE_PID_DIR
2828
#include"postmaster/autovacuum.h"
2929
#endif
30+
#include"storage/dsm.h"
3031
#include"storage/ipc.h"
3132
#include"tcop/tcopprot.h"
3233

@@ -64,14 +65,19 @@ static void proc_exit_prepare(int code);
6465

6566
#defineMAX_ON_EXITS 20
6667

67-
staticstructONEXIT
68+
structONEXIT
6869
{
6970
pg_on_exit_callbackfunction;
7071
Datumarg;
71-
}on_proc_exit_list[MAX_ON_EXITS],on_shmem_exit_list[MAX_ON_EXITS];
72+
};
73+
74+
staticstructONEXITon_proc_exit_list[MAX_ON_EXITS];
75+
staticstructONEXITon_shmem_exit_list[MAX_ON_EXITS];
76+
staticstructONEXITbefore_shmem_exit_list[MAX_ON_EXITS];
7277

7378
staticinton_proc_exit_index,
74-
on_shmem_exit_index;
79+
on_shmem_exit_index,
80+
before_shmem_exit_index;
7581

7682

7783
/* ----------------------------------------------------------------
@@ -202,25 +208,60 @@ proc_exit_prepare(int code)
202208
/* ------------------
203209
* Run all of the on_shmem_exit routines --- but don't actually exit.
204210
* This is used by the postmaster to re-initialize shared memory and
205-
* semaphores after a backend dies horribly.
211+
* semaphores after a backend dies horribly. As with proc_exit(), we
212+
* remove each callback from the list before calling it, to avoid
213+
* infinite loop in case of error.
206214
* ------------------
207215
*/
208216
void
209217
shmem_exit(intcode)
210218
{
211-
elog(DEBUG3,"shmem_exit(%d): %d callbacks to make",
212-
code,on_shmem_exit_index);
219+
/*
220+
* Call before_shmem_exit callbacks.
221+
*
222+
* These should be things that need most of the system to still be
223+
* up and working, such as cleanup of temp relations, which requires
224+
* catalog access; or things that need to be completed because later
225+
* cleanup steps depend on them, such as releasing lwlocks.
226+
*/
227+
elog(DEBUG3,"shmem_exit(%d): %d before_shmem_exit callbacks to make",
228+
code,before_shmem_exit_index);
229+
while (--before_shmem_exit_index >=0)
230+
(*before_shmem_exit_list[before_shmem_exit_index].function) (code,
231+
before_shmem_exit_list[before_shmem_exit_index].arg);
232+
before_shmem_exit_index=0;
213233

214234
/*
215-
* call all the registered callbacks.
235+
* Call dynamic shared memory callbacks.
236+
*
237+
* These serve the same purpose as late callbacks, but for dynamic shared
238+
* memory segments rather than the main shared memory segment.
239+
* dsm_backend_shutdown() has the same kind of progressive logic we use
240+
* for the main shared memory segment; namely, it unregisters each
241+
* callback before invoking it, so that we don't get stuck in an infinite
242+
* loop if one of those callbacks itself throws an ERROR or FATAL.
243+
*
244+
* Note that explicitly calling this function here is quite different
245+
* from registering it as an on_shmem_exit callback for precisely this
246+
* reason: if one dynamic shared memory callback errors out, the remaining
247+
* callbacks will still be invoked. Thus, hard-coding this call puts it
248+
* equal footing with callbacks for the main shared memory segment.
249+
*/
250+
dsm_backend_shutdown();
251+
252+
/*
253+
* Call on_shmem_exit callbacks.
216254
*
217-
* As with proc_exit(), we remove each callback from the list before
218-
* calling it, to avoid infinite loop in case of error.
255+
* These are generally releasing low-level shared memory resources. In
256+
* some cases, this is a backstop against the possibility that the early
257+
* callbacks might themselves fail, leading to re-entry to this routine;
258+
* in other cases, it's cleanup that only happens at process exit.
219259
*/
260+
elog(DEBUG3,"shmem_exit(%d): %d on_shmem_exit callbacks to make",
261+
code,on_shmem_exit_index);
220262
while (--on_shmem_exit_index >=0)
221263
(*on_shmem_exit_list[on_shmem_exit_index].function) (code,
222-
on_shmem_exit_list[on_shmem_exit_index].arg);
223-
264+
on_shmem_exit_list[on_shmem_exit_index].arg);
224265
on_shmem_exit_index=0;
225266
}
226267

@@ -269,11 +310,40 @@ on_proc_exit(pg_on_exit_callback function, Datum arg)
269310
}
270311
}
271312

313+
/* ----------------------------------------------------------------
314+
*before_shmem_exit
315+
*
316+
*Register early callback to perform user-level cleanup,
317+
*e.g. transaction abort, before we begin shutting down
318+
*low-level subsystems.
319+
* ----------------------------------------------------------------
320+
*/
321+
void
322+
before_shmem_exit(pg_on_exit_callbackfunction,Datumarg)
323+
{
324+
if (before_shmem_exit_index >=MAX_ON_EXITS)
325+
ereport(FATAL,
326+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
327+
errmsg_internal("out of before_shmem_exit slots")));
328+
329+
before_shmem_exit_list[before_shmem_exit_index].function=function;
330+
before_shmem_exit_list[before_shmem_exit_index].arg=arg;
331+
332+
++before_shmem_exit_index;
333+
334+
if (!atexit_callback_setup)
335+
{
336+
atexit(atexit_callback);
337+
atexit_callback_setup= true;
338+
}
339+
}
340+
272341
/* ----------------------------------------------------------------
273342
*on_shmem_exit
274343
*
275-
*this function adds a callback function to the list of
276-
*functions invoked by shmem_exit().-cim 2/6/90
344+
*Register ordinary callback to perform low-level shutdown
345+
*(e.g. releasing our PGPROC); run after before_shmem_exit
346+
*callbacks and before on_proc_exit callbacks.
277347
* ----------------------------------------------------------------
278348
*/
279349
void
@@ -297,21 +367,22 @@ on_shmem_exit(pg_on_exit_callback function, Datum arg)
297367
}
298368

299369
/* ----------------------------------------------------------------
300-
*cancel_shmem_exit
370+
*cancel_before_shmem_exit
301371
*
302-
*this function removesan entry, if present, from the list of
303-
*functions to be invoked by shmem_exit(). For simplicity,
304-
*only the latest entry can beremoved. (We could work harder
305-
*but there is no need forcurrent uses.)
372+
*this function removesa previously-registed before_shmem_exit
373+
*callback. For simplicity, only the latest entry can be
374+
*removed. (We could work harder but there is no need for
375+
*current uses.)
306376
* ----------------------------------------------------------------
307377
*/
308378
void
309-
cancel_shmem_exit(pg_on_exit_callbackfunction,Datumarg)
379+
cancel_before_shmem_exit(pg_on_exit_callbackfunction,Datumarg)
310380
{
311-
if (on_shmem_exit_index>0&&
312-
on_shmem_exit_list[on_shmem_exit_index-1].function==function&&
313-
on_shmem_exit_list[on_shmem_exit_index-1].arg==arg)
314-
--on_shmem_exit_index;
381+
if (before_shmem_exit_index>0&&
382+
before_shmem_exit_list[before_shmem_exit_index-1].function
383+
==function&&
384+
before_shmem_exit_list[before_shmem_exit_index-1].arg==arg)
385+
--before_shmem_exit_index;
315386
}
316387

317388
/* ----------------------------------------------------------------
@@ -326,6 +397,7 @@ cancel_shmem_exit(pg_on_exit_callback function, Datum arg)
326397
void
327398
on_exit_reset(void)
328399
{
400+
before_shmem_exit_index=0;
329401
on_shmem_exit_index=0;
330402
on_proc_exit_index=0;
331403
}

‎src/backend/utils/init/postinit.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -587,15 +587,14 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
587587
RelationCacheInitializePhase2();
588588

589589
/*
590-
* Set up process-exit callback to do pre-shutdown cleanup. This has to
591-
* be after we've initialized all the low-level modules like the buffer
592-
* manager, because during shutdown this has to run before the low-level
593-
* modules start to close down. On the other hand, we want it in place
594-
* before we begin our first transaction --- if we fail during the
595-
* initialization transaction, as is entirely possible, we need the
596-
* AbortTransaction call to clean up.
590+
* Set up process-exit callback to do pre-shutdown cleanup. This is the
591+
* first before_shmem_exit callback we register; thus, this will be the
592+
* last thing we do before low-level modules like the buffer manager begin
593+
* to close down. We need to have this in place before we begin our first
594+
* transaction --- if we fail during the initialization transaction, as is
595+
* entirely possible, we need the AbortTransaction call to clean up.
597596
*/
598-
on_shmem_exit(ShutdownPostgres,0);
597+
before_shmem_exit(ShutdownPostgres,0);
599598

600599
/* The autovacuum launcher is done here */
601600
if (IsAutoVacuumLauncherProcess())

‎src/include/storage/dsm.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717

1818
typedefstructdsm_segmentdsm_segment;
1919

20-
/*Initialization function. */
20+
/*Startup and shutdown functions. */
2121
externvoiddsm_postmaster_startup(void);
22+
externvoiddsm_backend_shutdown(void);
2223

2324
/* Functions that create, update, or remove mappings. */
2425
externdsm_segment*dsm_create(Sizesize);
@@ -36,4 +37,11 @@ extern void *dsm_segment_address(dsm_segment *seg);
3637
externSizedsm_segment_map_length(dsm_segment*seg);
3738
externdsm_handledsm_segment_handle(dsm_segment*seg);
3839

40+
/* Cleanup hooks. */
41+
typedefvoid (*on_dsm_detach_callback) (dsm_segment*,Datumarg);
42+
externvoidon_dsm_detach(dsm_segment*seg,
43+
on_dsm_detach_callbackfunction,Datumarg);
44+
externvoidcancel_on_dsm_detach(dsm_segment*seg,
45+
on_dsm_detach_callbackfunction,Datumarg);
46+
3947
#endif/* DSM_H */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp