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 "nodes/makefuncs.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
#include "postmaster/autovacuum.h"
|
#include "postmaster/autovacuum.h"
|
||||||
#include "postmaster/fork_process.h"
|
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
|
@ -311,13 +310,6 @@ static WorkerInfo MyWorkerInfo = NULL;
|
||||||
/* PID of launcher, valid only in worker while shutting down */
|
/* PID of launcher, valid only in worker while shutting down */
|
||||||
int AutovacuumLauncherPid = 0;
|
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 Oid do_start_worker(void);
|
||||||
static void HandleAutoVacLauncherInterrupts(void);
|
static void HandleAutoVacLauncherInterrupts(void);
|
||||||
static void AutoVacLauncherShutdown(void) pg_attribute_noreturn();
|
static void AutoVacLauncherShutdown(void) pg_attribute_noreturn();
|
||||||
|
@ -361,76 +353,23 @@ static void avl_sigusr2_handler(SIGNAL_ARGS);
|
||||||
* AUTOVACUUM LAUNCHER CODE
|
* AUTOVACUUM LAUNCHER CODE
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
|
||||||
/*
|
/*
|
||||||
* forkexec routine for the autovacuum launcher process.
|
* Main entry point for the autovacuum launcher process.
|
||||||
*
|
|
||||||
* Format up the arglist, then fork and exec.
|
|
||||||
*/
|
*/
|
||||||
static pid_t
|
void
|
||||||
avlauncher_forkexec(void)
|
AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
|
||||||
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[])
|
|
||||||
{
|
{
|
||||||
sigjmp_buf local_sigjmp_buf;
|
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;
|
MyBackendType = B_AUTOVAC_LAUNCHER;
|
||||||
init_ps_display(NULL);
|
init_ps_display(NULL);
|
||||||
|
|
||||||
|
@ -1412,78 +1351,24 @@ avl_sigusr2_handler(SIGNAL_ARGS)
|
||||||
* AUTOVACUUM WORKER CODE
|
* AUTOVACUUM WORKER CODE
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
|
||||||
/*
|
/*
|
||||||
* forkexec routines for the autovacuum worker.
|
* Main entry point for autovacuum worker processes.
|
||||||
*
|
|
||||||
* Format up the arglist, then fork and exec.
|
|
||||||
*/
|
*/
|
||||||
static pid_t
|
void
|
||||||
avworker_forkexec(void)
|
AutoVacWorkerMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
|
||||||
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[])
|
|
||||||
{
|
{
|
||||||
sigjmp_buf local_sigjmp_buf;
|
sigjmp_buf local_sigjmp_buf;
|
||||||
Oid dbid;
|
Oid dbid;
|
||||||
|
|
||||||
|
Assert(startup_data_len == 0);
|
||||||
|
|
||||||
|
/* Release postmaster's working memory context */
|
||||||
|
if (PostmasterContext)
|
||||||
|
{
|
||||||
|
MemoryContextDelete(PostmasterContext);
|
||||||
|
PostmasterContext = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
MyBackendType = B_AUTOVAC_WORKER;
|
MyBackendType = B_AUTOVAC_WORKER;
|
||||||
init_ps_display(NULL);
|
init_ps_display(NULL);
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/procsignal.h"
|
#include "storage/procsignal.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/ps_status.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,
|
* Common initialization code for auxiliary processes, such as the bgwriter,
|
||||||
* walwriter, walreceiver, bootstrapper and the shared memory checker code.
|
* walwriter, walreceiver, and the startup process.
|
||||||
*
|
|
||||||
* This code is here just because of historical reasons.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
AuxiliaryProcessMain(BackendType auxtype)
|
AuxiliaryProcessMainCommon(void)
|
||||||
{
|
{
|
||||||
Assert(IsUnderPostmaster);
|
Assert(IsUnderPostmaster);
|
||||||
|
|
||||||
MyBackendType = auxtype;
|
/* Release postmaster's working memory context */
|
||||||
|
if (PostmasterContext)
|
||||||
|
{
|
||||||
|
MemoryContextDelete(PostmasterContext);
|
||||||
|
PostmasterContext = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
init_ps_display(NULL);
|
init_ps_display(NULL);
|
||||||
|
|
||||||
|
@ -84,41 +88,6 @@ AuxiliaryProcessMain(BackendType auxtype)
|
||||||
before_shmem_exit(ShutdownAuxiliaryProcess, 0);
|
before_shmem_exit(ShutdownAuxiliaryProcess, 0);
|
||||||
|
|
||||||
SetProcessingMode(NormalProcessing);
|
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.
|
* Main entry point for background worker processes.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
BackgroundWorkerMain(void)
|
BackgroundWorkerMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
sigjmp_buf local_sigjmp_buf;
|
sigjmp_buf local_sigjmp_buf;
|
||||||
BackgroundWorker *worker = MyBgworkerEntry;
|
BackgroundWorker *worker;
|
||||||
bgworker_main_type entrypt;
|
bgworker_main_type entrypt;
|
||||||
|
|
||||||
if (worker == NULL)
|
if (startup_data == NULL)
|
||||||
elog(FATAL, "unable to find bgworker entry");
|
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;
|
MyBackendType = B_BG_WORKER;
|
||||||
init_ps_display(worker->bgw_name);
|
init_ps_display(worker->bgw_name);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
|
#include "postmaster/auxprocess.h"
|
||||||
#include "postmaster/bgwriter.h"
|
#include "postmaster/bgwriter.h"
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "storage/buf_internals.h"
|
#include "storage/buf_internals.h"
|
||||||
|
@ -83,13 +84,18 @@ static XLogRecPtr last_snapshot_lsn = InvalidXLogRecPtr;
|
||||||
* basic execution environment, but not enabled signals yet.
|
* basic execution environment, but not enabled signals yet.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
BackgroundWriterMain(void)
|
BackgroundWriterMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
sigjmp_buf local_sigjmp_buf;
|
sigjmp_buf local_sigjmp_buf;
|
||||||
MemoryContext bgwriter_context;
|
MemoryContext bgwriter_context;
|
||||||
bool prev_hibernate;
|
bool prev_hibernate;
|
||||||
WritebackContext wb_context;
|
WritebackContext wb_context;
|
||||||
|
|
||||||
|
Assert(startup_data_len == 0);
|
||||||
|
|
||||||
|
MyBackendType = B_BG_WRITER;
|
||||||
|
AuxiliaryProcessMainCommon();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Properly accept or ignore signals that might be sent to us.
|
* Properly accept or ignore signals that might be sent to us.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
|
#include "postmaster/auxprocess.h"
|
||||||
#include "postmaster/bgwriter.h"
|
#include "postmaster/bgwriter.h"
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "replication/syncrep.h"
|
#include "replication/syncrep.h"
|
||||||
|
@ -169,11 +170,16 @@ static void ReqCheckpointHandler(SIGNAL_ARGS);
|
||||||
* basic execution environment, but not enabled signals yet.
|
* basic execution environment, but not enabled signals yet.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
CheckpointerMain(void)
|
CheckpointerMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
sigjmp_buf local_sigjmp_buf;
|
sigjmp_buf local_sigjmp_buf;
|
||||||
MemoryContext checkpointer_context;
|
MemoryContext checkpointer_context;
|
||||||
|
|
||||||
|
Assert(startup_data_len == 0);
|
||||||
|
|
||||||
|
MyBackendType = B_CHECKPOINTER;
|
||||||
|
AuxiliaryProcessMainCommon();
|
||||||
|
|
||||||
CheckpointerShmem->checkpointer_pid = MyProcPid;
|
CheckpointerShmem->checkpointer_pid = MyProcPid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -49,7 +49,9 @@
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
#include "postmaster/startup.h"
|
#include "postmaster/startup.h"
|
||||||
#include "postmaster/syslogger.h"
|
#include "postmaster/syslogger.h"
|
||||||
|
#include "postmaster/walsummarizer.h"
|
||||||
#include "postmaster/walwriter.h"
|
#include "postmaster/walwriter.h"
|
||||||
|
#include "replication/slotsync.h"
|
||||||
#include "replication/walreceiver.h"
|
#include "replication/walreceiver.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
|
@ -89,13 +91,6 @@ typedef int InheritableSocket;
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool has_client_sock;
|
|
||||||
ClientSocket client_sock;
|
|
||||||
InheritableSocket inh_sock;
|
|
||||||
|
|
||||||
bool has_bgworker;
|
|
||||||
BackgroundWorker bgworker;
|
|
||||||
|
|
||||||
char DataDir[MAXPGPATH];
|
char DataDir[MAXPGPATH];
|
||||||
int32 MyCancelKey;
|
int32 MyCancelKey;
|
||||||
int MyPMChildSlot;
|
int MyPMChildSlot;
|
||||||
|
@ -138,22 +133,144 @@ typedef struct
|
||||||
#endif
|
#endif
|
||||||
char my_exec_path[MAXPGPATH];
|
char my_exec_path[MAXPGPATH];
|
||||||
char pkglib_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;
|
} BackendParameters;
|
||||||
|
|
||||||
#define SizeOfBackendParameters(startup_data_len) (offsetof(BackendParameters, startup_data) + startup_data_len)
|
#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 read_backend_variables(char *id, char **startup_data, size_t *startup_data_len);
|
||||||
static void restore_backend_variables(BackendParameters *param, ClientSocket **client_sock, BackgroundWorker **worker);
|
static void restore_backend_variables(BackendParameters *param);
|
||||||
|
|
||||||
#ifndef WIN32
|
static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock,
|
||||||
static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker);
|
#ifdef WIN32
|
||||||
#else
|
HANDLE childProcess, pid_t childPid,
|
||||||
static bool save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker,
|
|
||||||
HANDLE childProcess, pid_t childPid);
|
|
||||||
#endif
|
#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
|
#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
|
* - writes out backend variables to the parameter file
|
||||||
* - fork():s, and then exec():s the child process
|
* - fork():s, and then exec():s the child process
|
||||||
*/
|
*/
|
||||||
pid_t
|
static pid_t
|
||||||
internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker)
|
internal_forkexec(const char *child_kind, char *startup_data, size_t startup_data_len, ClientSocket *client_sock)
|
||||||
{
|
{
|
||||||
static unsigned long tmpBackendFileNum = 0;
|
static unsigned long tmpBackendFileNum = 0;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
char tmpfilename[MAXPGPATH];
|
char tmpfilename[MAXPGPATH];
|
||||||
BackendParameters param;
|
size_t paramsz;
|
||||||
|
BackendParameters *param;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
char *argv[4];
|
||||||
|
char forkav[MAXPGPATH];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure padding bytes are initialized, to prevent Valgrind from
|
* Use palloc0 to make sure padding bytes are initialized, to prevent
|
||||||
* complaining about writing uninitialized bytes to the file. This isn't
|
* Valgrind from complaining about writing uninitialized bytes to the
|
||||||
* performance critical, and the win32 implementation initializes the
|
* file. This isn't performance critical, and the win32 implementation
|
||||||
* padding bytes to zeros, so do it even when not using Valgrind.
|
* initializes the padding bytes to zeros, so do it even when not using
|
||||||
|
* Valgrind.
|
||||||
*/
|
*/
|
||||||
memset(¶m, 0, sizeof(BackendParameters));
|
paramsz = SizeOfBackendParameters(startup_data_len);
|
||||||
|
param = palloc0(paramsz);
|
||||||
if (!save_backend_variables(¶m, client_sock, worker))
|
if (!save_backend_variables(param, client_sock, startup_data, startup_data_len))
|
||||||
|
{
|
||||||
|
pfree(param);
|
||||||
return -1; /* log made by save_backend_variables */
|
return -1; /* log made by save_backend_variables */
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate name for temp file */
|
/* Calculate name for temp file */
|
||||||
snprintf(tmpfilename, MAXPGPATH, "%s/%s.backend_var.%d.%lu",
|
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(),
|
(errcode_for_file_access(),
|
||||||
errmsg("could not create file \"%s\": %m",
|
errmsg("could not create file \"%s\": %m",
|
||||||
tmpfilename)));
|
tmpfilename)));
|
||||||
|
pfree(param);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(¶m, sizeof(param), 1, fp) != 1)
|
if (fwrite(param, paramsz, 1, fp) != 1)
|
||||||
{
|
{
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errcode_for_file_access(),
|
(errcode_for_file_access(),
|
||||||
errmsg("could not write to file \"%s\": %m", tmpfilename)));
|
errmsg("could not write to file \"%s\": %m", tmpfilename)));
|
||||||
FreeFile(fp);
|
FreeFile(fp);
|
||||||
|
pfree(param);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
pfree(param);
|
||||||
|
|
||||||
/* Release file */
|
/* Release file */
|
||||||
if (FreeFile(fp))
|
if (FreeFile(fp))
|
||||||
|
@ -226,14 +353,13 @@ internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundW
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure caller set up argv properly */
|
/* set up argv properly */
|
||||||
Assert(argc >= 3);
|
argv[0] = "postgres";
|
||||||
Assert(argv[argc] == NULL);
|
snprintf(forkav, MAXPGPATH, "--forkchild=%s", child_kind);
|
||||||
Assert(strncmp(argv[1], "--fork", 6) == 0);
|
argv[1] = forkav;
|
||||||
Assert(argv[2] == NULL);
|
/* Insert temp file name after --forkchild argument */
|
||||||
|
|
||||||
/* Insert temp file name after --fork argument */
|
|
||||||
argv[2] = tmpfilename;
|
argv[2] = tmpfilename;
|
||||||
|
argv[3] = NULL;
|
||||||
|
|
||||||
/* Fire off execv in child */
|
/* Fire off execv in child */
|
||||||
if ((pid = fork_process()) == 0)
|
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
|
* - resumes execution of the new process once the backend parameter
|
||||||
* file is complete.
|
* file is complete.
|
||||||
*/
|
*/
|
||||||
pid_t
|
static pid_t
|
||||||
internal_forkexec(int argc, char *argv[], ClientSocket *client_sock, BackgroundWorker *worker)
|
internal_forkexec(const char *child_kind, char *startup_data, size_t startup_data_len, ClientSocket *client_sock)
|
||||||
{
|
{
|
||||||
int retry_count = 0;
|
int retry_count = 0;
|
||||||
STARTUPINFO si;
|
STARTUPINFO si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
char cmdLine[MAXPGPATH * 2];
|
char cmdLine[MAXPGPATH * 2];
|
||||||
HANDLE paramHandle;
|
HANDLE paramHandle;
|
||||||
BackendParameters *param;
|
BackendParameters *param;
|
||||||
SECURITY_ATTRIBUTES sa;
|
SECURITY_ATTRIBUTES sa;
|
||||||
|
size_t paramsz;
|
||||||
char paramHandleStr[32];
|
char paramHandleStr[32];
|
||||||
|
int l;
|
||||||
|
|
||||||
/* Make sure caller set up argv properly */
|
paramsz = SizeOfBackendParameters(startup_data_len);
|
||||||
Assert(argc >= 3);
|
|
||||||
Assert(argv[argc] == NULL);
|
|
||||||
Assert(strncmp(argv[1], "--fork", 6) == 0);
|
|
||||||
Assert(argv[2] == NULL);
|
|
||||||
|
|
||||||
/* Resume here if we need to retry */
|
/* Resume here if we need to retry */
|
||||||
retry:
|
retry:
|
||||||
|
@ -293,7 +415,7 @@ retry:
|
||||||
&sa,
|
&sa,
|
||||||
PAGE_READWRITE,
|
PAGE_READWRITE,
|
||||||
0,
|
0,
|
||||||
sizeof(BackendParameters),
|
paramsz,
|
||||||
NULL);
|
NULL);
|
||||||
if (paramHandle == INVALID_HANDLE_VALUE)
|
if (paramHandle == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
|
@ -302,8 +424,7 @@ retry:
|
||||||
GetLastError())));
|
GetLastError())));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, paramsz);
|
||||||
param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters));
|
|
||||||
if (!param)
|
if (!param)
|
||||||
{
|
{
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
|
@ -313,25 +434,15 @@ retry:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert temp file name after --fork argument */
|
/* Format the cmd line */
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
sprintf(paramHandleStr, "%llu", (LONG_PTR) paramHandle);
|
sprintf(paramHandleStr, "%llu", (LONG_PTR) paramHandle);
|
||||||
#else
|
#else
|
||||||
sprintf(paramHandleStr, "%lu", (DWORD) paramHandle);
|
sprintf(paramHandleStr, "%lu", (DWORD) paramHandle);
|
||||||
#endif
|
#endif
|
||||||
argv[2] = paramHandleStr;
|
l = snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\" --forkchild=\"%s\" %s",
|
||||||
|
postgres_exec_path, child_kind, paramHandleStr);
|
||||||
/* Format the cmd line */
|
if (l >= sizeof(cmdLine))
|
||||||
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')
|
|
||||||
{
|
{
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("subprocess command line too long")));
|
(errmsg("subprocess command line too long")));
|
||||||
|
@ -359,7 +470,7 @@ retry:
|
||||||
return -1;
|
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
|
* log made by save_backend_variables, but we have to clean up the
|
||||||
|
@ -445,6 +556,119 @@ retry:
|
||||||
}
|
}
|
||||||
#endif /* WIN32 */
|
#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
|
* The following need to be available to the save/restore_backend_variables
|
||||||
* functions. They are marked NON_EXEC_STATIC in their home modules.
|
* 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 */
|
/* Save critical backend variables into the BackendParameters struct */
|
||||||
#ifndef WIN32
|
|
||||||
static bool
|
static bool
|
||||||
save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker)
|
save_backend_variables(BackendParameters *param, ClientSocket *client_sock,
|
||||||
#else
|
#ifdef WIN32
|
||||||
static bool
|
HANDLE childProcess, pid_t childPid,
|
||||||
save_backend_variables(BackendParameters *param, ClientSocket *client_sock, BackgroundWorker *worker,
|
|
||||||
HANDLE childProcess, pid_t childPid)
|
|
||||||
#endif
|
#endif
|
||||||
|
char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
if (client_sock)
|
if (client_sock)
|
||||||
{
|
|
||||||
memcpy(¶m->client_sock, client_sock, sizeof(ClientSocket));
|
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
|
else
|
||||||
{
|
|
||||||
memset(¶m->client_sock, 0, sizeof(ClientSocket));
|
memset(¶m->client_sock, 0, sizeof(ClientSocket));
|
||||||
param->has_client_sock = false;
|
if (!write_inheritable_socket(¶m->inh_sock,
|
||||||
}
|
client_sock ? client_sock->sock : PGINVALID_SOCKET,
|
||||||
|
childPid))
|
||||||
if (worker)
|
return false;
|
||||||
{
|
|
||||||
memcpy(¶m->bgworker, worker, sizeof(BackgroundWorker));
|
|
||||||
param->has_bgworker = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memset(¶m->bgworker, 0, sizeof(BackgroundWorker));
|
|
||||||
param->has_bgworker = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
strlcpy(param->DataDir, DataDir, MAXPGPATH);
|
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);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,8 +863,8 @@ read_inheritable_socket(SOCKET *dest, InheritableSocket *src)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
static void
|
||||||
read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **worker)
|
read_backend_variables(char *id, char **startup_data, size_t *startup_data_len)
|
||||||
{
|
{
|
||||||
BackendParameters param;
|
BackendParameters param;
|
||||||
|
|
||||||
|
@ -676,6 +886,21 @@ read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **
|
||||||
exit(1);
|
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 */
|
/* Release file */
|
||||||
FreeFile(fp);
|
FreeFile(fp);
|
||||||
if (unlink(id) != 0)
|
if (unlink(id) != 0)
|
||||||
|
@ -703,6 +928,16 @@ read_backend_variables(char *id, ClientSocket **client_sock, BackgroundWorker **
|
||||||
|
|
||||||
memcpy(¶m, paramp, sizeof(BackendParameters));
|
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))
|
if (!UnmapViewOfFile(paramp))
|
||||||
{
|
{
|
||||||
write_stderr("could not unmap view of backend variables: error code %lu\n",
|
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
|
#endif
|
||||||
|
|
||||||
restore_backend_variables(¶m, client_sock, worker);
|
restore_backend_variables(¶m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore critical backend variables from the BackendParameters struct */
|
/* Restore critical backend variables from the BackendParameters struct */
|
||||||
static void
|
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));
|
MyClientSocket = MemoryContextAlloc(TopMemoryContext, sizeof(ClientSocket));
|
||||||
memcpy(*client_sock, ¶m->client_sock, sizeof(ClientSocket));
|
memcpy(MyClientSocket, ¶m->client_sock, sizeof(ClientSocket));
|
||||||
read_inheritable_socket(&(*client_sock)->sock, ¶m->inh_sock);
|
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);
|
SetDataDir(param->DataDir);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "lib/binaryheap.h"
|
#include "lib/binaryheap.h"
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
|
#include "postmaster/auxprocess.h"
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "postmaster/pgarch.h"
|
#include "postmaster/pgarch.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
|
@ -209,8 +210,13 @@ PgArchCanRestart(void)
|
||||||
|
|
||||||
/* Main entry point for archiver process */
|
/* Main entry point for archiver process */
|
||||||
void
|
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,
|
* Ignore all signals usually bound to some action in the postmaster,
|
||||||
* except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.
|
* except for SIGHUP, SIGTERM, SIGUSR1, SIGUSR2, and SIGQUIT.
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
*
|
*
|
||||||
* postmaster.c
|
* postmaster.c
|
||||||
* This program acts as a clearing house for requests to the
|
* This program acts as a clearing house for requests to the
|
||||||
* POSTGRES system. Frontend programs send a startup message
|
* POSTGRES system. Frontend programs connect to the Postmaster,
|
||||||
* to the Postmaster and the postmaster uses the info in the
|
* and postmaster forks a new backend process to handle the
|
||||||
* message to setup a backend process.
|
* connection.
|
||||||
*
|
*
|
||||||
* The postmaster also manages system-wide operations such as
|
* The postmaster also manages system-wide operations such as
|
||||||
* startup and shutdown. The postmaster itself doesn't do those
|
* startup and shutdown. The postmaster itself doesn't do those
|
||||||
|
@ -106,7 +106,6 @@
|
||||||
#include "postmaster/autovacuum.h"
|
#include "postmaster/autovacuum.h"
|
||||||
#include "postmaster/auxprocess.h"
|
#include "postmaster/auxprocess.h"
|
||||||
#include "postmaster/bgworker_internals.h"
|
#include "postmaster/bgworker_internals.h"
|
||||||
#include "postmaster/fork_process.h"
|
|
||||||
#include "postmaster/pgarch.h"
|
#include "postmaster/pgarch.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
#include "postmaster/syslogger.h"
|
#include "postmaster/syslogger.h"
|
||||||
|
@ -427,7 +426,6 @@ typedef enum CAC_state
|
||||||
} CAC_state;
|
} CAC_state;
|
||||||
|
|
||||||
static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
|
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 void ExitPostmaster(int status) pg_attribute_noreturn();
|
||||||
static int ServerLoop(void);
|
static int ServerLoop(void);
|
||||||
static int BackendStartup(ClientSocket *client_sock);
|
static int BackendStartup(ClientSocket *client_sock);
|
||||||
|
@ -485,13 +483,6 @@ typedef struct
|
||||||
} win32_deadchild_waitinfo;
|
} win32_deadchild_waitinfo;
|
||||||
#endif /* WIN32 */
|
#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 ShmemBackendArrayAdd(Backend *bn);
|
||||||
static void ShmemBackendArrayRemove(Backend *bn);
|
static void ShmemBackendArrayRemove(Backend *bn);
|
||||||
#endif /* EXEC_BACKEND */
|
#endif /* EXEC_BACKEND */
|
||||||
|
@ -1748,7 +1739,7 @@ ServerLoop(void)
|
||||||
(AutoVacuumingActive() || start_autovac_launcher) &&
|
(AutoVacuumingActive() || start_autovac_launcher) &&
|
||||||
pmState == PM_RUN)
|
pmState == PM_RUN)
|
||||||
{
|
{
|
||||||
AutoVacPID = StartAutoVacLauncher();
|
AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
|
||||||
if (AutoVacPID != 0)
|
if (AutoVacPID != 0)
|
||||||
start_autovac_launcher = false; /* signal processed */
|
start_autovac_launcher = false; /* signal processed */
|
||||||
}
|
}
|
||||||
|
@ -2902,7 +2893,7 @@ process_pm_child_exit(void)
|
||||||
* situation, some of them may be alive already.
|
* situation, some of them may be alive already.
|
||||||
*/
|
*/
|
||||||
if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0)
|
if (!IsBinaryUpgrade && AutoVacuumingActive() && AutoVacPID == 0)
|
||||||
AutoVacPID = StartAutoVacLauncher();
|
AutoVacPID = StartChildProcess(B_AUTOVAC_LAUNCHER);
|
||||||
if (PgArchStartupAllowed() && PgArchPID == 0)
|
if (PgArchStartupAllowed() && PgArchPID == 0)
|
||||||
PgArchPID = StartChildProcess(B_ARCHIVER);
|
PgArchPID = StartChildProcess(B_ARCHIVER);
|
||||||
MaybeStartSlotSyncWorker();
|
MaybeStartSlotSyncWorker();
|
||||||
|
@ -3964,6 +3955,12 @@ TerminateChildren(int signal)
|
||||||
signal_child(SlotSyncWorkerPID, signal);
|
signal_child(SlotSyncWorkerPID, signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Information passed from postmaster to backend process */
|
||||||
|
typedef struct BackendStartupData
|
||||||
|
{
|
||||||
|
CAC_state canAcceptConnections;
|
||||||
|
} BackendStartupData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BackendStartup -- start backend process
|
* BackendStartup -- start backend process
|
||||||
*
|
*
|
||||||
|
@ -3976,7 +3973,7 @@ BackendStartup(ClientSocket *client_sock)
|
||||||
{
|
{
|
||||||
Backend *bn; /* for backend cleanup */
|
Backend *bn; /* for backend cleanup */
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
CAC_state cac;
|
BackendStartupData startup_data;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create backend data structure. Better before the fork() so we can
|
* Create backend data structure. Better before the fork() so we can
|
||||||
|
@ -4005,11 +4002,10 @@ BackendStartup(ClientSocket *client_sock)
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
bn->cancel_key = MyCancelKey;
|
|
||||||
|
|
||||||
/* Pass down canAcceptConnections state */
|
/* Pass down canAcceptConnections state */
|
||||||
cac = canAcceptConnections(BACKEND_TYPE_NORMAL);
|
startup_data.canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL);
|
||||||
bn->dead_end = (cac != CAC_OK);
|
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
|
* 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 */
|
/* Hasn't asked to be notified about any bgworkers yet */
|
||||||
bn->bgworker_notify = false;
|
bn->bgworker_notify = false;
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
pid = postmaster_child_launch(B_BACKEND,
|
||||||
pid = backend_forkexec(client_sock, cac);
|
(char *) &startup_data, sizeof(startup_data),
|
||||||
#else /* !EXEC_BACKEND */
|
client_sock);
|
||||||
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 */
|
|
||||||
|
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
/* in parent, fork failed */
|
/* in parent, fork failed */
|
||||||
|
@ -4351,16 +4330,43 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac)
|
||||||
set_ps_display("initializing");
|
set_ps_display("initializing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
/*
|
BackendMain(char *startup_data, size_t startup_data_len)
|
||||||
* BackendRun -- set up the backend's argument list and invoke PostgresMain()
|
|
||||||
*
|
|
||||||
* returns:
|
|
||||||
* Doesn't return at all.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
BackendRun(void)
|
|
||||||
{
|
{
|
||||||
|
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
|
* Create a per-backend PGPROC struct in shared memory. We must do this
|
||||||
* before we can use LWLocks or access any shared memory.
|
* 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
|
* ExitPostmaster -- cleanup
|
||||||
*
|
*
|
||||||
|
@ -4912,87 +4679,12 @@ StartChildProcess(BackendType type)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
pid = postmaster_child_launch(type, NULL, 0, NULL);
|
||||||
{
|
|
||||||
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 */
|
|
||||||
|
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
/* in parent, fork failed */
|
/* in parent, fork failed */
|
||||||
int save_errno = errno;
|
ereport(LOG,
|
||||||
|
(errmsg("could not fork \"%s\" process: %m", PostmasterChildName(type))));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fork failure is fatal during startup, but there's no need to choke
|
* 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->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
|
||||||
bn->bgworker_notify = false;
|
bn->bgworker_notify = false;
|
||||||
|
|
||||||
bn->pid = StartAutoVacWorker();
|
bn->pid = StartChildProcess(B_AUTOVAC_WORKER);
|
||||||
if (bn->pid > 0)
|
if (bn->pid > 0)
|
||||||
{
|
{
|
||||||
bn->bkend_type = BACKEND_TYPE_AUTOVAC;
|
bn->bkend_type = BACKEND_TYPE_AUTOVAC;
|
||||||
|
@ -5070,7 +4762,7 @@ StartAutovacuumWorker(void)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fork failed, fall through to report -- actual error message was
|
* fork failed, fall through to report -- actual error message was
|
||||||
* logged by StartAutoVacWorker
|
* logged by StartChildProcess
|
||||||
*/
|
*/
|
||||||
(void) ReleasePostmasterChildSlot(bn->child_slot);
|
(void) ReleasePostmasterChildSlot(bn->child_slot);
|
||||||
pfree(bn);
|
pfree(bn);
|
||||||
|
@ -5153,7 +4845,7 @@ MaybeStartSlotSyncWorker(void)
|
||||||
if (SlotSyncWorkerPID == 0 && pmState == PM_HOT_STANDBY &&
|
if (SlotSyncWorkerPID == 0 && pmState == PM_HOT_STANDBY &&
|
||||||
Shutdown <= SmartShutdown && sync_replication_slots &&
|
Shutdown <= SmartShutdown && sync_replication_slots &&
|
||||||
ValidateSlotSyncParams(LOG) && SlotSyncWorkerCanRestart())
|
ValidateSlotSyncParams(LOG) && SlotSyncWorkerCanRestart())
|
||||||
SlotSyncWorkerPID = StartSlotSyncWorker();
|
SlotSyncWorkerPID = StartChildProcess(B_SLOTSYNC_WORKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5293,24 +4985,6 @@ BackgroundWorkerUnblockSignals(void)
|
||||||
sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
|
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.
|
* Start a new bgworker.
|
||||||
* Starting time conditions must have been checked already.
|
* Starting time conditions must have been checked already.
|
||||||
|
@ -5347,65 +5021,32 @@ do_start_bgworker(RegisteredBgWorker *rw)
|
||||||
(errmsg_internal("starting background worker process \"%s\"",
|
(errmsg_internal("starting background worker process \"%s\"",
|
||||||
rw->rw_worker.bgw_name)));
|
rw->rw_worker.bgw_name)));
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
worker_pid = postmaster_child_launch(B_BG_WORKER, (char *) &rw->rw_worker, sizeof(BackgroundWorker), NULL);
|
||||||
switch ((worker_pid = bgworker_forkexec(&rw->rw_worker)))
|
if (worker_pid == -1)
|
||||||
#else
|
|
||||||
switch ((worker_pid = fork_process()))
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
case -1:
|
/* in postmaster, fork failed ... */
|
||||||
/* in postmaster, fork failed ... */
|
ereport(LOG,
|
||||||
ereport(LOG,
|
(errmsg("could not fork background worker process: %m")));
|
||||||
(errmsg("could not fork background worker process: %m")));
|
/* undo what assign_backendlist_entry did */
|
||||||
/* undo what assign_backendlist_entry did */
|
ReleasePostmasterChildSlot(rw->rw_child_slot);
|
||||||
ReleasePostmasterChildSlot(rw->rw_child_slot);
|
rw->rw_child_slot = 0;
|
||||||
rw->rw_child_slot = 0;
|
pfree(rw->rw_backend);
|
||||||
pfree(rw->rw_backend);
|
rw->rw_backend = NULL;
|
||||||
rw->rw_backend = NULL;
|
/* mark entry as crashed, so we'll try again later */
|
||||||
/* mark entry as crashed, so we'll try again later */
|
rw->rw_crashed_at = GetCurrentTimestamp();
|
||||||
rw->rw_crashed_at = GetCurrentTimestamp();
|
return false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 "access/xlogutils.h"
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "postmaster/auxprocess.h"
|
||||||
#include "postmaster/startup.h"
|
#include "postmaster/startup.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "storage/pmsignal.h"
|
#include "storage/pmsignal.h"
|
||||||
|
@ -212,8 +213,13 @@ StartupProcExit(int code, Datum arg)
|
||||||
* ----------------------------------
|
* ----------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
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 */
|
/* Arrange to clean up at startup process exit */
|
||||||
on_shmem_exit(StartupProcExit, 0);
|
on_shmem_exit(StartupProcExit, 0);
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
#include "pgtime.h"
|
#include "pgtime.h"
|
||||||
#include "port/pg_bitutils.h"
|
#include "port/pg_bitutils.h"
|
||||||
#include "postmaster/fork_process.h"
|
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
#include "postmaster/syslogger.h"
|
#include "postmaster/syslogger.h"
|
||||||
|
@ -50,6 +49,7 @@
|
||||||
#include "storage/pg_shmem.h"
|
#include "storage/pg_shmem.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -133,10 +133,7 @@ static volatile sig_atomic_t rotation_requested = false;
|
||||||
#ifdef EXEC_BACKEND
|
#ifdef EXEC_BACKEND
|
||||||
static int syslogger_fdget(FILE *file);
|
static int syslogger_fdget(FILE *file);
|
||||||
static FILE *syslogger_fdopen(int fd);
|
static FILE *syslogger_fdopen(int fd);
|
||||||
static pid_t syslogger_forkexec(void);
|
|
||||||
static void syslogger_parseArgs(int argc, char *argv[]);
|
|
||||||
#endif
|
#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 process_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
|
||||||
static void flush_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,
|
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 sigUsr1Handler(SIGNAL_ARGS);
|
||||||
static void update_metainfo_datafile(void);
|
static void update_metainfo_datafile(void);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int syslogFile;
|
||||||
|
int csvlogFile;
|
||||||
|
int jsonlogFile;
|
||||||
|
} SysloggerStartupData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main entry point for syslogger process
|
* Main entry point for syslogger process
|
||||||
* argc/argv parameters are valid only in EXEC_BACKEND case.
|
* argc/argv parameters are valid only in EXEC_BACKEND case.
|
||||||
*/
|
*/
|
||||||
NON_EXEC_STATIC void
|
void
|
||||||
SysLoggerMain(int argc, char *argv[])
|
SysLoggerMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
char logbuffer[READ_BUF_SIZE];
|
char logbuffer[READ_BUF_SIZE];
|
||||||
|
@ -173,11 +176,37 @@ SysLoggerMain(int argc, char *argv[])
|
||||||
pg_time_t now;
|
pg_time_t now;
|
||||||
WaitEventSet *wes;
|
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
|
#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;
|
MyBackendType = B_LOGGER;
|
||||||
init_ps_display(NULL);
|
init_ps_display(NULL);
|
||||||
|
@ -567,6 +596,9 @@ SysLogger_Start(void)
|
||||||
{
|
{
|
||||||
pid_t sysloggerPid;
|
pid_t sysloggerPid;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
#ifdef EXEC_BACKEND
|
||||||
|
SysloggerStartupData startup_data;
|
||||||
|
#endif /* EXEC_BACKEND */
|
||||||
|
|
||||||
if (!Logging_collector)
|
if (!Logging_collector)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -666,112 +698,95 @@ SysLogger_Start(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
#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
|
#else
|
||||||
switch ((sysloggerPid = fork_process()))
|
sysloggerPid = postmaster_child_launch(B_LOGGER, NULL, 0, NULL);
|
||||||
#endif
|
#endif /* EXEC_BACKEND */
|
||||||
|
|
||||||
|
if (sysloggerPid == -1)
|
||||||
{
|
{
|
||||||
case -1:
|
ereport(LOG,
|
||||||
ereport(LOG,
|
(errmsg("could not fork system logger: %m")));
|
||||||
(errmsg("could not fork system logger: %m")));
|
return 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we should never reach here */
|
/* success, in postmaster */
|
||||||
return 0;
|
|
||||||
|
/* 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;
|
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 */
|
#endif /* EXEC_BACKEND */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "common/blkreftable.h"
|
#include "common/blkreftable.h"
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "postmaster/auxprocess.h"
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "postmaster/walsummarizer.h"
|
#include "postmaster/walsummarizer.h"
|
||||||
#include "replication/walreceiver.h"
|
#include "replication/walreceiver.h"
|
||||||
|
@ -206,7 +207,7 @@ WalSummarizerShmemInit(void)
|
||||||
* Entry point for walsummarizer process.
|
* Entry point for walsummarizer process.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
WalSummarizerMain(void)
|
WalSummarizerMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
sigjmp_buf local_sigjmp_buf;
|
sigjmp_buf local_sigjmp_buf;
|
||||||
MemoryContext context;
|
MemoryContext context;
|
||||||
|
@ -228,6 +229,11 @@ WalSummarizerMain(void)
|
||||||
XLogRecPtr switch_lsn = InvalidXLogRecPtr;
|
XLogRecPtr switch_lsn = InvalidXLogRecPtr;
|
||||||
TimeLineID switch_tli = 0;
|
TimeLineID switch_tli = 0;
|
||||||
|
|
||||||
|
Assert(startup_data_len == 0);
|
||||||
|
|
||||||
|
MyBackendType = B_WAL_SUMMARIZER;
|
||||||
|
AuxiliaryProcessMainCommon();
|
||||||
|
|
||||||
ereport(DEBUG1,
|
ereport(DEBUG1,
|
||||||
(errmsg_internal("WAL summarizer started")));
|
(errmsg_internal("WAL summarizer started")));
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
|
#include "postmaster/auxprocess.h"
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "postmaster/walwriter.h"
|
#include "postmaster/walwriter.h"
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
|
@ -85,13 +86,18 @@ int WalWriterFlushAfter = DEFAULT_WAL_WRITER_FLUSH_AFTER;
|
||||||
* basic execution environment, but not enabled signals yet.
|
* basic execution environment, but not enabled signals yet.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
WalWriterMain(void)
|
WalWriterMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
sigjmp_buf local_sigjmp_buf;
|
sigjmp_buf local_sigjmp_buf;
|
||||||
MemoryContext walwriter_context;
|
MemoryContext walwriter_context;
|
||||||
int left_till_hibernate;
|
int left_till_hibernate;
|
||||||
bool hibernating;
|
bool hibernating;
|
||||||
|
|
||||||
|
Assert(startup_data_len == 0);
|
||||||
|
|
||||||
|
MyBackendType = B_WAL_WRITER;
|
||||||
|
AuxiliaryProcessMainCommon();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Properly accept or ignore signals the postmaster might send us
|
* Properly accept or ignore signals the postmaster might send us
|
||||||
*
|
*
|
||||||
|
|
|
@ -139,11 +139,6 @@ typedef struct RemoteSlot
|
||||||
ReplicationSlotInvalidationCause invalidated;
|
ReplicationSlotInvalidationCause invalidated;
|
||||||
} RemoteSlot;
|
} 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);
|
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
|
* It connects to the primary server, fetches logical failover slots
|
||||||
* information periodically in order to create and sync the slots.
|
* information periodically in order to create and sync the slots.
|
||||||
*/
|
*/
|
||||||
NON_EXEC_STATIC void
|
void
|
||||||
ReplSlotSyncWorkerMain(int argc, char *argv[])
|
ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
WalReceiverConn *wrconn = NULL;
|
WalReceiverConn *wrconn = NULL;
|
||||||
char *dbname;
|
char *dbname;
|
||||||
|
@ -1122,6 +1117,8 @@ ReplSlotSyncWorkerMain(int argc, char *argv[])
|
||||||
sigjmp_buf local_sigjmp_buf;
|
sigjmp_buf local_sigjmp_buf;
|
||||||
StringInfoData app_name;
|
StringInfoData app_name;
|
||||||
|
|
||||||
|
Assert(startup_data_len == 0);
|
||||||
|
|
||||||
MyBackendType = B_SLOTSYNC_WORKER;
|
MyBackendType = B_SLOTSYNC_WORKER;
|
||||||
|
|
||||||
init_ps_display(NULL);
|
init_ps_display(NULL);
|
||||||
|
@ -1299,67 +1296,6 @@ ReplSlotSyncWorkerMain(int argc, char *argv[])
|
||||||
Assert(false);
|
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.
|
* Shut down the slot sync worker.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
|
#include "postmaster/auxprocess.h"
|
||||||
#include "postmaster/interrupt.h"
|
#include "postmaster/interrupt.h"
|
||||||
#include "replication/walreceiver.h"
|
#include "replication/walreceiver.h"
|
||||||
#include "replication/walsender.h"
|
#include "replication/walsender.h"
|
||||||
|
@ -179,7 +180,7 @@ ProcessWalRcvInterrupts(void)
|
||||||
|
|
||||||
/* Main entry point for walreceiver process */
|
/* Main entry point for walreceiver process */
|
||||||
void
|
void
|
||||||
WalReceiverMain(void)
|
WalReceiverMain(char *startup_data, size_t startup_data_len)
|
||||||
{
|
{
|
||||||
char conninfo[MAXCONNINFO];
|
char conninfo[MAXCONNINFO];
|
||||||
char *tmp_conninfo;
|
char *tmp_conninfo;
|
||||||
|
@ -195,6 +196,11 @@ WalReceiverMain(void)
|
||||||
char *sender_host = NULL;
|
char *sender_host = NULL;
|
||||||
int sender_port = 0;
|
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
|
* WalRcv should be set up already (if we are a backend, we inherit this
|
||||||
* by fork() or EXEC_BACKEND mechanism from the postmaster).
|
* by fork() or EXEC_BACKEND mechanism from the postmaster).
|
||||||
|
|
|
@ -45,6 +45,7 @@ volatile uint32 CritSectionCount = 0;
|
||||||
int MyProcPid;
|
int MyProcPid;
|
||||||
pg_time_t MyStartTime;
|
pg_time_t MyStartTime;
|
||||||
TimestampTz MyStartTimestamp;
|
TimestampTz MyStartTimestamp;
|
||||||
|
struct ClientSocket *MyClientSocket;
|
||||||
struct Port *MyProcPort;
|
struct Port *MyProcPort;
|
||||||
int32 MyCancelKey;
|
int32 MyCancelKey;
|
||||||
int MyPMChildSlot;
|
int MyPMChildSlot;
|
||||||
|
|
|
@ -50,18 +50,14 @@ extern PGDLLIMPORT int Log_autovacuum_min_duration;
|
||||||
/* Status inquiry functions */
|
/* Status inquiry functions */
|
||||||
extern bool AutoVacuumingActive(void);
|
extern bool AutoVacuumingActive(void);
|
||||||
|
|
||||||
/* Functions to start autovacuum process, called from postmaster */
|
/* called from postmaster at server startup */
|
||||||
extern void autovac_init(void);
|
extern void autovac_init(void);
|
||||||
extern int StartAutoVacLauncher(void);
|
|
||||||
extern int StartAutoVacWorker(void);
|
|
||||||
|
|
||||||
/* called from postmaster when a worker could not be forked */
|
/* called from postmaster when a worker could not be forked */
|
||||||
extern void AutoVacWorkerFailed(void);
|
extern void AutoVacWorkerFailed(void);
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
extern void AutoVacLauncherMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||||
extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn();
|
extern void AutoVacWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||||
extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type,
|
extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type,
|
||||||
Oid relationId, BlockNumber blkno);
|
Oid relationId, BlockNumber blkno);
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
#ifndef AUXPROCESS_H
|
#ifndef AUXPROCESS_H
|
||||||
#define AUXPROCESS_H
|
#define AUXPROCESS_H
|
||||||
|
|
||||||
#include "miscadmin.h"
|
extern void AuxiliaryProcessMainCommon(void);
|
||||||
|
|
||||||
extern void AuxiliaryProcessMain(BackendType auxtype) pg_attribute_noreturn();
|
|
||||||
|
|
||||||
#endif /* AUXPROCESS_H */
|
#endif /* AUXPROCESS_H */
|
||||||
|
|
|
@ -55,6 +55,6 @@ extern void ForgetUnstartedBackgroundWorkers(void);
|
||||||
extern void ResetBackgroundWorkerCrashTimes(void);
|
extern void ResetBackgroundWorkerCrashTimes(void);
|
||||||
|
|
||||||
/* Entry point for background worker processes */
|
/* 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 */
|
#endif /* BGWORKER_INTERNALS_H */
|
||||||
|
|
|
@ -27,8 +27,8 @@ extern PGDLLIMPORT int CheckPointTimeout;
|
||||||
extern PGDLLIMPORT int CheckPointWarning;
|
extern PGDLLIMPORT int CheckPointWarning;
|
||||||
extern PGDLLIMPORT double CheckPointCompletionTarget;
|
extern PGDLLIMPORT double CheckPointCompletionTarget;
|
||||||
|
|
||||||
extern void BackgroundWriterMain(void) pg_attribute_noreturn();
|
extern void BackgroundWriterMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||||
extern void CheckpointerMain(void) pg_attribute_noreturn();
|
extern void CheckpointerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||||
|
|
||||||
extern void RequestCheckpoint(int flags);
|
extern void RequestCheckpoint(int flags);
|
||||||
extern void CheckpointWriteDelay(int flags, double progress);
|
extern void CheckpointWriteDelay(int flags, double progress);
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
extern Size PgArchShmemSize(void);
|
extern Size PgArchShmemSize(void);
|
||||||
extern void PgArchShmemInit(void);
|
extern void PgArchShmemInit(void);
|
||||||
extern bool PgArchCanRestart(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 PgArchWakeup(void);
|
||||||
extern void PgArchForceDirScan(void);
|
extern void PgArchForceDirScan(void);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#ifndef _POSTMASTER_H
|
#ifndef _POSTMASTER_H
|
||||||
#define _POSTMASTER_H
|
#define _POSTMASTER_H
|
||||||
|
|
||||||
|
#include "miscadmin.h"
|
||||||
|
|
||||||
/* GUC options */
|
/* GUC options */
|
||||||
extern PGDLLIMPORT bool EnableSSL;
|
extern PGDLLIMPORT bool EnableSSL;
|
||||||
extern PGDLLIMPORT int SuperuserReservedConnections;
|
extern PGDLLIMPORT int SuperuserReservedConnections;
|
||||||
|
@ -58,11 +60,9 @@ extern int MaxLivePostmasterChildren(void);
|
||||||
|
|
||||||
extern bool PostmasterMarkPIDForWorkerNotify(int);
|
extern bool PostmasterMarkPIDForWorkerNotify(int);
|
||||||
|
|
||||||
|
extern void BackendMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
#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 Size ShmemBackendArraySize(void);
|
||||||
extern void ShmemBackendArrayAllocation(void);
|
extern void ShmemBackendArrayAllocation(void);
|
||||||
|
|
||||||
|
@ -71,6 +71,16 @@ extern void pgwin32_register_deadchild_callback(HANDLE procHandle, DWORD procId)
|
||||||
#endif
|
#endif
|
||||||
#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
|
* 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
|
* for buffer references in buf_internals.h. This limitation could be lifted
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
extern PGDLLIMPORT int log_startup_progress_interval;
|
extern PGDLLIMPORT int log_startup_progress_interval;
|
||||||
|
|
||||||
extern void HandleStartupProcInterrupts(void);
|
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 PreRestoreCommand(void);
|
||||||
extern void PostRestoreCommand(void);
|
extern void PostRestoreCommand(void);
|
||||||
extern bool IsPromoteSignaled(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);
|
extern void write_syslogger_file(const char *buffer, int count, int destination);
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
extern void SysLoggerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||||
extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern bool CheckLogrotateSignal(void);
|
extern bool CheckLogrotateSignal(void);
|
||||||
extern void RemoveLogrotateSignalFiles(void);
|
extern void RemoveLogrotateSignalFiles(void);
|
||||||
|
|
|
@ -21,7 +21,7 @@ extern PGDLLIMPORT int wal_summary_keep_time;
|
||||||
|
|
||||||
extern Size WalSummarizerShmemSize(void);
|
extern Size WalSummarizerShmemSize(void);
|
||||||
extern void WalSummarizerShmemInit(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,
|
extern void GetWalSummarizerState(TimeLineID *summarized_tli,
|
||||||
XLogRecPtr *summarized_lsn,
|
XLogRecPtr *summarized_lsn,
|
||||||
|
|
|
@ -18,6 +18,6 @@
|
||||||
extern PGDLLIMPORT int WalWriterDelay;
|
extern PGDLLIMPORT int WalWriterDelay;
|
||||||
extern PGDLLIMPORT int WalWriterFlushAfter;
|
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 */
|
#endif /* _WALWRITER_H */
|
||||||
|
|
|
@ -26,9 +26,7 @@ extern PGDLLIMPORT char *PrimarySlotName;
|
||||||
extern char *CheckAndGetDbnameFromConninfo(void);
|
extern char *CheckAndGetDbnameFromConninfo(void);
|
||||||
extern bool ValidateSlotSyncParams(int elevel);
|
extern bool ValidateSlotSyncParams(int elevel);
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
extern void ReplSlotSyncWorkerMain(char *startup_data, size_t startup_data_len) pg_attribute_noreturn();
|
||||||
extern void ReplSlotSyncWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
|
|
||||||
#endif
|
|
||||||
extern int StartSlotSyncWorker(void);
|
extern int StartSlotSyncWorker(void);
|
||||||
|
|
||||||
extern void ShutDownSlotSync(void);
|
extern void ShutDownSlotSync(void);
|
||||||
|
|
|
@ -483,7 +483,7 @@ walrcv_clear_result(WalRcvExecResult *walres)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prototypes for functions in walreceiver.c */
|
/* 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 ProcessWalRcvInterrupts(void);
|
||||||
extern void WalRcvForceReply(void);
|
extern void WalRcvForceReply(void);
|
||||||
|
|
||||||
|
|
|
@ -231,6 +231,7 @@ BY_HANDLE_FILE_INFORMATION
|
||||||
Backend
|
Backend
|
||||||
BackendId
|
BackendId
|
||||||
BackendParameters
|
BackendParameters
|
||||||
|
BackendStartupData
|
||||||
BackendState
|
BackendState
|
||||||
BackendType
|
BackendType
|
||||||
BackgroundWorker
|
BackgroundWorker
|
||||||
|
@ -2136,6 +2137,7 @@ PortalStrategy
|
||||||
PostParseColumnRefHook
|
PostParseColumnRefHook
|
||||||
PostgresPollingStatusType
|
PostgresPollingStatusType
|
||||||
PostingItem
|
PostingItem
|
||||||
|
PostmasterChildType
|
||||||
PreParseColumnRefHook
|
PreParseColumnRefHook
|
||||||
PredClass
|
PredClass
|
||||||
PredIterInfo
|
PredIterInfo
|
||||||
|
@ -3259,6 +3261,7 @@ check_network_data
|
||||||
check_object_relabel_type
|
check_object_relabel_type
|
||||||
check_password_hook_type
|
check_password_hook_type
|
||||||
check_ungrouped_columns_context
|
check_ungrouped_columns_context
|
||||||
|
child_process_kind
|
||||||
chr
|
chr
|
||||||
cmpEntriesArg
|
cmpEntriesArg
|
||||||
codes_t
|
codes_t
|
||||||
|
@ -4042,6 +4045,7 @@ BlockRefTableReader
|
||||||
BlockRefTableSerializedEntry
|
BlockRefTableSerializedEntry
|
||||||
BlockRefTableWriter
|
BlockRefTableWriter
|
||||||
SummarizerReadLocalXLogPrivate
|
SummarizerReadLocalXLogPrivate
|
||||||
|
SysloggerStartupData
|
||||||
WalSummarizerData
|
WalSummarizerData
|
||||||
WalSummaryFile
|
WalSummaryFile
|
||||||
WalSummaryIO
|
WalSummaryIO
|
||||||
|
|
Loading…
Reference in New Issue