From 1f8e1a2a1e9c35e70a68b29bebeddf8cc67304c1 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Mon, 13 Jul 2020 13:32:47 +1200 Subject: [PATCH v5 1/7] Use a long lived WaitEventSet for WaitLatch(). Create LatchWaitSet at backend startup time, and use it to implement WaitLatch(). This avoids repeated epoll/kqueue set-up and tear-down system calls, and makes sure we don't run into EMFILE later due to lack of file descriptors. Reorder SubPostmasterMain() slightly so that we restore the postmaster pipe and Windows signal before we reach InitPostmasterChild(), to make this work in EXEC_BACKEND builds. Reviewed-by: Kyotaro Horiguchi Discussion: https://postgr.es/m/CA%2BhUKGJAC4Oqao%3DqforhNey20J8CiG2R%3DoBPqvfR0vOJrFysGw%40mail.gmail.com --- src/backend/postmaster/postmaster.c | 24 ++++++------- src/backend/storage/ipc/latch.c | 55 ++++++++++++++++++++++++++--- src/backend/utils/init/miscinit.c | 2 ++ src/include/storage/latch.h | 1 + 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index dec02586c7..fc5ba11fb8 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -4896,9 +4896,6 @@ SubPostmasterMain(int argc, char *argv[]) IsPostmasterEnvironment = true; whereToSendOutput = DestNone; - /* Setup as postmaster child */ - InitPostmasterChild(); - /* Setup essential subsystems (to ensure elog() behaves sanely) */ InitializeGUCOptions(); @@ -4913,6 +4910,18 @@ SubPostmasterMain(int argc, char *argv[]) /* Close the postmaster's sockets (as soon as we know them) */ ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0); + /* + * Start our win32 signal implementation. This has to be done after we + * read the backend variables, because we need to pick up the signal pipe + * from the parent process. + */ +#ifdef WIN32 + pgwin32_signal_initialize(); +#endif + + /* Setup as postmaster child */ + InitPostmasterChild(); + /* * Set up memory area for GSS information. Mirrors the code in ConnCreate * for the non-exec case. @@ -4956,15 +4965,6 @@ SubPostmasterMain(int argc, char *argv[]) if (strcmp(argv[1], "--forkavworker") == 0) AutovacuumWorkerIAm(); - /* - * Start our win32 signal implementation. This has to be done after we - * read the backend variables, because we need to pick up the signal pipe - * from the parent process. - */ -#ifdef WIN32 - pgwin32_signal_initialize(); -#endif - /* In EXEC_BACKEND case we will not have inherited these settings */ pqinitmask(); PG_SETMASK(&BlockSig); diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index 91fa4b619b..fd4716ffaa 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -56,6 +56,7 @@ #include "storage/latch.h" #include "storage/pmsignal.h" #include "storage/shmem.h" +#include "utils/memutils.h" /* * Select the fd readiness primitive to use. Normally the "most modern" @@ -129,6 +130,11 @@ struct WaitEventSet #endif }; +/* A common WaitEventSet used to implement WatchLatch() */ +static WaitEventSet *LatchWaitSet; + +#define LatchWaitSetLatchPos 0 + #ifndef WIN32 /* Are we currently in WaitLatch? The signal handler would like to know. */ static volatile sig_atomic_t waiting = false; @@ -242,6 +248,24 @@ InitializeLatchSupport(void) #endif } +void +InitializeLatchWaitSet(void) +{ + int latch_pos PG_USED_FOR_ASSERTS_ONLY; + + Assert(LatchWaitSet == NULL); + + /* Set up the WaitEventSet used by WaitLatch(). */ + LatchWaitSet = CreateWaitEventSet(TopMemoryContext, 2); + latch_pos = AddWaitEventToSet(LatchWaitSet, WL_LATCH_SET, PGINVALID_SOCKET, + MyLatch, NULL); + if (IsUnderPostmaster) + AddWaitEventToSet(LatchWaitSet, WL_EXIT_ON_PM_DEATH, + PGINVALID_SOCKET, NULL, NULL); + + Assert(latch_pos == LatchWaitSetLatchPos); +} + /* * Initialize a process-local latch. */ @@ -365,8 +389,31 @@ int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info) { - return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout, - wait_event_info); + WaitEvent event; + + /* Postmaster-managed callers must handle postmaster death somehow. */ + Assert(!IsUnderPostmaster || + (wakeEvents & WL_EXIT_ON_PM_DEATH) || + (wakeEvents & WL_POSTMASTER_DEATH)); + + /* + * Some callers may have a latch other than MyLatch, or no latch at all, or + * want to handle postmaster death differently. It's cheap to assign + * those, so just do it every time. + */ + if (!(wakeEvents & WL_LATCH_SET)) + latch = NULL; + ModifyWaitEvent(LatchWaitSet, LatchWaitSetLatchPos, WL_LATCH_SET, latch); + LatchWaitSet->exit_on_postmaster_death = + ((wakeEvents & WL_EXIT_ON_PM_DEATH) != 0); + + if (WaitEventSetWait(LatchWaitSet, + (wakeEvents & WL_TIMEOUT) ? timeout : -1, + &event, 1, + wait_event_info) == 0) + return WL_TIMEOUT; + else + return event.events; } /* @@ -830,7 +877,8 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch, /* * Change the event mask and, in the WL_LATCH_SET case, the latch associated - * with the WaitEvent. + * with the WaitEvent. The latch may be changed to NULL to disable the latch + * temporarily, and then set back to a latch later. * * 'pos' is the id returned by AddWaitEventToSet. */ @@ -862,7 +910,6 @@ ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch) if (event->events & WL_LATCH_SET && events != event->events) { - /* we could allow to disable latch events for a while */ elog(ERROR, "cannot modify latch event"); } diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index cca9704d2d..cf8f9579c3 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -120,6 +120,7 @@ InitPostmasterChild(void) InitializeLatchSupport(); MyLatch = &LocalLatchData; InitLatch(MyLatch); + InitializeLatchWaitSet(); /* * If possible, make this process a group leader, so that the postmaster @@ -152,6 +153,7 @@ InitStandaloneProcess(const char *argv0) InitializeLatchSupport(); MyLatch = &LocalLatchData; InitLatch(MyLatch); + InitializeLatchWaitSet(); /* Compute paths, no postmaster to inherit from */ if (my_exec_path[0] == '\0') diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 46ae56cae3..7c742021fb 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -176,6 +176,7 @@ extern int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info); extern int WaitLatchOrSocket(Latch *latch, int wakeEvents, pgsocket sock, long timeout, uint32 wait_event_info); +extern void InitializeLatchWaitSet(void); /* * Unix implementation uses SIGUSR1 for inter-process signaling. -- 2.20.1