diff options
Diffstat (limited to 'src/backend/postmaster/pgstat.c')
-rw-r--r-- | src/backend/postmaster/pgstat.c | 248 |
1 files changed, 117 insertions, 131 deletions
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 70924eb676e..a3a4e57c855 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -9,11 +9,11 @@ * - Add some automatic call for pgstat vacuuming. * * - Add a pgstat config column to pg_database, so this - * entire thing can be enabled/disabled on a per db base. + * entire thing can be enabled/disabled on a per db basis. * * Copyright (c) 2001-2003, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.71 2004/05/24 02:47:47 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.72 2004/05/28 05:12:58 tgl Exp $ * ---------- */ #include "postgres.h" @@ -51,13 +51,6 @@ #include "utils/ps_status.h" #include "utils/syscache.h" -#ifdef EXEC_BACKEND -#include "utils/guc.h" -#endif - -#ifdef WIN32 -extern pid_t win32_forkexec(const char* path, char *argv[]); -#endif /* ---------- * GUC parameters @@ -107,8 +100,8 @@ static HTAB *pgStatBeDead = NULL; static PgStat_StatBeEntry *pgStatBeTable = NULL; static int pgStatNumBackends = 0; -static char pgStat_tmpfname[MAXPGPATH]; static char pgStat_fname[MAXPGPATH]; +static char pgStat_tmpfname[MAXPGPATH]; /* ---------- @@ -116,12 +109,20 @@ static char pgStat_fname[MAXPGPATH]; * ---------- */ #ifdef EXEC_BACKEND + +typedef enum STATS_PROCESS_TYPE +{ + STAT_PROC_BUFFER, + STAT_PROC_COLLECTOR +} STATS_PROCESS_TYPE; + static pid_t pgstat_forkexec(STATS_PROCESS_TYPE procType); -static void pgstat_parseArgs(PGSTAT_FORK_ARGS); +static void pgstat_parseArgs(int argc, char *argv[]); + #endif -NON_EXEC_STATIC void pgstat_main(PGSTAT_FORK_ARGS); -NON_EXEC_STATIC void pgstat_mainChild(PGSTAT_FORK_ARGS); -static void pgstat_mainInit(void); + +NON_EXEC_STATIC void PgstatBufferMain(int argc, char *argv[]); +NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]); static void pgstat_recvbuffer(void); static void pgstat_die(SIGNAL_ARGS); @@ -150,18 +151,6 @@ static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len); * ------------------------------------------------------------ */ -#ifdef EXEC_BACKEND - -void -pgstat_init_forkexec_backend(void) -{ - Assert(DataDir != NULL); - snprintf(pgStat_fname, MAXPGPATH, - PGSTAT_STAT_FILENAME, DataDir); -} - -#endif - /* ---------- * pgstat_init() - * @@ -195,12 +184,12 @@ pgstat_init(void) pgstat_collect_startcollector = true; /* - * Initialize the filenames for the status reports. + * Initialize the filename for the status reports. (In the EXEC_BACKEND + * case, this only sets the value in the postmaster. The collector + * subprocess will recompute the value for itself, and individual + * backends must do so also if they want to access the file.) */ - snprintf(pgStat_tmpfname, MAXPGPATH, - PGSTAT_STAT_TMPFILE, DataDir, getpid()); - snprintf(pgStat_fname, MAXPGPATH, - PGSTAT_STAT_FILENAME, DataDir); + snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir); /* * If we don't have to start a collector or should reset the collected @@ -441,112 +430,83 @@ startup_failed: #ifdef EXEC_BACKEND -/* ---------- +/* * pgstat_forkexec() - * - * Used to format up the arglist for, then fork and exec, statistics + * Format up the arglist for, then fork and exec, statistics * (buffer and collector) processes - * */ static pid_t pgstat_forkexec(STATS_PROCESS_TYPE procType) { - pid_t pid; - char *av[15]; + char *av[12]; int ac = 0, bufc = 0, i; - char pgstatBuf[12][MAXPGPATH]; + char pgstatBuf[7][32]; av[ac++] = "postgres"; + switch (procType) { case STAT_PROC_BUFFER: - av[ac++] = "-statBuf"; + av[ac++] = "-forkbuf"; break; case STAT_PROC_COLLECTOR: - av[ac++] = "-statCol"; + av[ac++] = "-forkcol"; break; default: Assert(false); } - /* Sockets + pipes */ - bufc = 0; - snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatSock); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[0]); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[1]); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[0]); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[1]); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[0]); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[1]); - - /* + misc */ - snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",MaxBackends); - - /* + the pstat file names, and postgres pathname */ - snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",pgStat_tmpfname); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",pgStat_fname); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",postgres_exec_path); - snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",DataDir); + av[ac++] = NULL; /* filled in by postmaster_forkexec */ + + /* postgres_exec_path is not passed by write_backend_variables */ + av[ac++] = postgres_exec_path; + + /* Sockets + pipes (those not passed by write_backend_variables) */ + snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[0]); + snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[1]); + snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[0]); + snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[1]); + snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[0]); + snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[1]); /* Add to the arg list */ Assert(bufc <= lengthof(pgstatBuf)); for (i = 0; i < bufc; i++) av[ac++] = pgstatBuf[i]; - av[ac++] = NULL; - Assert(ac <= lengthof(av)); + av[ac] = NULL; + Assert(ac < lengthof(av)); - /* Fire off execv in child */ -#ifdef WIN32 - pid = win32_forkexec(postgres_exec_path, av); -#else - if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1)) - /* FIXME: [fork/exec] suggestions for what to do here? Can't call elog... */ - abort(); -#endif - return pid; /* Parent returns pid */ + return postmaster_forkexec(ac, av); } -/* ---------- +/* * pgstat_parseArgs() - * - * Used to unformat the arglist for exec'ed statistics + * Extract data from the arglist for exec'ed statistics * (buffer and collector) processes - * */ static void -pgstat_parseArgs(PGSTAT_FORK_ARGS) +pgstat_parseArgs(int argc, char *argv[]) { - Assert(argc == 14); - - if (find_my_exec(argv[0], my_exec_path) < 0) - elog(FATAL, - gettext("%s: could not locate my own executable path"), - argv[0]); - - get_pkglib_path(my_exec_path, pkglib_path); + Assert(argc == 10); - argc = 2; - pgStatSock = atoi(argv[argc++]); + argc = 3; + StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH); pgStatPmPipe[0] = atoi(argv[argc++]); pgStatPmPipe[1] = atoi(argv[argc++]); pgStatCollectorPmPipe[0] = atoi(argv[argc++]); pgStatCollectorPmPipe[1] = atoi(argv[argc++]); pgStatPipe[0] = atoi(argv[argc++]); pgStatPipe[1] = atoi(argv[argc++]); - MaxBackends = atoi(argv[argc++]); - StrNCpy(pgStat_tmpfname,argv[argc++],MAXPGPATH); - StrNCpy(pgStat_fname, argv[argc++],MAXPGPATH); - StrNCpy(postgres_exec_path, argv[argc++],MAXPGPATH); - DataDir = strdup(argv[argc++]); - - read_nondefault_variables(); } -#endif +#endif /* EXEC_BACKEND */ + /* ---------- * pgstat_start() - @@ -638,7 +598,7 @@ pgstat_start(void) /* Drop our connection to postmaster's shared memory, as well */ PGSharedMemoryDetach(); - pgstat_main(); + PgstatBufferMain(0, NULL); break; #endif @@ -1443,26 +1403,20 @@ pgstat_send(void *msg, int len) } -/* ------------------------------------------------------------ - * Local functions implementing the statistics collector itself follow - *------------------------------------------------------------ +/* ---------- + * PgstatBufferMain() - + * + * Start up the statistics buffer process. This is the body of the + * postmaster child process. + * + * The argc/argv parameters are valid only in EXEC_BACKEND case. + * ---------- */ - -static void -pgstat_mainInit(void) +NON_EXEC_STATIC void +PgstatBufferMain(int argc, char *argv[]) { IsUnderPostmaster = true; /* we are a postmaster subprocess now */ -#ifdef EXEC_BACKEND - /* In EXEC case we will not have inherited these settings */ - IsPostmasterEnvironment = true; - whereToSendOutput = None; - - /* Setup global context */ - MemoryContextInit(); /* before any elog'ing can occur */ - InitializeGUCOptions(); -#endif - MyProcPid = getpid(); /* reset MyProcPid */ /* Lose the postmaster's on-exit routines */ @@ -1485,20 +1439,8 @@ pgstat_mainInit(void) pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGCONT, SIG_DFL); pqsignal(SIGWINCH, SIG_DFL); -} - + /* unblock will happen in pgstat_recvbuffer */ -/* ---------- - * pgstat_main() - - * - * Start up the statistics collector itself. This is the body of the - * postmaster child process. - * ---------- - */ -NON_EXEC_STATIC void -pgstat_main(PGSTAT_FORK_ARGS) -{ - pgstat_mainInit(); /* Note: for *both* EXEC_BACKEND and regular cases */ #ifdef EXEC_BACKEND pgstat_parseArgs(argc,argv); #endif @@ -1547,7 +1489,7 @@ pgstat_main(PGSTAT_FORK_ARGS) #ifndef EXEC_BACKEND case 0: /* child becomes collector process */ - pgstat_mainChild(); + PgstatCollectorMain(0, NULL); break; #endif @@ -1560,8 +1502,17 @@ pgstat_main(PGSTAT_FORK_ARGS) } +/* ---------- + * PgstatCollectorMain() - + * + * Start up the statistics collector itself. This is the body of the + * postmaster grandchild process. + * + * The argc/argv parameters are valid only in EXEC_BACKEND case. + * ---------- + */ NON_EXEC_STATIC void -pgstat_mainChild(PGSTAT_FORK_ARGS) +PgstatCollectorMain(int argc, char *argv[]) { PgStat_Msg msg; fd_set rfds; @@ -1574,30 +1525,53 @@ pgstat_mainChild(PGSTAT_FORK_ARGS) bool need_statwrite; HASHCTL hash_ctl; + MyProcPid = getpid(); /* reset MyProcPid */ + + /* + * Reset signal handling. With the exception of restoring default + * SIGCHLD handling, this is a no-op in the non-EXEC_BACKEND case + * because we'll have inherited these settings from the buffer process; + * but it's not a no-op for EXEC_BACKEND. + */ + pqsignal(SIGHUP, SIG_IGN); + pqsignal(SIGINT, SIG_IGN); + pqsignal(SIGTERM, SIG_IGN); + pqsignal(SIGQUIT, SIG_IGN); + pqsignal(SIGALRM, SIG_IGN); + pqsignal(SIGPIPE, SIG_IGN); + pqsignal(SIGUSR1, SIG_IGN); + pqsignal(SIGUSR2, SIG_IGN); + pqsignal(SIGCHLD, SIG_DFL); + pqsignal(SIGTTIN, SIG_DFL); + pqsignal(SIGTTOU, SIG_DFL); + pqsignal(SIGCONT, SIG_DFL); + pqsignal(SIGWINCH, SIG_DFL); + PG_SETMASK(&UnBlockSig); + #ifdef EXEC_BACKEND - pgstat_mainInit(); /* Note: only in EXEC_BACKEND case */ pgstat_parseArgs(argc,argv); -#else - MyProcPid = getpid(); /* reset MyProcPid */ #endif + /* Close unwanted files */ closesocket(pgStatPipe[1]); closesocket(pgStatSock); pmPipe = pgStatCollectorPmPipe[0]; /* - * In the child we can have default SIGCHLD handling (in case we want - * to call system() here...) - */ - pqsignal(SIGCHLD, SIG_DFL); - - /* * Identify myself via ps */ init_ps_display("stats collector process", "", ""); set_ps_display(""); /* + * Initialize filenames needed for status reports. + */ + snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir); + /* tmpfname need only be set correctly in this process */ + snprintf(pgStat_tmpfname, MAXPGPATH, PGSTAT_STAT_TMPFILE, + DataDir, getpid()); + + /* * Arrange to write the initial status file right away */ gettimeofday(&next_statwrite, NULL); @@ -2550,6 +2524,18 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, *betab = NULL; /* + * In EXEC_BACKEND case, we won't have inherited pgStat_fname from + * postmaster, so compute it first time through. + */ +#ifdef EXEC_BACKEND + if (pgStat_fname[0] == '\0') + { + Assert(DataDir != NULL); + snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir); + } +#endif + + /* * Try to open the status file. If it doesn't exist, the backends * simply return zero for anything and the collector simply starts * from scratch with empty counters. |