mirror of https://github.com/postgres/postgres
Refactor postmaster child process launching
Introduce new postmaster_child_launch() function that deals with the differences in EXEC_BACKEND mode. Refactor the mechanism of passing information from the parent to child process. Instead of using different command-line arguments when launching the child process in EXEC_BACKEND mode, pass a variable-length blob of startup data along with all the global variables. The contents of that blob depend on the kind of child process being launched. In !EXEC_BACKEND mode, we use the same blob, but it's simply inherited from the parent to child process. Reviewed-by: Tristan Partin, Andres Freund Discussion: https://www.postgresql.org/message-id/7a59b073-5b5b-151e-7ed3-8b01ff7ce9ef@iki.fi
This commit is contained in:
parent
f1baed18bc
commit
aafc05de1b
|
@ -85,7 +85,6 @@
|
|||
#include "nodes/makefuncs.h"
|
||||
#include "pgstat.h"
|
||||
#include "postmaster/autovacuum.h"
|
||||
#include "postmaster/fork_process.h"
|
||||
#include "postmaster/interrupt.h"
|
||||
#include "postmaster/postmaster.h"
|
||||
#include "storage/bufmgr.h"
|
||||
|
@ -311,13 +310,6 @@ static WorkerInfo MyWorkerInfo = NULL;
|
|||
/* PID of launcher, valid only in worker while shutting down */
|
||||
int AutovacuumLauncherPid = 0;
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
static pid_t avlauncher_forkexec(void);
|
||||
static pid_t avworker_forkexec(void);
|
||||
#endif
|
||||
NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
|
||||
static Oid do_start_worker(void);
|
||||
static void HandleAutoVacLauncherInterrupts(void);
|
||||
static void AutoVacLauncherShutdown(void) pg_attribute_noreturn();
|
||||
|
@ -361,76 +353,23 @@ static void avl_sigusr2_handler(SIGNAL_ARGS);
|
|||
* AUTOVACUUM LAUNCHER CODE
|
||||
********************************************************************/
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
/*
|
||||
* forkexec routine for the autovacuum launcher process.
|
||||
*
|
||||
* Format up the arglist, then fork and exec.
|
||||
* Main entry point for the autovacuum launcher process.
|
||||
*/
|
||||
static pid_t
|
||||
avlauncher_forkexec(void)
|
||||
{
|
||||
char *av[10];
|
||||
int ac = 0;
|
||||
|
||||
av[ac++] = "postgres";
|
||||
av[ac++] = "--forkavlauncher";
|
||||
av[ac++] = NULL; /* filled in by postmaster_forkexec */
|
||||
av[ac] = NULL;
|
||||
|
||||
Assert(ac < lengthof(av));
|
||||
|
||||
return postmaster_forkexec(ac, av);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Main entry point for autovacuum launcher process, to be called from the
|
||||
* postmaster.
|
||||
*/
|
||||
int
|
||||
StartAutoVacLauncher(void)
|
||||
{
|
||||
pid_t AutoVacPID;
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
switch ((AutoVacPID = avlauncher_forkexec()))
|
||||
#else
|
||||
switch ((AutoVacPID = fork_process()))
|
||||
#endif
|
||||
{
|
||||
case -1:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork autovacuum launcher process: %m")));
|
||||
return 0;
|
||||
|
||||
#ifndef EXEC_BACKEND
|
||||
case 0:
|
||||
/* in postmaster child ... */
|
||||
InitPostmasterChild();
|
||||
|
||||
/* Close the postmaster's sockets */
|
||||
ClosePostmasterPorts(false);
|
||||
|
||||
AutoVacLauncherMain(0, NULL);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (int) AutoVacPID;
|
||||
}
|
||||
|
||||
/* shouldn't get here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main loop for the autovacuum launcher process.
|
||||
*/
|
||||
NON_EXEC_STATIC void
|
||||
AutoVacLauncherMain(int argc, char *argv[])
|
||||
void
|
||||
AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
/* Release postmaster's working memory context */
|
||||
if (PostmasterContext)
|
||||
{
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
PostmasterContext = NULL;
|
||||
}
|
||||
|
||||
MyBackendType = B_AUTOVAC_LAUNCHER;
|
||||
init_ps_display(NULL);
|
||||
|
||||
|
@ -1412,78 +1351,24 @@ avl_sigusr2_handler(SIGNAL_ARGS)
|
|||
* AUTOVACUUM WORKER CODE
|
||||
********************************************************************/
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
/*
|
||||
* forkexec routines for the autovacuum worker.
|
||||
*
|
||||
* Format up the arglist, then fork and exec.
|
||||
* Main entry point for autovacuum worker processes.
|
||||
*/
|
||||
static pid_t
|
||||
avworker_forkexec(void)
|
||||
{
|
||||
char *av[10];
|
||||
int ac = 0;
|
||||
|
||||
av[ac++] = "postgres";
|
||||
av[ac++] = "--forkavworker";
|
||||
av[ac++] = NULL; /* filled in by postmaster_forkexec */
|
||||
av[ac] = NULL;
|
||||
|
||||
Assert(ac < lengthof(av));
|
||||
|
||||
return postmaster_forkexec(ac, av);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Main entry point for autovacuum worker process.
|
||||
*
|
||||
* This code is heavily based on pgarch.c, q.v.
|
||||
*/
|
||||
int
|
||||
StartAutoVacWorker(void)
|
||||
{
|
||||
pid_t worker_pid;
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
switch ((worker_pid = avworker_forkexec()))
|
||||
#else
|
||||
switch ((worker_pid = fork_process()))
|
||||
#endif
|
||||
{
|
||||
case -1:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork autovacuum worker process: %m")));
|
||||
return 0;
|
||||
|
||||
#ifndef EXEC_BACKEND
|
||||
case 0:
|
||||
/* in postmaster child ... */
|
||||
InitPostmasterChild();
|
||||
|
||||
/* Close the postmaster's sockets */
|
||||
ClosePostmasterPorts(false);
|
||||
|
||||
AutoVacWorkerMain(0, NULL);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (int) worker_pid;
|
||||
}
|
||||
|
||||
/* shouldn't get here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* AutoVacWorkerMain
|
||||
*/
|
||||
NON_EXEC_STATIC void
|
||||
AutoVacWorkerMain(int argc, char *argv[])
|
||||
void
|
||||
AutoVacWorkerMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
Oid dbid;
|
||||
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
/* Release postmaster's working memory context */
|
||||
if (PostmasterContext)
|
||||
{
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
PostmasterContext = NULL;
|
||||
}
|
||||
|
||||
MyBackendType = B_AUTOVAC_WORKER;
|
||||
init_ps_display(NULL);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "storage/ipc.h"
|
||||
#include "storage/proc.h"
|
||||
#include "storage/procsignal.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/ps_status.h"
|
||||
|
||||
|
||||
|
@ -34,19 +35,22 @@ static void ShutdownAuxiliaryProcess(int code, Datum arg);
|
|||
|
||||
|
||||
/*
|
||||
* AuxiliaryProcessMain
|
||||
* AuxiliaryProcessMainCommon
|
||||
*
|
||||
* The main entry point for auxiliary processes, such as the bgwriter,
|
||||
* walwriter, walreceiver, bootstrapper and the shared memory checker code.
|
||||
*
|
||||
* This code is here just because of historical reasons.
|
||||
* Common initialization code for auxiliary processes, such as the bgwriter,
|
||||
* walwriter, walreceiver, and the startup process.
|
||||
*/
|
||||
void
|
||||
AuxiliaryProcessMain(BackendType auxtype)
|
||||
AuxiliaryProcessMainCommon(void)
|
||||
{
|
||||
Assert(IsUnderPostmaster);
|
||||
|
||||
MyBackendType = auxtype;
|
||||
/* Release postmaster's working memory context */
|
||||
if (PostmasterContext)
|
||||
{
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
PostmasterContext = NULL;
|
||||
}
|
||||
|
||||
init_ps_display(NULL);
|
||||
|
||||
|
@ -84,41 +88,6 @@ AuxiliaryProcessMain(BackendType auxtype)
|
|||
before_shmem_exit(ShutdownAuxiliaryProcess, 0);
|
||||
|
||||
SetProcessingMode(NormalProcessing);
|
||||
|
||||
switch (MyBackendType)
|
||||
{
|
||||
case B_STARTUP:
|
||||
StartupProcessMain();
|
||||
proc_exit(1);
|
||||
|
||||
case B_ARCHIVER:
|
||||
PgArchiverMain();
|
||||
proc_exit(1);
|
||||
|
||||
case B_BG_WRITER:
|
||||
BackgroundWriterMain();
|
||||
proc_exit(1);
|
||||
|
||||
case B_CHECKPOINTER:
|
||||
CheckpointerMain();
|
||||
proc_exit(1);
|
||||
|
||||
case B_WAL_WRITER:
|
||||
WalWriterMain();
|
||||
proc_exit(1);
|
||||
|
||||
case B_WAL_RECEIVER:
|
||||
WalReceiverMain();
|
||||
proc_exit(1);
|
||||
|
||||
case B_WAL_SUMMARIZER:
|
||||
WalSummarizerMain();
|
||||
proc_exit(1);
|
||||
|
||||
default:
|
||||
elog(PANIC, "unrecognized process type: %d", (int) MyBackendType);
|
||||
proc_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -720,15 +720,29 @@ bgworker_die(SIGNAL_ARGS)
|
|||
* Main entry point for background worker processes.
|
||||
*/
|
||||
void
|
||||
BackgroundWorkerMain(void)
|
||||
BackgroundWorkerMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
BackgroundWorker *worker = MyBgworkerEntry;
|
||||
BackgroundWorker *worker;
|
||||
bgworker_main_type entrypt;
|
||||
|
||||
if (worker == NULL)
|
||||
if (startup_data == NULL)
|
||||
elog(FATAL, "unable to find bgworker entry");
|
||||
Assert(startup_data_len == sizeof(BackgroundWorker));
|
||||
worker = MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker));
|
||||
memcpy(worker, startup_data, sizeof(BackgroundWorker));
|
||||
|
||||
/*
|
||||
* Now that we're done reading the startup data, release postmaster's
|
||||
* working memory context.
|
||||
*/
|
||||
if (PostmasterContext)
|
||||
{
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
PostmasterContext = NULL;
|
||||
}
|
||||
|
||||
MyBgworkerEntry = worker;
|
||||
MyBackendType = B_BG_WORKER;
|
||||
init_ps_display(worker->bgw_name);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "libpq/pqsignal.h"
|
||||
#include "miscadmin.h"
|
||||
#include "pgstat.h"
|
||||
#include "postmaster/auxprocess.h"
|
||||
#include "postmaster/bgwriter.h"
|
||||
#include "postmaster/interrupt.h"
|
||||
#include "storage/buf_internals.h"
|
||||
|
@ -83,13 +84,18 @@ static XLogRecPtr last_snapshot_lsn = InvalidXLogRecPtr;
|
|||
* basic execution environment, but not enabled signals yet.
|
||||
*/
|
||||
void
|
||||
BackgroundWriterMain(void)
|
||||
BackgroundWriterMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
MemoryContext bgwriter_context;
|
||||
bool prev_hibernate;
|
||||
WritebackContext wb_context;
|
||||
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
MyBackendType = B_BG_WRITER;
|
||||
AuxiliaryProcessMainCommon();
|
||||
|
||||
/*
|
||||
* Properly accept or ignore signals that might be sent to us.
|
||||
*/
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "libpq/pqsignal.h"
|
||||
#include "miscadmin.h"
|
||||
#include "pgstat.h"
|
||||
#include "postmaster/auxprocess.h"
|
||||
#include "postmaster/bgwriter.h"
|
||||
#include "postmaster/interrupt.h"
|
||||
#include "replication/syncrep.h"
|
||||
|
@ -169,11 +170,16 @@ static void ReqCheckpointHandler(SIGNAL_ARGS);
|
|||
* basic execution environment, but not enabled signals yet.
|
||||
*/
|
||||
void
|
||||
CheckpointerMain(void)
|
||||
CheckpointerMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
MemoryContext checkpointer_context;
|
||||
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
MyBackendType = B_CHECKPOINTER;
|
||||
AuxiliaryProcessMainCommon();
|
||||
|
||||
CheckpointerShmem->checkpointer_pid = MyProcPid;
|
||||
|
||||
/*
|
||||
|
|
|
@ -49,7 +49,9 @@
|
|||
#include "postmaster/postmaster.h"
|
||||
#include "postmaster/startup.h"
|
||||
#include "postmaster/syslogger.h"
|
||||
#include "postmaster/walsummarizer.h"
|
||||
#include "postmaster/walwriter.h"
|
||||
#include "replication/slotsync.h"
|
||||
#include "replication/walreceiver.h"
|
||||
#include "storage/fd.h"
|
||||
#include "storage/ipc.h"
|
||||
|
@ -89,13 +91,6 @@ typedef int InheritableSocket;
|
|||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool has_client_sock;
|
||||
ClientSocket client_sock;
|
||||
InheritableSocket inh_sock;
|
||||
|
||||
bool has_bgworker;
|
||||
BackgroundWorker bgworker;
|
||||
|
||||
char DataDir[MAXPGPATH];
|
||||
int32 MyCancelKey;
|
||||
int MyPMChildSlot;
|
||||
|
@ -138,22 +133,144 @@ typedef struct
|
|||
#endif
|
||||
char my_exec_path[MAXPGPATH];
|
||||
char pkglib_path[MAXPGPATH];
|
||||
|
||||
/*
|
||||
* These are only used by backend processes, but are here because passing
|
||||
* a socket needs some special handling on Windows. 'client_sock' is an
|
||||
* explicit argument to postmaster_child_launch, but is stored in
|
||||
* MyClientSocket in the child process.
|
||||
*/
|
||||
ClientSocket client_sock;
|
||||
InheritableSocket inh_sock;
|
||||
|
||||
/*
|
||||
* Extra startup data, content depends on the child process.
|
||||
*/
|
||||
size_t startup_data_len;
|
||||
char startup_data[FLEXIBLE_ARRAY_MEMBER];
|
||||
} BackendParameters;
|
||||
|
||||
#define SizeOfBackendParameters(startup_data_len) (offsetof(BackendParameters, startup_data) + startup_data_len)
|
||||
|
||||
void read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker);
|
||||
static void restore_backend_variables(BackendParameters *param, ClientSocket **client_sock, BackgroundWorker **worker);
|
||||
static void read_backend_variables(char *id, char **startup_data, size_t *startup_data_len);
|
||||
static void restore_backend_variables(BackendParameters *param);
|
||||
|
||||
#ifndef WIN32
|
||||
static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker);
|
||||
#else
|
||||
static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker,
|
||||
HANDLE childProcess, pid_t childPid);
|
||||
static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock,
|
||||
#ifdef WIN32
|
||||
HANDLE childProcess, pid_t childPid,
|
||||
#endif
|
||||
char *startup_data, size_t startup_data_len);
|
||||
|
||||
pid_t internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker);
|
||||
static pid_t internal_forkexec(const char *child_kind, char *startup_data, size_t startup_data_len, ClientSocket *client_sock);
|
||||
|
||||
#endif /* EXEC_BACKEND */
|
||||
|
||||
/*
|
||||
* Information needed to launch different kinds of child processes.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
void (*main_fn) (char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
bool shmem_attach;
|
||||
} child_process_kind;
|
||||
|
||||
child_process_kind child_process_kinds[] = {
|
||||
[B_INVALID] = {"invalid", NULL, false},
|
||||
|
||||
[B_BACKEND] = {"backend", BackendMain, true},
|
||||
[B_AUTOVAC_LAUNCHER] = {"autovacuum launcher", AutoVacLauncherMain, true},
|
||||
[B_AUTOVAC_WORKER] = {"autovacuum worker", AutoVacWorkerMain, true},
|
||||
[B_BG_WORKER] = {"bgworker", BackgroundWorkerMain, true},
|
||||
|
||||
/*
|
||||
* WAL senders start their life as regular backend processes, and change
|
||||
* their type after authenticating the client for replication. We list it
|
||||
* here forPostmasterChildName() but cannot launch them directly.
|
||||
*/
|
||||
[B_WAL_SENDER] = {"wal sender", NULL, true},
|
||||
[B_SLOTSYNC_WORKER] = {"slot sync worker", ReplSlotSyncWorkerMain, true},
|
||||
|
||||
[B_STANDALONE_BACKEND] = {"standalone backend", NULL, false},
|
||||
|
||||
[B_ARCHIVER] = {"archiver", PgArchiverMain, true},
|
||||
[B_BG_WRITER] = {"bgwriter", BackgroundWriterMain, true},
|
||||
[B_CHECKPOINTER] = {"checkpointer", CheckpointerMain, true},
|
||||
[B_STARTUP] = {"startup", StartupProcessMain, true},
|
||||
[B_WAL_RECEIVER] = {"wal_receiver", WalReceiverMain, true},
|
||||
[B_WAL_SUMMARIZER] = {"wal_summarizer", WalSummarizerMain, true},
|
||||
[B_WAL_WRITER] = {"wal_writer", WalWriterMain, true},
|
||||
|
||||
[B_LOGGER] = {"syslogger", SysLoggerMain, false},
|
||||
};
|
||||
|
||||
const char *
|
||||
PostmasterChildName(BackendType child_type)
|
||||
{
|
||||
Assert(child_type >= 0 && child_type < lengthof(child_process_kinds));
|
||||
return child_process_kinds[child_type].name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start a new postmaster child process.
|
||||
*
|
||||
* The child process will be restored to roughly the same state whether
|
||||
* EXEC_BACKEND is used or not: it will be attached to shared memory, and fds
|
||||
* and other resources that we've inherited from postmaster that are not
|
||||
* needed in a child process have been closed.
|
||||
*
|
||||
* 'startup_data' is an optional contiguous chunk of data that is passed to
|
||||
* the child process.
|
||||
*/
|
||||
pid_t
|
||||
postmaster_child_launch(BackendType child_type,
|
||||
char *startup_data, size_t startup_data_len,
|
||||
ClientSocket *client_sock)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
Assert(child_type >= 0 && child_type < lengthof(child_process_kinds));
|
||||
Assert(IsPostmasterEnvironment && !IsUnderPostmaster);
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
pid = internal_forkexec(child_process_kinds[child_type].name,
|
||||
startup_data, startup_data_len, client_sock);
|
||||
/* the child process will arrive in SubPostmasterMain */
|
||||
#else /* !EXEC_BACKEND */
|
||||
pid = fork_process();
|
||||
if (pid == 0) /* child */
|
||||
{
|
||||
/* Close the postmaster's sockets */
|
||||
ClosePostmasterPorts(child_type == B_LOGGER);
|
||||
|
||||
/* Detangle from postmaster */
|
||||
InitPostmasterChild();
|
||||
|
||||
/*
|
||||
* Enter the Main function with TopMemoryContext. The startup data is
|
||||
* allocated in PostmasterContext, so we cannot release it here yet.
|
||||
* The Main function will do it after it's done handling the startup
|
||||
* data.
|
||||
*/
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
|
||||
if (client_sock)
|
||||
{
|
||||
MyClientSocket = palloc(sizeof(ClientSocket));
|
||||
memcpy(MyClientSocket, client_sock, sizeof(ClientSocket));
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the appropriate Main function
|
||||
*/
|
||||
child_process_kinds[child_type].main_fn(startup_data, startup_data_len);
|
||||
pg_unreachable(); /* main_fn never returns */
|
||||
}
|
||||
#endif /* EXEC_BACKEND */
|
||||
return pid;
|
||||
}
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
#ifndef WIN32
|
||||
|
||||
/*
|
||||
|
@ -162,25 +279,32 @@ pid_t internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, Back
|
|||
* - writes out backend variables to the parameter file
|
||||
* - fork():s, and then exec():s the child process
|
||||
*/
|
||||
pid_t
|
||||
internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker)
|
||||
static pid_t
|
||||
internal_forkexec(const char *child_kind, char *startup_data, size_t startup_data_len, ClientSocket *client_sock)
|
||||
{
|
||||
static unsigned long tmpBackendFileNum = 0;
|
||||
pid_t pid;
|
||||
char tmpfilename[MAXPGPATH];
|
||||
BackendParameters param;
|
||||
size_t paramsz;
|
||||
BackendParameters *param;
|
||||
FILE *fp;
|
||||
char *argv[4];
|
||||
char forkav[MAXPGPATH];
|
||||
|
||||
/*
|
||||
* Make sure padding bytes are initialized, to prevent Valgrind from
|
||||
* complaining about writing uninitialized bytes to the file. This isn't
|
||||
* performance critical, and the win32 implementation initializes the
|
||||
* padding bytes to zeros, so do it even when not using Valgrind.
|
||||
* Use palloc0 to make sure padding bytes are initialized, to prevent
|
||||
* Valgrind from complaining about writing uninitialized bytes to the
|
||||
* file. This isn't performance critical, and the win32 implementation
|
||||
* initializes the padding bytes to zeros, so do it even when not using
|
||||
* Valgrind.
|
||||
*/
|
||||
memset(¶m, 0, sizeof(BackendParameters));
|
||||
|
||||
if (!save_backend_variables(¶m, client_sock, worker))
|
||||
paramsz = SizeOfBackendParameters(startup_data_len);
|
||||
param = palloc0(paramsz);
|
||||
if (!save_backend_variables(param, client_sock, startup_data, startup_data_len))
|
||||
{
|
||||
pfree(param);
|
||||
return -1; /* log made by save_backend_variables */
|
||||
}
|
||||
|
||||
/* Calculate name for temp file */
|
||||
snprintf(tmpfilename, MAXPGPATH, "%s/%s.backend_var.%d.%lu",
|
||||
|
@ -204,18 +328,21 @@ internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundW
|
|||
(errcode_for_file_access(),
|
||||
errmsg("could not create file \"%s\": %m",
|
||||
tmpfilename)));
|
||||
pfree(param);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fwrite(¶m, sizeof(param), 1, fp) != 1)
|
||||
if (fwrite(param, paramsz, 1, fp) != 1)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not write to file \"%s\": %m", tmpfilename)));
|
||||
FreeFile(fp);
|
||||
pfree(param);
|
||||
return -1;
|
||||
}
|
||||
pfree(param);
|
||||
|
||||
/* Release file */
|
||||
if (FreeFile(fp))
|
||||
|
@ -226,14 +353,13 @@ internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundW
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure caller set up argv properly */
|
||||
Assert(argc >= 3);
|
||||
Assert(argv[argc] == NULL);
|
||||
Assert(strncmp(argv[1], "--fork", 6) == 0);
|
||||
Assert(argv[2] == NULL);
|
||||
|
||||
/* Insert temp file name after --fork argument */
|
||||
/* set up argv properly */
|
||||
argv[0] = "postgres";
|
||||
snprintf(forkav, MAXPGPATH, "--forkchild=%s", child_kind);
|
||||
argv[1] = forkav;
|
||||
/* Insert temp file name after --forkchild argument */
|
||||
argv[2] = tmpfilename;
|
||||
argv[3] = NULL;
|
||||
|
||||
/* Fire off execv in child */
|
||||
if ((pid = fork_process()) == 0)
|
||||
|
@ -262,25 +388,21 @@ internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundW
|
|||
* - resumes execution of the new process once the backend parameter
|
||||
* file is complete.
|
||||
*/
|
||||
pid_t
|
||||
internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker)
|
||||
static pid_t
|
||||
internal_forkexec(const char *child_kind, char *startup_data, size_t startup_data_len, ClientSocket *client_sock)
|
||||
{
|
||||
int retry_count = 0;
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
int i;
|
||||
int j;
|
||||
char cmdLine[MAXPGPATH * 2];
|
||||
HANDLE paramHandle;
|
||||
BackendParameters *param;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
size_t paramsz;
|
||||
char paramHandleStr[32];
|
||||
int l;
|
||||
|
||||
/* Make sure caller set up argv properly */
|
||||
Assert(argc >= 3);
|
||||
Assert(argv[argc] == NULL);
|
||||
Assert(strncmp(argv[1], "--fork", 6) == 0);
|
||||
Assert(argv[2] == NULL);
|
||||
paramsz = SizeOfBackendParameters(startup_data_len);
|
||||
|
||||
/* Resume here if we need to retry */
|
||||
retry:
|
||||
|
@ -293,7 +415,7 @@ retry:
|
|||
&sa,
|
||||
PAGE_READWRITE,
|
||||
0,
|
||||
sizeof(BackendParameters),
|
||||
paramsz,
|
||||
NULL);
|
||||
if (paramHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
|
@ -302,8 +424,7 @@ retry:
|
|||
GetLastError())));
|
||||
return -1;
|
||||
}
|
||||
|
||||
param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters));
|
||||
param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, paramsz);
|
||||
if (!param)
|
||||
{
|
||||
ereport(LOG,
|
||||
|
@ -313,25 +434,15 @@ retry:
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Insert temp file name after --fork argument */
|
||||
/* Format the cmd line */
|
||||
#ifdef _WIN64
|
||||
sprintf(paramHandleStr, "%llu", (LONG_PTR) paramHandle);
|
||||
#else
|
||||
sprintf(paramHandleStr, "%lu", (DWORD) paramHandle);
|
||||
#endif
|
||||
argv[2] = paramHandleStr;
|
||||
|
||||
/* Format the cmd line */
|
||||
cmdLine[sizeof(cmdLine) - 1] = '\0';
|
||||
cmdLine[sizeof(cmdLine) - 2] = '\0';
|
||||
snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", postgres_exec_path);
|
||||
i = 0;
|
||||
while (argv[++i] != NULL)
|
||||
{
|
||||
j = strlen(cmdLine);
|
||||
snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"", argv[i]);
|
||||
}
|
||||
if (cmdLine[sizeof(cmdLine) - 2] != '\0')
|
||||
l = snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\" --forkchild=\"%s\" %s",
|
||||
postgres_exec_path, child_kind, paramHandleStr);
|
||||
if (l >= sizeof(cmdLine))
|
||||
{
|
||||
ereport(LOG,
|
||||
(errmsg("subprocess command line too long")));
|
||||
|
@ -359,7 +470,7 @@ retry:
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!save_backend_variables(param, client_sock, worker, pi.hProcess, pi.dwProcessId))
|
||||
if (!save_backend_variables(param, client_sock, pi.hProcess, pi.dwProcessId, startup_data, startup_data_len))
|
||||
{
|
||||
/*
|
||||
* log made by save_backend_variables, but we have to clean up the
|
||||
|
@ -445,6 +556,119 @@ retry:
|
|||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
/*
|
||||
* SubPostmasterMain -- Get the fork/exec'd process into a state equivalent
|
||||
* to what it would be if we'd simply forked on Unix, and then
|
||||
* dispatch to the appropriate place.
|
||||
*
|
||||
* The first two command line arguments are expected to be "--forkchild=<name>",
|
||||
* where <name> indicates which postmaster child we are to become, and
|
||||
* the name of a variables file that we can read to load data that would
|
||||
* have been inherited by fork() on Unix.
|
||||
*/
|
||||
void
|
||||
SubPostmasterMain(int argc, char *argv[])
|
||||
{
|
||||
char *startup_data;
|
||||
size_t startup_data_len;
|
||||
char *child_kind;
|
||||
BackendType child_type;
|
||||
bool found = false;
|
||||
|
||||
/* In EXEC_BACKEND case we will not have inherited these settings */
|
||||
IsPostmasterEnvironment = true;
|
||||
whereToSendOutput = DestNone;
|
||||
|
||||
/* Setup essential subsystems (to ensure elog() behaves sanely) */
|
||||
InitializeGUCOptions();
|
||||
|
||||
/* Check we got appropriate args */
|
||||
if (argc != 3)
|
||||
elog(FATAL, "invalid subpostmaster invocation");
|
||||
|
||||
/* Find the entry in child_process_kinds */
|
||||
if (strncmp(argv[1], "--forkchild=", 12) != 0)
|
||||
elog(FATAL, "invalid subpostmaster invocation (--forkchild argument missing)");
|
||||
child_kind = argv[1] + 12;
|
||||
found = false;
|
||||
for (int idx = 0; idx < lengthof(child_process_kinds); idx++)
|
||||
{
|
||||
if (strcmp(child_process_kinds[idx].name, child_kind) == 0)
|
||||
{
|
||||
child_type = (BackendType) idx;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
elog(ERROR, "unknown child kind %s", child_kind);
|
||||
|
||||
/* Read in the variables file */
|
||||
read_backend_variables(argv[2], &startup_data, &startup_data_len);
|
||||
|
||||
/* Close the postmaster's sockets (as soon as we know them) */
|
||||
ClosePostmasterPorts(child_type == B_LOGGER);
|
||||
|
||||
/* Setup as postmaster child */
|
||||
InitPostmasterChild();
|
||||
|
||||
/*
|
||||
* If appropriate, physically re-attach to shared memory segment. We want
|
||||
* to do this before going any further to ensure that we can attach at the
|
||||
* same address the postmaster used. On the other hand, if we choose not
|
||||
* to re-attach, we may have other cleanup to do.
|
||||
*
|
||||
* If testing EXEC_BACKEND on Linux, you should run this as root before
|
||||
* starting the postmaster:
|
||||
*
|
||||
* sysctl -w kernel.randomize_va_space=0
|
||||
*
|
||||
* This prevents using randomized stack and code addresses that cause the
|
||||
* child process's memory map to be different from the parent's, making it
|
||||
* sometimes impossible to attach to shared memory at the desired address.
|
||||
* Return the setting to its old value (usually '1' or '2') when finished.
|
||||
*/
|
||||
if (child_process_kinds[child_type].shmem_attach)
|
||||
PGSharedMemoryReAttach();
|
||||
else
|
||||
PGSharedMemoryNoReAttach();
|
||||
|
||||
/* Read in remaining GUC variables */
|
||||
read_nondefault_variables();
|
||||
|
||||
/*
|
||||
* Check that the data directory looks valid, which will also check the
|
||||
* privileges on the data directory and update our umask and file/group
|
||||
* variables for creating files later. Note: this should really be done
|
||||
* before we create any files or directories.
|
||||
*/
|
||||
checkDataDir();
|
||||
|
||||
/*
|
||||
* (re-)read control file, as it contains config. The postmaster will
|
||||
* already have read this, but this process doesn't know about that.
|
||||
*/
|
||||
LocalProcessControlFile(false);
|
||||
|
||||
/*
|
||||
* Reload any libraries that were preloaded by the postmaster. Since we
|
||||
* exec'd this process, those libraries didn't come along with us; but we
|
||||
* should load them into all child processes to be consistent with the
|
||||
* non-EXEC_BACKEND behavior.
|
||||
*/
|
||||
process_shared_preload_libraries();
|
||||
|
||||
/* Restore basic shared memory pointers */
|
||||
if (UsedShmemSegAddr != NULL)
|
||||
InitShmemAccess(UsedShmemSegAddr);
|
||||
|
||||
/*
|
||||
* Run the appropriate Main function
|
||||
*/
|
||||
child_process_kinds[child_type].main_fn(startup_data, startup_data_len);
|
||||
pg_unreachable(); /* main_fn never returns */
|
||||
}
|
||||
|
||||
/*
|
||||
* The following need to be available to the save/restore_backend_variables
|
||||
* functions. They are marked NON_EXEC_STATIC in their home modules.
|
||||
|
@ -469,38 +693,21 @@ static void read_inheritable_socket(SOCKET *dest, InheritableSocket *src);
|
|||
|
||||
|
||||
/* Save critical backend variables into the BackendParameters struct */
|
||||
#ifndef WIN32
|
||||
static bool
|
||||
save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker)
|
||||
#else
|
||||
static bool
|
||||
save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker,
|
||||
HANDLE childProcess, pid_t childPid)
|
||||
save_backend_variables(BackendParameters *param, ClientSocket *client_sock,
|
||||
#ifdef WIN32
|
||||
HANDLE childProcess, pid_t childPid,
|
||||
#endif
|
||||
char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
if (client_sock)
|
||||
{
|
||||
memcpy(¶m->client_sock, client_sock, sizeof(ClientSocket));
|
||||
if (!write_inheritable_socket(¶m->inh_sock, client_sock->sock, childPid))
|
||||
return false;
|
||||
param->has_client_sock = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(¶m->client_sock, 0, sizeof(ClientSocket));
|
||||
param->has_client_sock = false;
|
||||
}
|
||||
|
||||
if (worker)
|
||||
{
|
||||
memcpy(¶m->bgworker, worker, sizeof(BackgroundWorker));
|
||||
param->has_bgworker = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(¶m->bgworker, 0, sizeof(BackgroundWorker));
|
||||
param->has_bgworker = false;
|
||||
}
|
||||
if (!write_inheritable_socket(¶m->inh_sock,
|
||||
client_sock ? client_sock->sock : PGINVALID_SOCKET,
|
||||
childPid))
|
||||
return false;
|
||||
|
||||
strlcpy(param->DataDir, DataDir, MAXPGPATH);
|
||||
|
||||
|
@ -557,6 +764,9 @@ save_backend_variables(BackendParameters *param, ClientSocket *client_sock, Back
|
|||
|
||||
strlcpy(param->pkglib_path, pkglib_path, MAXPGPATH);
|
||||
|
||||
param->startup_data_len = startup_data_len;
|
||||
memcpy(param->startup_data, startup_data, startup_data_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -653,8 +863,8 @@ read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker)
|
||||
static void
|
||||
read_backend_variables(char *id, char **startup_data, size_t *startup_data_len)
|
||||
{
|
||||
BackendParameters param;
|
||||
|
||||
|
@ -676,6 +886,21 @@ read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **
|
|||
exit(1);
|
||||
}
|
||||
|
||||
/* read startup data */
|
||||
*startup_data_len = param.startup_data_len;
|
||||
if (param.startup_data_len > 0)
|
||||
{
|
||||
*startup_data = palloc(*startup_data_len);
|
||||
if (fread(*startup_data, *startup_data_len, 1, fp) != 1)
|
||||
{
|
||||
write_stderr("could not read startup data from backend variables file \"%s\": %m\n",
|
||||
id);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
*startup_data = NULL;
|
||||
|
||||
/* Release file */
|
||||
FreeFile(fp);
|
||||
if (unlink(id) != 0)
|
||||
|
@ -703,6 +928,16 @@ read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **
|
|||
|
||||
memcpy(¶m, paramp, sizeof(BackendParameters));
|
||||
|
||||
/* read startup data */
|
||||
*startup_data_len = param.startup_data_len;
|
||||
if (param.startup_data_len > 0)
|
||||
{
|
||||
*startup_data = palloc(paramp->startup_data_len);
|
||||
memcpy(*startup_data, paramp->startup_data, param.startup_data_len);
|
||||
}
|
||||
else
|
||||
*startup_data = NULL;
|
||||
|
||||
if (!UnmapViewOfFile(paramp))
|
||||
{
|
||||
write_stderr("could not unmap view of backend variables: error code %lu\n",
|
||||
|
@ -718,30 +953,19 @@ read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **
|
|||
}
|
||||
#endif
|
||||
|
||||
restore_backend_variables(¶m, client_sock, worker);
|
||||
restore_backend_variables(¶m);
|
||||
}
|
||||
|
||||
/* Restore critical backend variables from the BackendParameters struct */
|
||||
static void
|
||||
restore_backend_variables(BackendParameters *param, ClientSocket **client_sock, BackgroundWorker **worker)
|
||||
restore_backend_variables(BackendParameters *param)
|
||||
{
|
||||
if (param->has_client_sock)
|
||||
if (param->client_sock.sock != PGINVALID_SOCKET)
|
||||
{
|
||||
*client_sock = (ClientSocket *) MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket));
|
||||
memcpy(*client_sock, ¶m->client_sock, sizeof(ClientSocket));
|
||||
read_inheritable_socket(&(*client_sock)->sock, ¶m->inh_sock);
|
||||
MyClientSocket = MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket));
|
||||
memcpy(MyClientSocket, ¶m->client_sock, sizeof(ClientSocket));
|
||||
read_inheritable_socket(&MyClientSocket->sock, ¶m->inh_sock);
|
||||
}
|
||||
else
|
||||
*client_sock = NULL;
|
||||
|
||||
if (param->has_bgworker)
|
||||
{
|
||||
*worker = (BackgroundWorker *)
|
||||
MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker));
|
||||
memcpy(*worker, ¶m->bgworker, sizeof(BackgroundWorker));
|
||||
}
|
||||
else
|
||||
*worker = NULL;
|
||||
|
||||
SetDataDir(param->DataDir);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "lib/binaryheap.h"
|
||||
#include "libpq/pqsignal.h"
|
||||
#include "pgstat.h"
|
||||
#include "postmaster/auxprocess.h"
|
||||
#include "postmaster/interrupt.h"
|
||||
#include "postmaster/pgarch.h"
|
||||
#include "storage/fd.h"
|
||||
|
@ -209,8 +210,13 @@ PgArchCanRestart(void)
|
|||
|
||||
/* Main entry point for archiver process */
|
||||
void
|
||||
PgArchiverMain(void)
|
||||
PgArchiverMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
MyBackendType = B_ARCHIVER;
|
||||
AuxiliaryProcessMainCommon();
|
||||
|
||||
/*
|
||||
* Ignore all signals usually bound to some action in the postmaster,
|
||||
* except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
*
|
||||
* postmaster.c
|
||||
* This program acts as a clearing house for requests to the
|
||||
* POSTGRES system. Frontend programs send a startup message
|
||||
* to the Postmaster and the postmaster uses the info in the
|
||||
* message to setup a backend process.
|
||||
* POSTGRES system. Frontend programs connect to the Postmaster,
|
||||
* and postmaster forks a new backend process to handle the
|
||||
* connection.
|
||||
*
|
||||
* The postmaster also manages system-wide operations such as
|
||||
* startup and shutdown. The postmaster itself doesn't do those
|
||||
|
@ -106,7 +106,6 @@
|
|||
#include "postmaster/autovacuum.h"
|
||||
#include "postmaster/auxprocess.h"
|
||||
#include "postmaster/bgworker_internals.h"
|
||||
#include "postmaster/fork_process.h"
|
||||
#include "postmaster/pgarch.h"
|
||||
#include "postmaster/postmaster.h"
|
||||
#include "postmaster/syslogger.h"
|
||||
|
@ -427,7 +426,6 @@ typedef enum CAC_state
|
|||
} CAC_state;
|
||||
|
||||
static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
|
||||
static void BackendRun(void) pg_attribute_noreturn();
|
||||
static void ExitPostmaster(int status) pg_attribute_noreturn();
|
||||
static int ServerLoop(void);
|
||||
static int BackendStartup(ClientSocket *client_sock);
|
||||
|
@ -485,13 +483,6 @@ typedef struct
|
|||
} win32_deadchild_waitinfo;
|
||||
#endif /* WIN32 */
|
||||
|
||||
static pid_t backend_forkexec(ClientSocket *client_sock, CAC_state cac);
|
||||
|
||||
|
||||
/* in launch_backend.c */
|
||||
extern pid_t internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker);
|
||||
extern void read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker);
|
||||
|
||||
static void ShmemBackendArrayAdd(Backend *bn);
|
||||
static void ShmemBackendArrayRemove(Backend *bn);
|
||||
#endif /* EXEC_BACKEND */
|
||||
|
@ -1748,7 +1739,7 @@ ServerLoop(void)
|
|||
(AutoVacuumingActive() || start_autovac_launcher) &&
|
||||
pmState == PM_RUN)
|
||||
{
|
||||
AutoVacPID = StartAutoVacLauncher();
|
||||
AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
|
||||
if (AutoVacPID != 0)
|
||||
start_autovac_launcher = false; /* signal processed */
|
||||
}
|
||||
|
@ -2902,7 +2893,7 @@ process_pm_child_exit(void)
|
|||
* situation, some of them may be alive already.
|
||||
*/
|
||||
if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0)
|
||||
AutoVacPID = StartAutoVacLauncher();
|
||||
AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
|
||||
if (PgArchStartupAllowed() && PgArchPID == 0)
|
||||
PgArchPID = StartChildProcess(B_ARCHIVER);
|
||||
MaybeStartSlotSyncWorker();
|
||||
|
@ -3964,6 +3955,12 @@ TerminateChildren(int signal)
|
|||
signal_child(SlotSyncWorkerPID, signal);
|
||||
}
|
||||
|
||||
/* Information passed from postmaster to backend process */
|
||||
typedef struct BackendStartupData
|
||||
{
|
||||
CAC_state canAcceptConnections;
|
||||
} BackendStartupData;
|
||||
|
||||
/*
|
||||
* BackendStartup -- start backend process
|
||||
*
|
||||
|
@ -3976,7 +3973,7 @@ BackendStartup(ClientSocket *client_sock)
|
|||
{
|
||||
Backend *bn; /* for backend cleanup */
|
||||
pid_t pid;
|
||||
CAC_state cac;
|
||||
BackendStartupData startup_data;
|
||||
|
||||
/*
|
||||
* Create backend data structure. Better before the fork() so we can
|
||||
|
@ -4005,11 +4002,10 @@ BackendStartup(ClientSocket *client_sock)
|
|||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
bn->cancel_key = MyCancelKey;
|
||||
|
||||
/* Pass down canAcceptConnections state */
|
||||
cac = canAcceptConnections(BACKEND_TYPE_NORMAL);
|
||||
bn->dead_end = (cac != CAC_OK);
|
||||
startup_data.canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL);
|
||||
bn->dead_end = (startup_data.canAcceptConnections != CAC_OK);
|
||||
bn->cancel_key = MyCancelKey;
|
||||
|
||||
/*
|
||||
* Unless it's a dead_end child, assign it a child slot number
|
||||
|
@ -4022,26 +4018,9 @@ BackendStartup(ClientSocket *client_sock)
|
|||
/* Hasn't asked to be notified about any bgworkers yet */
|
||||
bn->bgworker_notify = false;
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
pid = backend_forkexec(client_sock, cac);
|
||||
#else /* !EXEC_BACKEND */
|
||||
pid = fork_process();
|
||||
if (pid == 0) /* child */
|
||||
{
|
||||
/* Detangle from postmaster */
|
||||
InitPostmasterChild();
|
||||
|
||||
/* Close the postmaster's sockets */
|
||||
ClosePostmasterPorts(false);
|
||||
|
||||
/* Perform additional initialization and collect startup packet */
|
||||
BackendInitialize(client_sock, cac);
|
||||
|
||||
/* And run the backend */
|
||||
BackendRun();
|
||||
}
|
||||
#endif /* EXEC_BACKEND */
|
||||
|
||||
pid = postmaster_child_launch(B_BACKEND,
|
||||
(char *) &startup_data, sizeof(startup_data),
|
||||
client_sock);
|
||||
if (pid < 0)
|
||||
{
|
||||
/* in parent, fork failed */
|
||||
|
@ -4351,16 +4330,43 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac)
|
|||
set_ps_display("initializing");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BackendRun -- set up the backend's argument list and invoke PostgresMain()
|
||||
*
|
||||
* returns:
|
||||
* Doesn't return at all.
|
||||
*/
|
||||
static void
|
||||
BackendRun(void)
|
||||
void
|
||||
BackendMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
BackendStartupData *bsdata = (BackendStartupData *) startup_data;
|
||||
|
||||
Assert(startup_data_len == sizeof(BackendStartupData));
|
||||
Assert(MyClientSocket != NULL);
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
|
||||
/*
|
||||
* Need to reinitialize the SSL library in the backend, since the context
|
||||
* structures contain function pointers and cannot be passed through the
|
||||
* parameter file.
|
||||
*
|
||||
* If for some reason reload fails (maybe the user installed broken key
|
||||
* files), soldier on without SSL; that's better than all connections
|
||||
* becoming impossible.
|
||||
*
|
||||
* XXX should we do this in all child processes? For the moment it's
|
||||
* enough to do it in backend children.
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
if (EnableSSL)
|
||||
{
|
||||
if (secure_initialize(false) == 0)
|
||||
LoadedSSL = true;
|
||||
else
|
||||
ereport(LOG,
|
||||
(errmsg("SSL configuration could not be loaded in child process")));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Perform additional initialization and collect startup packet */
|
||||
BackendInitialize(MyClientSocket, bsdata->canAcceptConnections);
|
||||
|
||||
/*
|
||||
* Create a per-backend PGPROC struct in shared memory. We must do this
|
||||
* before we can use LWLocks or access any shared memory.
|
||||
|
@ -4377,245 +4383,6 @@ BackendRun(void)
|
|||
}
|
||||
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
|
||||
/*
|
||||
* postmaster_forkexec -- fork and exec a postmaster subprocess
|
||||
*
|
||||
* The caller must have set up the argv array already, except for argv[2]
|
||||
* which will be filled with the name of the temp variable file.
|
||||
*
|
||||
* Returns the child process PID, or -1 on fork failure (a suitable error
|
||||
* message has been logged on failure).
|
||||
*
|
||||
* All uses of this routine will dispatch to SubPostmasterMain in the
|
||||
* child process.
|
||||
*/
|
||||
pid_t
|
||||
postmaster_forkexec(int argc, char *argv[])
|
||||
{
|
||||
return internal_forkexec(argc, argv, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* backend_forkexec -- fork/exec off a backend process
|
||||
*
|
||||
* Some operating systems (WIN32) don't have fork() so we have to simulate
|
||||
* it by storing parameters that need to be passed to the child and
|
||||
* then create a new child process.
|
||||
*
|
||||
* returns the pid of the fork/exec'd process, or -1 on failure
|
||||
*/
|
||||
static pid_t
|
||||
backend_forkexec(ClientSocket *client_sock, CAC_state cac)
|
||||
{
|
||||
char *av[5];
|
||||
int ac = 0;
|
||||
char cacbuf[10];
|
||||
|
||||
av[ac++] = "postgres";
|
||||
av[ac++] = "--forkbackend";
|
||||
av[ac++] = NULL; /* filled in by internal_forkexec */
|
||||
|
||||
snprintf(cacbuf, sizeof(cacbuf), "%d", (int) cac);
|
||||
av[ac++] = cacbuf;
|
||||
|
||||
av[ac] = NULL;
|
||||
Assert(ac < lengthof(av));
|
||||
|
||||
return internal_forkexec(ac, av, client_sock, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* SubPostmasterMain -- Get the fork/exec'd process into a state equivalent
|
||||
* to what it would be if we'd simply forked on Unix, and then
|
||||
* dispatch to the appropriate place.
|
||||
*
|
||||
* The first two command line arguments are expected to be "--forkFOO"
|
||||
* (where FOO indicates which postmaster child we are to become), and
|
||||
* the name of a variables file that we can read to load data that would
|
||||
* have been inherited by fork() on Unix. Remaining arguments go to the
|
||||
* subprocess FooMain() routine.
|
||||
*/
|
||||
void
|
||||
SubPostmasterMain(int argc, char *argv[])
|
||||
{
|
||||
ClientSocket *client_sock;
|
||||
BackgroundWorker *worker;
|
||||
|
||||
/* In EXEC_BACKEND case we will not have inherited these settings */
|
||||
IsPostmasterEnvironment = true;
|
||||
whereToSendOutput = DestNone;
|
||||
|
||||
/* Setup essential subsystems (to ensure elog() behaves sanely) */
|
||||
InitializeGUCOptions();
|
||||
|
||||
/* Check we got appropriate args */
|
||||
if (argc < 3)
|
||||
elog(FATAL, "invalid subpostmaster invocation");
|
||||
|
||||
/* Read in the variables file */
|
||||
read_backend_variables(argv[2], &client_sock, &worker);
|
||||
|
||||
/* Close the postmaster's sockets (as soon as we know them) */
|
||||
ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0);
|
||||
|
||||
/* Setup as postmaster child */
|
||||
InitPostmasterChild();
|
||||
|
||||
/*
|
||||
* If appropriate, physically re-attach to shared memory segment. We want
|
||||
* to do this before going any further to ensure that we can attach at the
|
||||
* same address the postmaster used. On the other hand, if we choose not
|
||||
* to re-attach, we may have other cleanup to do.
|
||||
*
|
||||
* If testing EXEC_BACKEND on Linux, you should run this as root before
|
||||
* starting the postmaster:
|
||||
*
|
||||
* sysctl -w kernel.randomize_va_space=0
|
||||
*
|
||||
* This prevents using randomized stack and code addresses that cause the
|
||||
* child process's memory map to be different from the parent's, making it
|
||||
* sometimes impossible to attach to shared memory at the desired address.
|
||||
* Return the setting to its old value (usually '1' or '2') when finished.
|
||||
*/
|
||||
if (strcmp(argv[1], "--forkbackend") == 0 ||
|
||||
strcmp(argv[1], "--forkavlauncher") == 0 ||
|
||||
strcmp(argv[1], "--forkssworker") == 0 ||
|
||||
strcmp(argv[1], "--forkavworker") == 0 ||
|
||||
strcmp(argv[1], "--forkaux") == 0 ||
|
||||
strcmp(argv[1], "--forkbgworker") == 0)
|
||||
PGSharedMemoryReAttach();
|
||||
else
|
||||
PGSharedMemoryNoReAttach();
|
||||
|
||||
/* Read in remaining GUC variables */
|
||||
read_nondefault_variables();
|
||||
|
||||
/*
|
||||
* Check that the data directory looks valid, which will also check the
|
||||
* privileges on the data directory and update our umask and file/group
|
||||
* variables for creating files later. Note: this should really be done
|
||||
* before we create any files or directories.
|
||||
*/
|
||||
checkDataDir();
|
||||
|
||||
/*
|
||||
* (re-)read control file, as it contains config. The postmaster will
|
||||
* already have read this, but this process doesn't know about that.
|
||||
*/
|
||||
LocalProcessControlFile(false);
|
||||
|
||||
/*
|
||||
* Reload any libraries that were preloaded by the postmaster. Since we
|
||||
* exec'd this process, those libraries didn't come along with us; but we
|
||||
* should load them into all child processes to be consistent with the
|
||||
* non-EXEC_BACKEND behavior.
|
||||
*/
|
||||
process_shared_preload_libraries();
|
||||
|
||||
/* Run backend or appropriate child */
|
||||
if (strcmp(argv[1], "--forkbackend") == 0)
|
||||
{
|
||||
CAC_state cac;
|
||||
|
||||
Assert(argc == 4);
|
||||
cac = (CAC_state) atoi(argv[3]);
|
||||
|
||||
/*
|
||||
* Need to reinitialize the SSL library in the backend, since the
|
||||
* context structures contain function pointers and cannot be passed
|
||||
* through the parameter file.
|
||||
*
|
||||
* If for some reason reload fails (maybe the user installed broken
|
||||
* key files), soldier on without SSL; that's better than all
|
||||
* connections becoming impossible.
|
||||
*
|
||||
* XXX should we do this in all child processes? For the moment it's
|
||||
* enough to do it in backend children.
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
if (EnableSSL)
|
||||
{
|
||||
if (secure_initialize(false) == 0)
|
||||
LoadedSSL = true;
|
||||
else
|
||||
ereport(LOG,
|
||||
(errmsg("SSL configuration could not be loaded in child process")));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Perform additional initialization and collect startup packet.
|
||||
*
|
||||
* We want to do this before InitProcess() for a couple of reasons: 1.
|
||||
* so that we aren't eating up a PGPROC slot while waiting on the
|
||||
* client. 2. so that if InitProcess() fails due to being out of
|
||||
* PGPROC slots, we have already initialized libpq and are able to
|
||||
* report the error to the client.
|
||||
*/
|
||||
BackendInitialize(client_sock, cac);
|
||||
|
||||
/* Restore basic shared memory pointers */
|
||||
InitShmemAccess(UsedShmemSegAddr);
|
||||
|
||||
/* And run the backend */
|
||||
BackendRun(); /* does not return */
|
||||
|
||||
}
|
||||
if (strcmp(argv[1], "--forkaux") == 0)
|
||||
{
|
||||
BackendType auxtype;
|
||||
|
||||
Assert(argc == 4);
|
||||
|
||||
/* Restore basic shared memory pointers */
|
||||
InitShmemAccess(UsedShmemSegAddr);
|
||||
|
||||
auxtype = atoi(argv[3]);
|
||||
AuxiliaryProcessMain(auxtype); /* does not return */
|
||||
}
|
||||
if (strcmp(argv[1], "--forkavlauncher") == 0)
|
||||
{
|
||||
/* Restore basic shared memory pointers */
|
||||
InitShmemAccess(UsedShmemSegAddr);
|
||||
|
||||
AutoVacLauncherMain(argc - 2, argv + 2); /* does not return */
|
||||
}
|
||||
if (strcmp(argv[1], "--forkavworker") == 0)
|
||||
{
|
||||
/* Restore basic shared memory pointers */
|
||||
InitShmemAccess(UsedShmemSegAddr);
|
||||
|
||||
AutoVacWorkerMain(argc - 2, argv + 2); /* does not return */
|
||||
}
|
||||
if (strcmp(argv[1], "--forkssworker") == 0)
|
||||
{
|
||||
/* Restore basic shared memory pointers */
|
||||
InitShmemAccess(UsedShmemSegAddr);
|
||||
|
||||
ReplSlotSyncWorkerMain(argc - 2, argv + 2); /* does not return */
|
||||
}
|
||||
if (strcmp(argv[1], "--forkbgworker") == 0)
|
||||
{
|
||||
/* Restore basic shared memory pointers */
|
||||
InitShmemAccess(UsedShmemSegAddr);
|
||||
|
||||
MyBgworkerEntry = worker;
|
||||
BackgroundWorkerMain();
|
||||
}
|
||||
if (strcmp(argv[1], "--forklog") == 0)
|
||||
{
|
||||
/* Do not want to attach to shared memory */
|
||||
|
||||
SysLoggerMain(argc, argv); /* does not return */
|
||||
}
|
||||
|
||||
abort(); /* shouldn't get here */
|
||||
}
|
||||
#endif /* EXEC_BACKEND */
|
||||
|
||||
|
||||
/*
|
||||
* ExitPostmaster -- cleanup
|
||||
*
|
||||
|
@ -4912,87 +4679,12 @@ StartChildProcess(BackendType type)
|
|||
{
|
||||
pid_t pid;
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
{
|
||||
char *av[10];
|
||||
int ac = 0;
|
||||
char typebuf[32];
|
||||
|
||||
/*
|
||||
* Set up command-line arguments for subprocess
|
||||
*/
|
||||
av[ac++] = "postgres";
|
||||
av[ac++] = "--forkaux";
|
||||
av[ac++] = NULL; /* filled in by postmaster_forkexec */
|
||||
|
||||
snprintf(typebuf, sizeof(typebuf), "%d", type);
|
||||
av[ac++] = typebuf;
|
||||
|
||||
av[ac] = NULL;
|
||||
Assert(ac < lengthof(av));
|
||||
|
||||
pid = postmaster_forkexec(ac, av);
|
||||
}
|
||||
#else /* !EXEC_BACKEND */
|
||||
pid = fork_process();
|
||||
|
||||
if (pid == 0) /* child */
|
||||
{
|
||||
InitPostmasterChild();
|
||||
|
||||
/* Close the postmaster's sockets */
|
||||
ClosePostmasterPorts(false);
|
||||
|
||||
/* Release postmaster's working memory context */
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
PostmasterContext = NULL;
|
||||
|
||||
AuxiliaryProcessMain(type); /* does not return */
|
||||
}
|
||||
#endif /* EXEC_BACKEND */
|
||||
|
||||
pid = postmaster_child_launch(type, NULL, 0, NULL);
|
||||
if (pid < 0)
|
||||
{
|
||||
/* in parent, fork failed */
|
||||
int save_errno = errno;
|
||||
|
||||
errno = save_errno;
|
||||
switch (type)
|
||||
{
|
||||
case B_STARTUP:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork startup process: %m")));
|
||||
break;
|
||||
case B_ARCHIVER:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork archiver process: %m")));
|
||||
break;
|
||||
case B_BG_WRITER:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork background writer process: %m")));
|
||||
break;
|
||||
case B_CHECKPOINTER:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork checkpointer process: %m")));
|
||||
break;
|
||||
case B_WAL_WRITER:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork WAL writer process: %m")));
|
||||
break;
|
||||
case B_WAL_RECEIVER:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork WAL receiver process: %m")));
|
||||
break;
|
||||
case B_WAL_SUMMARIZER:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork WAL summarizer process: %m")));
|
||||
break;
|
||||
default:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork process: %m")));
|
||||
break;
|
||||
}
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork \"%s\" process: %m", PostmasterChildName(type))));
|
||||
|
||||
/*
|
||||
* fork failure is fatal during startup, but there's no need to choke
|
||||
|
@ -5056,7 +4748,7 @@ StartAutovacuumWorker(void)
|
|||
bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
|
||||
bn->bgworker_notify = false;
|
||||
|
||||
bn->pid = StartAutoVacWorker();
|
||||
bn->pid = StartChildProcess(B_AUTOVAC_WORKER);
|
||||
if (bn->pid > 0)
|
||||
{
|
||||
bn->bkend_type = BACKEND_TYPE_AUTOVAC;
|
||||
|
@ -5070,7 +4762,7 @@ StartAutovacuumWorker(void)
|
|||
|
||||
/*
|
||||
* fork failed, fall through to report -- actual error message was
|
||||
* logged by StartAutoVacWorker
|
||||
* logged by StartChildProcess
|
||||
*/
|
||||
(void) ReleasePostmasterChildSlot(bn->child_slot);
|
||||
pfree(bn);
|
||||
|
@ -5153,7 +4845,7 @@ MaybeStartSlotSyncWorker(void)
|
|||
if (SlotSyncWorkerPID == 0 && pmState == PM_HOT_STANDBY &&
|
||||
Shutdown <= SmartShutdown && sync_replication_slots &&
|
||||
ValidateSlotSyncParams(LOG) && SlotSyncWorkerCanRestart())
|
||||
SlotSyncWorkerPID = StartSlotSyncWorker();
|
||||
SlotSyncWorkerPID = StartChildProcess(B_SLOTSYNC_WORKER);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -5293,24 +4985,6 @@ BackgroundWorkerUnblockSignals(void)
|
|||
sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
|
||||
}
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
static pid_t
|
||||
bgworker_forkexec(BackgroundWorker *worker)
|
||||
{
|
||||
char *av[10];
|
||||
int ac = 0;
|
||||
|
||||
av[ac++] = "postgres";
|
||||
av[ac++] = "--forkbgworker";
|
||||
av[ac++] = NULL; /* filled in by internal_forkexec */
|
||||
av[ac] = NULL;
|
||||
|
||||
Assert(ac < lengthof(av));
|
||||
|
||||
return internal_forkexec(ac, av, NULL, worker);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start a new bgworker.
|
||||
* Starting time conditions must have been checked already.
|
||||
|
@ -5347,65 +5021,32 @@ do_start_bgworker(RegisteredBgWorker *rw)
|
|||
(errmsg_internal("starting background worker process \"%s\"",
|
||||
rw->rw_worker.bgw_name)));
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
switch ((worker_pid = bgworker_forkexec(&rw->rw_worker)))
|
||||
#else
|
||||
switch ((worker_pid = fork_process()))
|
||||
#endif
|
||||
worker_pid = postmaster_child_launch(B_BG_WORKER, (char *) &rw->rw_worker, sizeof(BackgroundWorker), NULL);
|
||||
if (worker_pid == -1)
|
||||
{
|
||||
case -1:
|
||||
/* in postmaster, fork failed ... */
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork background worker process: %m")));
|
||||
/* undo what assign_backendlist_entry did */
|
||||
ReleasePostmasterChildSlot(rw->rw_child_slot);
|
||||
rw->rw_child_slot = 0;
|
||||
pfree(rw->rw_backend);
|
||||
rw->rw_backend = NULL;
|
||||
/* mark entry as crashed, so we'll try again later */
|
||||
rw->rw_crashed_at = GetCurrentTimestamp();
|
||||
break;
|
||||
|
||||
#ifndef EXEC_BACKEND
|
||||
case 0:
|
||||
/* in postmaster child ... */
|
||||
InitPostmasterChild();
|
||||
|
||||
/* Close the postmaster's sockets */
|
||||
ClosePostmasterPorts(false);
|
||||
|
||||
/*
|
||||
* Before blowing away PostmasterContext, save this bgworker's
|
||||
* data where it can find it.
|
||||
*/
|
||||
MyBgworkerEntry = (BackgroundWorker *)
|
||||
MemoryContextAlloc(TopMemoryContext, sizeof(BackgroundWorker));
|
||||
memcpy(MyBgworkerEntry, &rw->rw_worker, sizeof(BackgroundWorker));
|
||||
|
||||
/* Release postmaster's working memory context */
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
PostmasterContext = NULL;
|
||||
|
||||
BackgroundWorkerMain();
|
||||
|
||||
exit(1); /* should not get here */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* in postmaster, fork successful ... */
|
||||
rw->rw_pid = worker_pid;
|
||||
rw->rw_backend->pid = rw->rw_pid;
|
||||
ReportBackgroundWorkerPID(rw);
|
||||
/* add new worker to lists of backends */
|
||||
dlist_push_head(&BackendList, &rw->rw_backend->elem);
|
||||
#ifdef EXEC_BACKEND
|
||||
ShmemBackendArrayAdd(rw->rw_backend);
|
||||
#endif
|
||||
return true;
|
||||
/* in postmaster, fork failed ... */
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork background worker process: %m")));
|
||||
/* undo what assign_backendlist_entry did */
|
||||
ReleasePostmasterChildSlot(rw->rw_child_slot);
|
||||
rw->rw_child_slot = 0;
|
||||
pfree(rw->rw_backend);
|
||||
rw->rw_backend = NULL;
|
||||
/* mark entry as crashed, so we'll try again later */
|
||||
rw->rw_crashed_at = GetCurrentTimestamp();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
/* in postmaster, fork successful ... */
|
||||
rw->rw_pid = worker_pid;
|
||||
rw->rw_backend->pid = rw->rw_pid;
|
||||
ReportBackgroundWorkerPID(rw);
|
||||
/* add new worker to lists of backends */
|
||||
dlist_push_head(&BackendList, &rw->rw_backend->elem);
|
||||
#ifdef EXEC_BACKEND
|
||||
ShmemBackendArrayAdd(rw->rw_backend);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "access/xlogutils.h"
|
||||
#include "libpq/pqsignal.h"
|
||||
#include "miscadmin.h"
|
||||
#include "postmaster/auxprocess.h"
|
||||
#include "postmaster/startup.h"
|
||||
#include "storage/ipc.h"
|
||||
#include "storage/pmsignal.h"
|
||||
|
@ -212,8 +213,13 @@ StartupProcExit(int code, Datum arg)
|
|||
* ----------------------------------
|
||||
*/
|
||||
void
|
||||
StartupProcessMain(void)
|
||||
StartupProcessMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
MyBackendType = B_STARTUP;
|
||||
AuxiliaryProcessMainCommon();
|
||||
|
||||
/* Arrange to clean up at startup process exit */
|
||||
on_shmem_exit(StartupProcExit, 0);
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "pgstat.h"
|
||||
#include "pgtime.h"
|
||||
#include "port/pg_bitutils.h"
|
||||
#include "postmaster/fork_process.h"
|
||||
#include "postmaster/interrupt.h"
|
||||
#include "postmaster/postmaster.h"
|
||||
#include "postmaster/syslogger.h"
|
||||
|
@ -50,6 +49,7 @@
|
|||
#include "storage/pg_shmem.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/ps_status.h"
|
||||
|
||||
/*
|
||||
|
@ -133,10 +133,7 @@ static volatile sig_atomic_t rotation_requested = false;
|
|||
#ifdef EXEC_BACKEND
|
||||
static int syslogger_fdget(FILE *file);
|
||||
static FILE *syslogger_fdopen(int fd);
|
||||
static pid_t syslogger_forkexec(void);
|
||||
static void syslogger_parseArgs(int argc, char *argv[]);
|
||||
#endif
|
||||
NON_EXEC_STATIC void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
|
||||
static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
|
||||
static FILE *logfile_open(const char *filename, const char *mode,
|
||||
|
@ -155,13 +152,19 @@ static void set_next_rotation_time(void);
|
|||
static void sigUsr1Handler(SIGNAL_ARGS);
|
||||
static void update_metainfo_datafile(void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int syslogFile;
|
||||
int csvlogFile;
|
||||
int jsonlogFile;
|
||||
} SysloggerStartupData;
|
||||
|
||||
/*
|
||||
* Main entry point for syslogger process
|
||||
* argc/argv parameters are valid only in EXEC_BACKEND case.
|
||||
*/
|
||||
NON_EXEC_STATIC void
|
||||
SysLoggerMain(int argc, char *argv[])
|
||||
void
|
||||
SysLoggerMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
#ifndef WIN32
|
||||
char logbuffer[READ_BUF_SIZE];
|
||||
|
@ -173,11 +176,37 @@ SysLoggerMain(int argc, char *argv[])
|
|||
pg_time_t now;
|
||||
WaitEventSet *wes;
|
||||
|
||||
now = MyStartTime;
|
||||
|
||||
/*
|
||||
* Re-open the error output files that were opened by SysLogger_Start().
|
||||
*
|
||||
* We expect this will always succeed, which is too optimistic, but if it
|
||||
* fails there's not a lot we can do to report the problem anyway. As
|
||||
* coded, we'll just crash on a null pointer dereference after failure...
|
||||
*/
|
||||
#ifdef EXEC_BACKEND
|
||||
syslogger_parseArgs(argc, argv);
|
||||
#endif /* EXEC_BACKEND */
|
||||
{
|
||||
SysloggerStartupData *slsdata = (SysloggerStartupData *) startup_data;
|
||||
|
||||
Assert(startup_data_len == sizeof(*slsdata));
|
||||
syslogFile = syslogger_fdopen(slsdata->syslogFile);
|
||||
csvlogFile = syslogger_fdopen(slsdata->csvlogFile);
|
||||
jsonlogFile = syslogger_fdopen(slsdata->jsonlogFile);
|
||||
}
|
||||
#else
|
||||
Assert(startup_data_len == 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now that we're done reading the startup data, release postmaster's
|
||||
* working memory context.
|
||||
*/
|
||||
if (PostmasterContext)
|
||||
{
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
PostmasterContext = NULL;
|
||||
}
|
||||
|
||||
now = MyStartTime;
|
||||
|
||||
MyBackendType = B_LOGGER;
|
||||
init_ps_display(NULL);
|
||||
|
@ -567,6 +596,9 @@ SysLogger_Start(void)
|
|||
{
|
||||
pid_t sysloggerPid;
|
||||
char *filename;
|
||||
#ifdef EXEC_BACKEND
|
||||
SysloggerStartupData startup_data;
|
||||
#endif /* EXEC_BACKEND */
|
||||
|
||||
if (!Logging_collector)
|
||||
return 0;
|
||||
|
@ -666,112 +698,95 @@ SysLogger_Start(void)
|
|||
}
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
switch ((sysloggerPid = syslogger_forkexec()))
|
||||
startup_data.syslogFile = syslogger_fdget(syslogFile);
|
||||
startup_data.csvlogFile = syslogger_fdget(csvlogFile);
|
||||
startup_data.jsonlogFile = syslogger_fdget(jsonlogFile);
|
||||
sysloggerPid = postmaster_child_launch(B_LOGGER, (char *) &startup_data, sizeof(startup_data), NULL);
|
||||
#else
|
||||
switch ((sysloggerPid = fork_process()))
|
||||
#endif
|
||||
sysloggerPid = postmaster_child_launch(B_LOGGER, NULL, 0, NULL);
|
||||
#endif /* EXEC_BACKEND */
|
||||
|
||||
if (sysloggerPid == -1)
|
||||
{
|
||||
case -1:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork system logger: %m")));
|
||||
return 0;
|
||||
|
||||
#ifndef EXEC_BACKEND
|
||||
case 0:
|
||||
/* in postmaster child ... */
|
||||
InitPostmasterChild();
|
||||
|
||||
/* Close the postmaster's sockets */
|
||||
ClosePostmasterPorts(true);
|
||||
|
||||
/* Drop our connection to postmaster's shared memory, as well */
|
||||
dsm_detach_all();
|
||||
PGSharedMemoryDetach();
|
||||
|
||||
/* do the work */
|
||||
SysLoggerMain(0, NULL);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/* success, in postmaster */
|
||||
|
||||
/* now we redirect stderr, if not done already */
|
||||
if (!redirection_done)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int fd;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Leave a breadcrumb trail when redirecting, in case the user
|
||||
* forgets that redirection is active and looks only at the
|
||||
* original stderr target file.
|
||||
*/
|
||||
ereport(LOG,
|
||||
(errmsg("redirecting log output to logging collector process"),
|
||||
errhint("Future log output will appear in directory \"%s\".",
|
||||
Log_directory)));
|
||||
|
||||
#ifndef WIN32
|
||||
fflush(stdout);
|
||||
if (dup2(syslogPipe[1], STDOUT_FILENO) < 0)
|
||||
ereport(FATAL,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not redirect stdout: %m")));
|
||||
fflush(stderr);
|
||||
if (dup2(syslogPipe[1], STDERR_FILENO) < 0)
|
||||
ereport(FATAL,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not redirect stderr: %m")));
|
||||
/* Now we are done with the write end of the pipe. */
|
||||
close(syslogPipe[1]);
|
||||
syslogPipe[1] = -1;
|
||||
#else
|
||||
|
||||
/*
|
||||
* open the pipe in binary mode and make sure stderr is binary
|
||||
* after it's been dup'ed into, to avoid disturbing the pipe
|
||||
* chunking protocol.
|
||||
*/
|
||||
fflush(stderr);
|
||||
fd = _open_osfhandle((intptr_t) syslogPipe[1],
|
||||
_O_APPEND | _O_BINARY);
|
||||
if (dup2(fd, STDERR_FILENO) < 0)
|
||||
ereport(FATAL,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not redirect stderr: %m")));
|
||||
close(fd);
|
||||
_setmode(STDERR_FILENO, _O_BINARY);
|
||||
|
||||
/*
|
||||
* Now we are done with the write end of the pipe.
|
||||
* CloseHandle() must not be called because the preceding
|
||||
* close() closes the underlying handle.
|
||||
*/
|
||||
syslogPipe[1] = 0;
|
||||
#endif
|
||||
redirection_done = true;
|
||||
}
|
||||
|
||||
/* postmaster will never write the file(s); close 'em */
|
||||
fclose(syslogFile);
|
||||
syslogFile = NULL;
|
||||
if (csvlogFile != NULL)
|
||||
{
|
||||
fclose(csvlogFile);
|
||||
csvlogFile = NULL;
|
||||
}
|
||||
if (jsonlogFile != NULL)
|
||||
{
|
||||
fclose(jsonlogFile);
|
||||
jsonlogFile = NULL;
|
||||
}
|
||||
return (int) sysloggerPid;
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork system logger: %m")));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we should never reach here */
|
||||
return 0;
|
||||
/* success, in postmaster */
|
||||
|
||||
/* now we redirect stderr, if not done already */
|
||||
if (!redirection_done)
|
||||
{
|
||||
#ifdef WIN32
|
||||
int fd;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Leave a breadcrumb trail when redirecting, in case the user forgets
|
||||
* that redirection is active and looks only at the original stderr
|
||||
* target file.
|
||||
*/
|
||||
ereport(LOG,
|
||||
(errmsg("redirecting log output to logging collector process"),
|
||||
errhint("Future log output will appear in directory \"%s\".",
|
||||
Log_directory)));
|
||||
|
||||
#ifndef WIN32
|
||||
fflush(stdout);
|
||||
if (dup2(syslogPipe[1], STDOUT_FILENO) < 0)
|
||||
ereport(FATAL,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not redirect stdout: %m")));
|
||||
fflush(stderr);
|
||||
if (dup2(syslogPipe[1], STDERR_FILENO) < 0)
|
||||
ereport(FATAL,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not redirect stderr: %m")));
|
||||
/* Now we are done with the write end of the pipe. */
|
||||
close(syslogPipe[1]);
|
||||
syslogPipe[1] = -1;
|
||||
#else
|
||||
|
||||
/*
|
||||
* open the pipe in binary mode and make sure stderr is binary after
|
||||
* it's been dup'ed into, to avoid disturbing the pipe chunking
|
||||
* protocol.
|
||||
*/
|
||||
fflush(stderr);
|
||||
fd = _open_osfhandle((intptr_t) syslogPipe[1],
|
||||
_O_APPEND | _O_BINARY);
|
||||
if (dup2(fd, STDERR_FILENO) < 0)
|
||||
ereport(FATAL,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not redirect stderr: %m")));
|
||||
close(fd);
|
||||
_setmode(STDERR_FILENO, _O_BINARY);
|
||||
|
||||
/*
|
||||
* Now we are done with the write end of the pipe. CloseHandle() must
|
||||
* not be called because the preceding close() closes the underlying
|
||||
* handle.
|
||||
*/
|
||||
syslogPipe[1] = 0;
|
||||
#endif
|
||||
redirection_done = true;
|
||||
}
|
||||
|
||||
/* postmaster will never write the file(s); close 'em */
|
||||
fclose(syslogFile);
|
||||
syslogFile = NULL;
|
||||
if (csvlogFile != NULL)
|
||||
{
|
||||
fclose(csvlogFile);
|
||||
csvlogFile = NULL;
|
||||
}
|
||||
if (jsonlogFile != NULL)
|
||||
{
|
||||
fclose(jsonlogFile);
|
||||
jsonlogFile = NULL;
|
||||
}
|
||||
return (int) sysloggerPid;
|
||||
}
|
||||
|
||||
|
||||
|
@ -830,69 +845,6 @@ syslogger_fdopen(int fd)
|
|||
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
* syslogger_forkexec() -
|
||||
*
|
||||
* Format up the arglist for, then fork and exec, a syslogger process
|
||||
*/
|
||||
static pid_t
|
||||
syslogger_forkexec(void)
|
||||
{
|
||||
char *av[10];
|
||||
int ac = 0;
|
||||
char filenobuf[32];
|
||||
char csvfilenobuf[32];
|
||||
char jsonfilenobuf[32];
|
||||
|
||||
av[ac++] = "postgres";
|
||||
av[ac++] = "--forklog";
|
||||
av[ac++] = NULL; /* filled in by postmaster_forkexec */
|
||||
|
||||
/* static variables (those not passed by write_backend_variables) */
|
||||
snprintf(filenobuf, sizeof(filenobuf), "%d",
|
||||
syslogger_fdget(syslogFile));
|
||||
av[ac++] = filenobuf;
|
||||
snprintf(csvfilenobuf, sizeof(csvfilenobuf), "%d",
|
||||
syslogger_fdget(csvlogFile));
|
||||
av[ac++] = csvfilenobuf;
|
||||
snprintf(jsonfilenobuf, sizeof(jsonfilenobuf), "%d",
|
||||
syslogger_fdget(jsonlogFile));
|
||||
av[ac++] = jsonfilenobuf;
|
||||
|
||||
av[ac] = NULL;
|
||||
Assert(ac < lengthof(av));
|
||||
|
||||
return postmaster_forkexec(ac, av);
|
||||
}
|
||||
|
||||
/*
|
||||
* syslogger_parseArgs() -
|
||||
*
|
||||
* Extract data from the arglist for exec'ed syslogger process
|
||||
*/
|
||||
static void
|
||||
syslogger_parseArgs(int argc, char *argv[])
|
||||
{
|
||||
int fd;
|
||||
|
||||
Assert(argc == 6);
|
||||
argv += 3;
|
||||
|
||||
/*
|
||||
* Re-open the error output files that were opened by SysLogger_Start().
|
||||
*
|
||||
* We expect this will always succeed, which is too optimistic, but if it
|
||||
* fails there's not a lot we can do to report the problem anyway. As
|
||||
* coded, we'll just crash on a null pointer dereference after failure...
|
||||
*/
|
||||
fd = atoi(*argv++);
|
||||
syslogFile = syslogger_fdopen(fd);
|
||||
fd = atoi(*argv++);
|
||||
csvlogFile = syslogger_fdopen(fd);
|
||||
fd = atoi(*argv++);
|
||||
jsonlogFile = syslogger_fdopen(fd);
|
||||
}
|
||||
#endif /* EXEC_BACKEND */
|
||||
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "common/blkreftable.h"
|
||||
#include "libpq/pqsignal.h"
|
||||
#include "miscadmin.h"
|
||||
#include "postmaster/auxprocess.h"
|
||||
#include "postmaster/interrupt.h"
|
||||
#include "postmaster/walsummarizer.h"
|
||||
#include "replication/walreceiver.h"
|
||||
|
@ -206,7 +207,7 @@ WalSummarizerShmemInit(void)
|
|||
* Entry point for walsummarizer process.
|
||||
*/
|
||||
void
|
||||
WalSummarizerMain(void)
|
||||
WalSummarizerMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
MemoryContext context;
|
||||
|
@ -228,6 +229,11 @@ WalSummarizerMain(void)
|
|||
XLogRecPtr switch_lsn = InvalidXLogRecPtr;
|
||||
TimeLineID switch_tli = 0;
|
||||
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
MyBackendType = B_WAL_SUMMARIZER;
|
||||
AuxiliaryProcessMainCommon();
|
||||
|
||||
ereport(DEBUG1,
|
||||
(errmsg_internal("WAL summarizer started")));
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "libpq/pqsignal.h"
|
||||
#include "miscadmin.h"
|
||||
#include "pgstat.h"
|
||||
#include "postmaster/auxprocess.h"
|
||||
#include "postmaster/interrupt.h"
|
||||
#include "postmaster/walwriter.h"
|
||||
#include "storage/bufmgr.h"
|
||||
|
@ -85,13 +86,18 @@ int WalWriterFlushAfter = DEFAULT_WAL_WRITER_FLUSH_AFTER;
|
|||
* basic execution environment, but not enabled signals yet.
|
||||
*/
|
||||
void
|
||||
WalWriterMain(void)
|
||||
WalWriterMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
MemoryContext walwriter_context;
|
||||
int left_till_hibernate;
|
||||
bool hibernating;
|
||||
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
MyBackendType = B_WAL_WRITER;
|
||||
AuxiliaryProcessMainCommon();
|
||||
|
||||
/*
|
||||
* Properly accept or ignore signals the postmaster might send us
|
||||
*
|
||||
|
|
|
@ -139,11 +139,6 @@ typedef struct RemoteSlot
|
|||
ReplicationSlotInvalidationCause invalidated;
|
||||
} RemoteSlot;
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
static pid_t slotsyncworker_forkexec(void);
|
||||
#endif
|
||||
NON_EXEC_STATIC void ReplSlotSyncWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
|
||||
static void slotsync_failure_callback(int code, Datum arg);
|
||||
|
||||
/*
|
||||
|
@ -1113,8 +1108,8 @@ wait_for_slot_activity(bool some_slot_updated)
|
|||
* It connects to the primary server, fetches logical failover slots
|
||||
* information periodically in order to create and sync the slots.
|
||||
*/
|
||||
NON_EXEC_STATIC void
|
||||
ReplSlotSyncWorkerMain(int argc, char *argv[])
|
||||
void
|
||||
ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
WalReceiverConn *wrconn = NULL;
|
||||
char *dbname;
|
||||
|
@ -1122,6 +1117,8 @@ ReplSlotSyncWorkerMain(int argc, char *argv[])
|
|||
sigjmp_buf local_sigjmp_buf;
|
||||
StringInfoData app_name;
|
||||
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
MyBackendType = B_SLOTSYNC_WORKER;
|
||||
|
||||
init_ps_display(NULL);
|
||||
|
@ -1299,67 +1296,6 @@ ReplSlotSyncWorkerMain(int argc, char *argv[])
|
|||
Assert(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main entry point for slot sync worker process, to be called from the
|
||||
* postmaster.
|
||||
*/
|
||||
int
|
||||
StartSlotSyncWorker(void)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
switch ((pid = slotsyncworker_forkexec()))
|
||||
{
|
||||
#else
|
||||
switch ((pid = fork_process()))
|
||||
{
|
||||
case 0:
|
||||
/* in postmaster child ... */
|
||||
InitPostmasterChild();
|
||||
|
||||
/* Close the postmaster's sockets */
|
||||
ClosePostmasterPorts(false);
|
||||
|
||||
ReplSlotSyncWorkerMain(0, NULL);
|
||||
break;
|
||||
#endif
|
||||
case -1:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork slot sync worker process: %m")));
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return (int) pid;
|
||||
}
|
||||
|
||||
/* shouldn't get here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
/*
|
||||
* The forkexec routine for the slot sync worker process.
|
||||
*
|
||||
* Format up the arglist, then fork and exec.
|
||||
*/
|
||||
static pid_t
|
||||
slotsyncworker_forkexec(void)
|
||||
{
|
||||
char *av[10];
|
||||
int ac = 0;
|
||||
|
||||
av[ac++] = "postgres";
|
||||
av[ac++] = "--forkssworker";
|
||||
av[ac++] = NULL; /* filled in by postmaster_forkexec */
|
||||
av[ac] = NULL;
|
||||
|
||||
Assert(ac < lengthof(av));
|
||||
|
||||
return postmaster_forkexec(ac, av);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Shut down the slot sync worker.
|
||||
*/
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include "libpq/pqsignal.h"
|
||||
#include "miscadmin.h"
|
||||
#include "pgstat.h"
|
||||
#include "postmaster/auxprocess.h"
|
||||
#include "postmaster/interrupt.h"
|
||||
#include "replication/walreceiver.h"
|
||||
#include "replication/walsender.h"
|
||||
|
@ -179,7 +180,7 @@ ProcessWalRcvInterrupts(void)
|
|||
|
||||
/* Main entry point for walreceiver process */
|
||||
void
|
||||
WalReceiverMain(void)
|
||||
WalReceiverMain(char *startup_data, size_t startup_data_len)
|
||||
{
|
||||
char conninfo[MAXCONNINFO];
|
||||
char *tmp_conninfo;
|
||||
|
@ -195,6 +196,11 @@ WalReceiverMain(void)
|
|||
char *sender_host = NULL;
|
||||
int sender_port = 0;
|
||||
|
||||
Assert(startup_data_len == 0);
|
||||
|
||||
MyBackendType = B_WAL_RECEIVER;
|
||||
AuxiliaryProcessMainCommon();
|
||||
|
||||
/*
|
||||
* WalRcv should be set up already (if we are a backend, we inherit this
|
||||
* by fork() or EXEC_BACKEND mechanism from the postmaster).
|
||||
|
|
|
@ -45,6 +45,7 @@ volatile uint32 CritSectionCount = 0;
|
|||
int MyProcPid;
|
||||
pg_time_t MyStartTime;
|
||||
TimestampTz MyStartTimestamp;
|
||||
struct ClientSocket *MyClientSocket;
|
||||
struct Port *MyProcPort;
|
||||
int32 MyCancelKey;
|
||||
int MyPMChildSlot;
|
||||
|
|
|
@ -50,18 +50,14 @@ extern PGDLLIMPORT int Log_autovacuum_min_duration;
|
|||
/* Status inquiry functions */
|
||||
extern bool AutoVacuumingActive(void);
|
||||
|
||||
/* Functions to start autovacuum process, called from postmaster */
|
||||
/* called from postmaster at server startup */
|
||||
extern void autovac_init(void);
|
||||
extern int StartAutoVacLauncher(void);
|
||||
extern int StartAutoVacWorker(void);
|
||||
|
||||
/* called from postmaster when a worker could not be forked */
|
||||
extern void AutoVacWorkerFailed(void);
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
#endif
|
||||
extern void AutoVacLauncherMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
extern void AutoVacWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
|
||||
extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type,
|
||||
Oid relationId, BlockNumber blkno);
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
#ifndef AUXPROCESS_H
|
||||
#define AUXPROCESS_H
|
||||
|
||||
#include "miscadmin.h"
|
||||
|
||||
extern void AuxiliaryProcessMain(BackendType auxtype) pg_attribute_noreturn();
|
||||
extern void AuxiliaryProcessMainCommon(void);
|
||||
|
||||
#endif /* AUXPROCESS_H */
|
||||
|
|
|
@ -55,6 +55,6 @@ extern void ForgetUnstartedBackgroundWorkers(void);
|
|||
extern void ResetBackgroundWorkerCrashTimes(void);
|
||||
|
||||
/* Entry point for background worker processes */
|
||||
extern void BackgroundWorkerMain(void) pg_attribute_noreturn();
|
||||
extern void BackgroundWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
|
||||
#endif /* BGWORKER_INTERNALS_H */
|
||||
|
|
|
@ -27,8 +27,8 @@ extern PGDLLIMPORT int CheckPointTimeout;
|
|||
extern PGDLLIMPORT int CheckPointWarning;
|
||||
extern PGDLLIMPORT double CheckPointCompletionTarget;
|
||||
|
||||
extern void BackgroundWriterMain(void) pg_attribute_noreturn();
|
||||
extern void CheckpointerMain(void) pg_attribute_noreturn();
|
||||
extern void BackgroundWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
extern void CheckpointerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
|
||||
extern void RequestCheckpoint(int flags);
|
||||
extern void CheckpointWriteDelay(int flags, double progress);
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
extern Size PgArchShmemSize(void);
|
||||
extern void PgArchShmemInit(void);
|
||||
extern bool PgArchCanRestart(void);
|
||||
extern void PgArchiverMain(void) pg_attribute_noreturn();
|
||||
extern void PgArchiverMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
extern void PgArchWakeup(void);
|
||||
extern void PgArchForceDirScan(void);
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#ifndef _POSTMASTER_H
|
||||
#define _POSTMASTER_H
|
||||
|
||||
#include "miscadmin.h"
|
||||
|
||||
/* GUC options */
|
||||
extern PGDLLIMPORT bool EnableSSL;
|
||||
extern PGDLLIMPORT int SuperuserReservedConnections;
|
||||
|
@ -58,11 +60,9 @@ extern int MaxLivePostmasterChildren(void);
|
|||
|
||||
extern bool PostmasterMarkPIDForWorkerNotify(int);
|
||||
|
||||
extern void BackendMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
|
||||
extern pid_t postmaster_forkexec(int argc, char *argv[]);
|
||||
extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
|
||||
extern Size ShmemBackendArraySize(void);
|
||||
extern void ShmemBackendArrayAllocation(void);
|
||||
|
||||
|
@ -71,6 +71,16 @@ extern void pgwin32_register_deadchild_callback(HANDLE procHandle, DWORD procId)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* defined in globals.c */
|
||||
extern struct ClientSocket *MyClientSocket;
|
||||
|
||||
/* prototypes for functions in launch_backend.c */
|
||||
extern pid_t postmaster_child_launch(BackendType child_type, char *startup_data, size_t startup_data_len, struct ClientSocket *sock);
|
||||
const char *PostmasterChildName(BackendType child_type);
|
||||
#ifdef EXEC_BACKEND
|
||||
extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note: MAX_BACKENDS is limited to 2^18-1 because that's the width reserved
|
||||
* for buffer references in buf_internals.h. This limitation could be lifted
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
extern PGDLLIMPORT int log_startup_progress_interval;
|
||||
|
||||
extern void HandleStartupProcInterrupts(void);
|
||||
extern void StartupProcessMain(void) pg_attribute_noreturn();
|
||||
extern void StartupProcessMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
extern void PreRestoreCommand(void);
|
||||
extern void PostRestoreCommand(void);
|
||||
extern bool IsPromoteSignaled(void);
|
||||
|
|
|
@ -86,9 +86,7 @@ extern int SysLogger_Start(void);
|
|||
|
||||
extern void write_syslogger_file(const char *buffer, int count, int destination);
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
#endif
|
||||
extern void SysLoggerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
|
||||
extern bool CheckLogrotateSignal(void);
|
||||
extern void RemoveLogrotateSignalFiles(void);
|
||||
|
|
|
@ -21,7 +21,7 @@ extern PGDLLIMPORT int wal_summary_keep_time;
|
|||
|
||||
extern Size WalSummarizerShmemSize(void);
|
||||
extern void WalSummarizerShmemInit(void);
|
||||
extern void WalSummarizerMain(void) pg_attribute_noreturn();
|
||||
extern void WalSummarizerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
|
||||
extern void GetWalSummarizerState(TimeLineID *summarized_tli,
|
||||
XLogRecPtr *summarized_lsn,
|
||||
|
|
|
@ -18,6 +18,6 @@
|
|||
extern PGDLLIMPORT int WalWriterDelay;
|
||||
extern PGDLLIMPORT int WalWriterFlushAfter;
|
||||
|
||||
extern void WalWriterMain(void) pg_attribute_noreturn();
|
||||
extern void WalWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
|
||||
#endif /* _WALWRITER_H */
|
||||
|
|
|
@ -26,9 +26,7 @@ extern PGDLLIMPORT char *PrimarySlotName;
|
|||
extern char *CheckAndGetDbnameFromConninfo(void);
|
||||
extern bool ValidateSlotSyncParams(int elevel);
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
extern void ReplSlotSyncWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
||||
#endif
|
||||
extern void ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
extern int StartSlotSyncWorker(void);
|
||||
|
||||
extern void ShutDownSlotSync(void);
|
||||
|
|
|
@ -483,7 +483,7 @@ walrcv_clear_result(WalRcvExecResult *walres)
|
|||
}
|
||||
|
||||
/* prototypes for functions in walreceiver.c */
|
||||
extern void WalReceiverMain(void) pg_attribute_noreturn();
|
||||
extern void WalReceiverMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||
extern void ProcessWalRcvInterrupts(void);
|
||||
extern void WalRcvForceReply(void);
|
||||
|
||||
|
|
|
@ -231,6 +231,7 @@ BY_HANDLE_FILE_INFORMATION
|
|||
Backend
|
||||
BackendId
|
||||
BackendParameters
|
||||
BackendStartupData
|
||||
BackendState
|
||||
BackendType
|
||||
BackgroundWorker
|
||||
|
@ -2136,6 +2137,7 @@ PortalStrategy
|
|||
PostParseColumnRefHook
|
||||
PostgresPollingStatusType
|
||||
PostingItem
|
||||
PostmasterChildType
|
||||
PreParseColumnRefHook
|
||||
PredClass
|
||||
PredIterInfo
|
||||
|
@ -3259,6 +3261,7 @@ check_network_data
|
|||
check_object_relabel_type
|
||||
check_password_hook_type
|
||||
check_ungrouped_columns_context
|
||||
child_process_kind
|
||||
chr
|
||||
cmpEntriesArg
|
||||
codes_t
|
||||
|
@ -4042,6 +4045,7 @@ BlockRefTableReader
|
|||
BlockRefTableSerializedEntry
|
||||
BlockRefTableWriter
|
||||
SummarizerReadLocalXLogPrivate
|
||||
SysloggerStartupData
|
||||
WalSummarizerData
|
||||
WalSummaryFile
|
||||
WalSummaryIO
|
||||
|
|
Loading…
Reference in New Issue