Exemple #1
0
/*
 * WalSndQuickDieHandler() occurs when signalled SIGQUIT by the postmaster.
 *
 * Some backend has bought the farm,
 * so we need to stop what we're doing and exit.
 */
static void
WalSndQuickDieHandler(SIGNAL_ARGS)
{
	PG_SETMASK(&BlockSig);

	/*
	 * We DO NOT want to run proc_exit() callbacks -- we're here because
	 * shared memory may be corrupted, so we don't want to try to clean up our
	 * transaction.  Just nail the windows shut and get out of town.  Now that
	 * there's an atexit callback to prevent third-party code from breaking
	 * things by calling exit() directly, we have to reset the callbacks
	 * explicitly to make this work as intended.
	 */
	on_exit_reset();

	/*
	 * Note we do exit(2) not exit(0).	This is to force the postmaster into a
	 * system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
	 * backend.  This is necessary precisely because we don't clean up our
	 * shared memory state.  (The "dead man switch" mechanism in pmsignal.c
	 * should ensure the postmaster sees this as a crash, too, but no harm in
	 * being doubly sure.)
	 */
	exit(2);
}
Exemple #2
0
pid_t
StartContQueryScheduler(void)
{
	pid_t pid;

#ifdef EXEC_BACKEND
	switch ((pid = cqscheduler_forkexec()))
#else
	switch ((pid = fork_process()))
#endif
	{
	case -1:
		ereport(LOG,
				(errmsg("could not fork continuous query scheduler process: %m")));
		return 0;

#ifndef EXEC_BACKEND
	case 0:
		/* in postmaster child ... */
		/* Close the postmaster's sockets */
		ClosePostmasterPorts(false);

		/* Lose the postmaster's on-exit routines */
		on_exit_reset();

		ContQuerySchedulerMain(0, NULL);
		break;
#endif
	default:
		return pid;
	}

	/* shouldn't get here */
	return 0;
}
Exemple #3
0
/*
 * pgarch_start
 *
 *	Called from postmaster at startup or after an existing archiver
 *	died.  Attempt to fire up a fresh archiver process.
 *
 *	Returns PID of child process, or 0 if fail.
 *
 *	Note: if fail, we will be called again from the postmaster main loop.
 */
int
pgarch_start(void)
{
	time_t		curtime;
	pid_t		pgArchPid;

	/*
	 * Do nothing if no archiver needed
	 */
	if (!XLogArchivingActive())
		return 0;

	/*
	 * Do nothing if too soon since last archiver start.  This is a safety
	 * valve to protect against continuous respawn attempts if the archiver is
	 * dying immediately at launch. Note that since we will be re-called from
	 * the postmaster main loop, we will get another chance later.
	 */
	curtime = time(NULL);
	if ((unsigned int) (curtime - last_pgarch_start_time) <
		(unsigned int) PGARCH_RESTART_INTERVAL)
		return 0;
	last_pgarch_start_time = curtime;

#ifdef EXEC_BACKEND
	switch ((pgArchPid = pgarch_forkexec()))
#else
	switch ((pgArchPid = fork_process()))
#endif
	{
		case -1:
			ereport(LOG,
					(errmsg("could not fork archiver: %m")));
			return 0;

#ifndef EXEC_BACKEND
		case 0:
			/* in postmaster child ... */
			/* Close the postmaster's sockets */
			ClosePostmasterPorts(false);

			/* Lose the postmaster's on-exit routines */
			on_exit_reset();

			/* Drop our connection to postmaster's shared memory, as well */
			PGSharedMemoryDetach();

			PgArchiverMain(0, NULL);
			break;
#endif

		default:
			return (int) pgArchPid;
	}

	/* shouldn't get here */
	return 0;
}
Exemple #4
0
/*
 * PgArchiverMain
 *
 *	The argc/argv parameters are valid only in EXEC_BACKEND case.  However,
 *	since we don't use 'em, it hardly matters...
 */
NON_EXEC_STATIC void
PgArchiverMain(int argc, char *argv[])
{
	IsUnderPostmaster = true;	/* we are a postmaster subprocess now */

	MyProcPid = getpid();		/* reset MyProcPid */

	/* Lose the postmaster's on-exit routines */
	on_exit_reset();

	/*
	 * Ignore all signals usually bound to some action in the postmaster,
	 * except for SIGHUP, SIGUSR1 and SIGQUIT.
	 */
	pqsignal(SIGHUP, ArchSigHupHandler);
	pqsignal(SIGINT, SIG_IGN);
	pqsignal(SIGTERM, SIG_IGN);
	pqsignal(SIGQUIT, pgarch_exit);
	pqsignal(SIGALRM, SIG_IGN);
	pqsignal(SIGPIPE, SIG_IGN);
	pqsignal(SIGUSR1, pgarch_waken);
	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);

	/*
	 * Identify myself via ps
	 */
	init_ps_display("archiver process", "", "");
	set_ps_display("");

	pgarch_MainLoop();

	exit(0);
}
Exemple #5
0
/*
 * Postmaster subroutine to start a syslogger subprocess.
 */
int
syslog_start(void)
{
	pid_t pid;
	char *filename;

	if (!log_collector)
		return 0;

	/*
	 * If first time through, create the pipe which will receive stderr
	 * output. If syslog crashes and needs to be restarted, we continue to 
	 * use the same pipe. Indeed must do so, since extant backends will be
	 * writing into that pipe.
	 *
	 * This means the postmaster must continue to hold the read end of the
	 * pipe open, so we can pass it down to the reincarnated syslogger. This
	 * is a bit klugy but we have little choice.
	 */
#ifndef WIN32
	if (syslog_pipe[0] < 0) {
		if (pgpipe(syslog_pipe) < 0)
			ereport(FATAL, (
			errcode_sock_access(),
			errmsg("could not create pipe for syslog: %m")));
	}
#else
	if (!syslog_pipe[0]) {
		SECURITY_ATTRIBUTES sa;

		memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
		sa.nLength = sizeof(SECURITY_ATTRIBUTES);
		sa.bInheritHandle = TRUE;

		if (!CreatePipe(&syslog_pipe[0], &syslog_pipe[1], &sa, 32768))
			ereport(FATAL, (
			errcode_file_access(),
			errmsg("could not create pipe for syslog: %m")));
	}
#endif

	/*
	 * Create log directory if not present; ignore errors
	 */
	mkdir(log_directory, S_IRWXU);

	/*
	 * The initial logfile is created right in the postmaster, to verify i
	 * that the log_directory is writable.
	 */
	filename = logfile_getname(time(NULL), NULL);
	syslog_file = logfile_open(filename, "a", false);
	pfree(filename);

#ifdef EXEC_BACKEND
	switch ((pid = syslog_forkexec())) {
#else
	switch ((pid = fork_process())) {
#endif
	case -1:
		ereport(LOG, (errmsg("could not fork system logger: %m")));
		return 0;

#ifndef EXEC_BACKEND
	case 0:
		/* in postmaster child ... */
		/* Close the postmaster's sockets */
		close_ports(true);

		/* Lose the postmaster's on-exit routines */
		on_exit_reset();

		/* Drop our connection to postmaster's shared memory */
		shm_child_detach();

		/* do the work */
		syslog_main(0, NULL);
		break;
#endif

	default:
		/* success, in postmaster */

		/* now we redirect stderr, if not done already */
		if (!redirection_done) {
#ifndef WIN32
			fflush(stdout);
			if (dup2(syslog_pipe[1], fileno(stdout)) < 0) {
				ereport(FATAL, (
				errcode_file_access(),
				errmsg("could not redirect stdout: %m")));
			}

			fflush(stderr);
			if (dup2(syslog_pipe[1], fileno(stderr)) < 0) {
				ereport(FATAL, (
				errcode_file_access(),
				errmsg("could not redirect stderr: %m")));
			}

			/* Now we are done with the write end of pipe */
			close(syslog_pipe[1]);
			syslog_pipe[1] = -1;
#else
			int fd;

			/*
			 * 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) syslog_pipe[1], _O_APPEND | _O_BINARY);
			if (dup2(fd, _fileno(stderr)) < 0)
				ereport(FATAL, (
				errcode_file_access(),
				errmsg("could not redirect stderr: %m")));

			close(fd);
			_setmode(_fileno(stderr), _O_BINARY);

			/* Now we are done with the write end of the pipe. */
			CloseHandle(syslog_pipe[1]);
			syslog_pipe[1] = 0;
#endif
			redirection_done = true;
		}

		/* postmaster will never write the file; close it */
		fclose(syslog_file);
		syslog_file = NULL;
		return (int) pid;
	}

	/* we should never reach here */
	return 0;
}


#ifdef EXEC_BACKEND

/*
 * syslog_forkexec() -
 *
 * Format up the arglist for, then fork and exec, a syslogger process
 */
static pid_t
syslog_forkexec(void)
{
	char *av[10];
	int ac = 0;
	char filenobuf[32];

	av[ac++] = "postgres";
	av[ac++] = "--forklog";
	av[ac++] = NULL;			/* filled in by master_forkexec */

	/* static variables (those not passed by write_backend_variables) */
#ifndef WIN32
	if (syslog_file != NULL)
		snprintf(filenobuf, sizeof(filenobuf), "%d", fileno(syslog_file));
	else
		strcpy(filenobuf, "-1");

#else	/* WIN32 */
	if (syslog_file != NULL)
		snprintf(filenobuf, sizeof(filenobuf), "%ld",
			(long) _get_osfhandle(_fileno(syslog_file)));
	else
		strcpy(filenobuf, "0");

#endif   /* WIN32 */
	av[ac++] = filenobuf;
	av[ac] = NULL;
	ASSERT(ac < lengthof(av));

	return master_forkexec(ac, av);
}
Exemple #6
0
/*
 * fork escalation process
 */
pid_t
fork_escalation_process(void)
{
	pid_t		pid;

	pid = fork();
	if (pid != 0)
	{
		if (pid == -1)
			ereport(NOTICE,
					(errmsg("failed to fork a escalation process")));
		return pid;
	}
	on_exit_reset();
	processType = PT_WATCHDOG_UTILITY;

	POOL_SETMASK(&UnBlockSig);

	init_ps_display("", "", "", "");

	pool_signal(SIGTERM, wd_exit);
	pool_signal(SIGINT, wd_exit);
	pool_signal(SIGQUIT, wd_exit);
	pool_signal(SIGCHLD, SIG_DFL);
	pool_signal(SIGHUP, SIG_IGN);
	pool_signal(SIGPIPE, SIG_IGN);

	MemoryContextSwitchTo(TopMemoryContext);

	set_ps_display("watchdog escalation", false);

	ereport(LOG,
			(errmsg("watchdog: escalation started")));

	/*
	 * STEP 1 clear shared memory cache
	 */
	if (pool_config->memory_cache_enabled && pool_is_shmem_cache() &&
		pool_config->clear_memqcache_on_escalation)
	{
		ereport(LOG,
				(errmsg("watchdog escalation"),
				 errdetail("clearing all the query cache on shared memory")));

		pool_clear_memory_cache();
	}

	/*
	 * STEP 2 execute escalation command provided by user in pgpool conf file
	 */
	if (strlen(pool_config->wd_escalation_command))
	{
		int			r = system(pool_config->wd_escalation_command);

		if (WIFEXITED(r))
		{
			if (WEXITSTATUS(r) == EXIT_SUCCESS)
				ereport(LOG,
						(errmsg("watchdog escalation successful")));
			else
			{
				ereport(WARNING,
						(errmsg("watchdog escalation command failed with exit status: %d", WEXITSTATUS(r))));
			}
		}
		else
		{
			ereport(WARNING,
					(errmsg("watchdog escalation command exit abnormally")));
		}
	}

	/*
	 * STEP 3 bring up the delegate IP
	 */
	if (strlen(pool_config->delegate_IP) != 0)
	{
		if (wd_IP_up() != WD_OK)
			ereport(WARNING,
					(errmsg("watchdog escalation failed to acquire delegate IP")));

	}
	exit(0);
}
Exemple #7
0
/*
 * fork de-escalation process
 */
pid_t
fork_plunging_process(void)
{
	pid_t		pid;

	pid = fork();
	if (pid != 0)
	{
		if (pid == -1)
			ereport(NOTICE,
					(errmsg("failed to fork a de-escalation process")));
		return pid;
	}
	on_exit_reset();
	processType = PT_WATCHDOG_UTILITY;

	POOL_SETMASK(&UnBlockSig);

	init_ps_display("", "", "", "");

	pool_signal(SIGTERM, wd_exit);
	pool_signal(SIGINT, wd_exit);
	pool_signal(SIGQUIT, wd_exit);
	pool_signal(SIGCHLD, SIG_DFL);
	pool_signal(SIGHUP, SIG_IGN);
	pool_signal(SIGPIPE, SIG_IGN);

	MemoryContextSwitchTo(TopMemoryContext);

	set_ps_display("watchdog de-escalation", false);

	ereport(LOG,
			(errmsg("watchdog: de-escalation started")));

	/*
	 * STEP 1 execute de-escalation command provided by user in pgpool conf
	 * file
	 */
	if (strlen(pool_config->wd_de_escalation_command))
	{
		int			r = system(pool_config->wd_de_escalation_command);

		if (WIFEXITED(r))
		{
			if (WEXITSTATUS(r) == EXIT_SUCCESS)
				ereport(LOG,
						(errmsg("watchdog de-escalation successful")));
			else
			{
				ereport(WARNING,
						(errmsg("watchdog de-escalation command failed with exit status: %d", WEXITSTATUS(r))));
			}
		}
		else
		{
			ereport(WARNING,
					(errmsg("watchdog de-escalation command exit abnormally")));
		}
	}

	/*
	 * STEP 2 bring down the delegate IP
	 */

	if (strlen(pool_config->delegate_IP) != 0)
	{
		if (wd_IP_down() != WD_OK)
			ereport(WARNING,
					(errmsg("watchdog de-escalation failed to bring down delegate IP")));
	}
	exit(0);
}
Exemple #8
0
/*
 * Common service main.
 */
void
ServiceMain(ServiceCtrl *serviceCtrl)
{
	ServiceConfig *serviceConfig;

	sigjmp_buf	local_sigjmp_buf;

	Assert(serviceCtrl != NULL);
	serviceConfig = (ServiceConfig*)serviceCtrl->serviceConfig;
	Assert(serviceConfig != NULL);

	IsUnderPostmaster = true;

	/* reset MyProcPid */
	MyProcPid = getpid();


	/* Lose the postmaster's on-exit routines */
	on_exit_reset();

	/* Identify myself via ps */
	init_ps_display(serviceConfig->psTitle, "", "", "");

	if (serviceConfig->ServiceEarlyInit != NULL)
	{
		serviceConfig->ServiceEarlyInit();
	}
	else
	{
		SetProcessingMode(InitProcessing);
	}

	/*
	 * Set up signal handlers.	We operate on databases much like a regular
	 * backend, so we use the same signal handling.  See equivalent code in
	 * tcop/postgres.c.
	 *
	 * Currently, we don't pay attention to postgresql.conf changes that
	 * happen during a single daemon iteration, so we can ignore SIGHUP.
	 */
	pqsignal(SIGHUP, SIG_IGN);

	/*
	 * Presently, SIGINT will lead to autovacuum shutdown, because that's how
	 * we handle ereport(ERROR).  It could be improved however.
	 */
	pqsignal(SIGINT, StatementCancelHandler);
	pqsignal(SIGTERM, ServiceDie);
	pqsignal(SIGQUIT, ServiceQuickDie);
	pqsignal(SIGALRM, handle_sig_alarm);

	pqsignal(SIGPIPE, SIG_IGN);
	pqsignal(SIGUSR1, procsignal_sigusr1_handler);
	/* We don't listen for async notifies */
	pqsignal(SIGUSR2, serviceConfig->ServiceRequestShutdown);
	pqsignal(SIGFPE, FloatExceptionHandler);
	pqsignal(SIGCHLD, SIG_DFL);

#ifdef SIGBUS
    pqsignal(SIGBUS, HandleCrash);
#endif
#ifdef SIGILL
    pqsignal(SIGILL, HandleCrash);
#endif
#ifdef SIGSEGV
    pqsignal(SIGSEGV, HandleCrash);
#endif


	/* Early initialization */
	BaseInit();

	if (serviceConfig->ServicePostgresInit != NULL)
	{
		serviceConfig->ServicePostgresInit();
	}

	SetProcessingMode(NormalProcessing);

	/*
	 * If an exception is encountered, processing resumes here.
	 *
	 * See notes in postgres.c about the design of this coding.
	 */
	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* Prevents interrupts while cleaning up */
		HOLD_INTERRUPTS();

		/* Report the error to the server log */
		EmitErrorReport();

		/*
		 * We can now go away.	Note that because we'll call InitProcess, a
		 * callback will be registered to do ProcKill, which will clean up
		 * necessary state.
		 */
		proc_exit(0);
	}

	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	PG_SETMASK(&UnBlockSig);

	/* set up a listener port and put it in shmem*/
	serviceCtrl->listenerPort = ServiceListenerSetup(serviceCtrl);

	if (serviceConfig->ServiceInit != NULL)
	{
		serviceConfig->ServiceInit(serviceCtrl->listenerPort);
	}

	/* listen loop */
	ServiceListenLoop(serviceCtrl);

	proc_exit(0);
}
/*
 * Postmaster subroutine to start a syslogger subprocess.
 */
int
SysLogger_Start(void)
{
	pid_t		sysloggerPid;
	char	   *filename;

	if (!Redirect_stderr)
		return 0;

	/*
	 * If first time through, create the pipe which will receive stderr
	 * output.
	 *
	 * If the syslogger crashes and needs to be restarted, we continue to use
	 * the same pipe (indeed must do so, since extant backends will be writing
	 * into that pipe).
	 *
	 * This means the postmaster must continue to hold the read end of the
	 * pipe open, so we can pass it down to the reincarnated syslogger. This
	 * is a bit klugy but we have little choice.
	 */
#ifndef WIN32
	if (syslogPipe[0] < 0)
	{
		if (pgpipe(syslogPipe) < 0)
			ereport(FATAL,
					(errcode_for_socket_access(),
					 (errmsg("could not create pipe for syslog: %m"))));
	}
#else
	if (!syslogPipe[0])
	{
		SECURITY_ATTRIBUTES sa;

		memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
		sa.nLength = sizeof(SECURITY_ATTRIBUTES);
		sa.bInheritHandle = TRUE;

		if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, 32768))
			ereport(FATAL,
					(errcode_for_file_access(),
					 (errmsg("could not create pipe for syslog: %m"))));
	}
#endif

	/*
	 * Create log directory if not present; ignore errors
	 */
	mkdir(Log_directory, 0700);

	/*
	 * The initial logfile is created right in the postmaster, to verify that
	 * the Log_directory is writable.
	 */
	filename = logfile_getname(time(NULL));

	syslogFile = fopen(filename, "a");

	if (!syslogFile)
		ereport(FATAL,
				(errcode_for_file_access(),
				 (errmsg("could not create log file \"%s\": %m",
						 filename))));

	setvbuf(syslogFile, NULL, LBF_MODE, 0);

	pfree(filename);

#ifdef EXEC_BACKEND
	switch ((sysloggerPid = syslogger_forkexec()))
#else
	switch ((sysloggerPid = fork_process()))
#endif
	{
		case -1:
			ereport(LOG,
					(errmsg("could not fork system logger: %m")));
			return 0;

#ifndef EXEC_BACKEND
		case 0:
			/* in postmaster child ... */
			/* Close the postmaster's sockets */
			ClosePostmasterPorts(true);

			/* Lose the postmaster's on-exit routines */
			on_exit_reset();

			/* Drop our connection to postmaster's shared memory, as well */
			PGSharedMemoryDetach();

			/* do the work */
			SysLoggerMain(0, NULL);
			break;
#endif

		default:
			/* success, in postmaster */

			/* now we redirect stderr, if not done already */
			if (!redirection_done)
			{
#ifndef WIN32
				fflush(stdout);
				if (dup2(syslogPipe[1], fileno(stdout)) < 0)
					ereport(FATAL,
							(errcode_for_file_access(),
							 errmsg("could not redirect stdout: %m")));
				fflush(stderr);
				if (dup2(syslogPipe[1], fileno(stderr)) < 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
				int			fd;

				/*
				 * 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((long) syslogPipe[1],
									 _O_APPEND | _O_BINARY);
				if (dup2(fd, _fileno(stderr)) < 0)
					ereport(FATAL,
							(errcode_for_file_access(),
							 errmsg("could not redirect stderr: %m")));
				close(fd);
				_setmode(_fileno(stderr),_O_BINARY);
				/* Now we are done with the write end of the pipe. */
				CloseHandle(syslogPipe[1]);
				syslogPipe[1] = 0;
#endif
				redirection_done = true;
			}

			/* postmaster will never write the file; close it */
			fclose(syslogFile);
			syslogFile = NULL;
			return (int) sysloggerPid;
	}

	/* we should never reach here */
	return 0;
}
/*
 * Main entry point for syslogger process
 * argc/argv parameters are valid only in EXEC_BACKEND case.
 */
NON_EXEC_STATIC void
SysLoggerMain(int argc, char *argv[])
{
	char	   *currentLogDir;
	char	   *currentLogFilename;
	int			currentLogRotationAge;

	IsUnderPostmaster = true;	/* we are a postmaster subprocess now */

	MyProcPid = getpid();		/* reset MyProcPid */

	/* Lose the postmaster's on-exit routines */
	on_exit_reset();

#ifdef EXEC_BACKEND
	syslogger_parseArgs(argc, argv);
#endif   /* EXEC_BACKEND */

	am_syslogger = true;

	init_ps_display("logger process", "", "");
	set_ps_display("");

	/*
	 * If we restarted, our stderr is already redirected into our own
	 * input pipe.	This is of course pretty useless, not to mention that
	 * it interferes with detecting pipe EOF.  Point stderr to /dev/null.
	 * This assumes that all interesting messages generated in the
	 * syslogger will come through elog.c and will be sent to
	 * write_syslogger_file.
	 */
	if (redirection_done)
	{
		int			fd = open(NULL_DEV, O_WRONLY);

		/*
		 * The closes might look redundant, but they are not: we want to
		 * be darn sure the pipe gets closed even if the open failed.  We
		 * can survive running with stderr pointing nowhere, but we can't
		 * afford to have extra pipe input descriptors hanging around.
		 */
		close(fileno(stdout));
		close(fileno(stderr));
		dup2(fd, fileno(stdout));
		dup2(fd, fileno(stderr));
		close(fd);
	}

	/*
	 * Also close our copy of the write end of the pipe.  This is needed
	 * to ensure we can detect pipe EOF correctly.	(But note that in the
	 * restart case, the postmaster already did this.)
	 */
#ifndef WIN32
	if (syslogPipe[1] >= 0)
		close(syslogPipe[1]);
	syslogPipe[1] = -1;
#else
	if (syslogPipe[1])
		CloseHandle(syslogPipe[1]);
	syslogPipe[1] = 0;
#endif

	/*
	 * Properly accept or ignore signals the postmaster might send us
	 *
	 * Note: we ignore all termination signals, and instead exit only when
	 * all upstream processes are gone, to ensure we don't miss any dying
	 * gasps of broken backends...
	 */

	pqsignal(SIGHUP, sigHupHandler);	/* set flag to read config file */
	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);

	/*
	 * Reset some signals that are accepted by postmaster but not here
	 */
	pqsignal(SIGCHLD, SIG_DFL);
	pqsignal(SIGTTIN, SIG_DFL);
	pqsignal(SIGTTOU, SIG_DFL);
	pqsignal(SIGCONT, SIG_DFL);
	pqsignal(SIGWINCH, SIG_DFL);

	PG_SETMASK(&UnBlockSig);

#ifdef WIN32
	/* Fire up separate data transfer thread */
	InitializeCriticalSection(&sysfileSection);

	{
		unsigned int tid;

		threadHandle = (HANDLE) _beginthreadex(0, 0, pipeThread, 0, 0, &tid);
	}
#endif   /* WIN32 */

	/* remember active logfile parameters */
	currentLogDir = pstrdup(Log_directory);
	currentLogFilename = pstrdup(Log_filename);
	currentLogRotationAge = Log_RotationAge;
	/* set next planned rotation time */
	set_next_rotation_time();

	/* main worker loop */
	for (;;)
	{
		bool		rotation_requested = false;
		bool		time_based_rotation = false;

#ifndef WIN32
		char		logbuffer[1024];
		int			bytesRead;
		int			rc;
		fd_set		rfds;
		struct timeval timeout;
#endif

		if (got_SIGHUP)
		{
			got_SIGHUP = false;
			ProcessConfigFile(PGC_SIGHUP);

			/*
			 * Check if the log directory or filename pattern changed in 
			 * postgresql.conf. If so, force rotation to make sure we're 
			 * writing the logfiles in the right place.
			 */
			if (strcmp(Log_directory, currentLogDir) != 0)
			{
				pfree(currentLogDir);
				currentLogDir = pstrdup(Log_directory);
				rotation_requested = true;
			}
			if (strcmp(Log_filename, currentLogFilename) != 0)
			{
				pfree(currentLogFilename);
				currentLogFilename = pstrdup(Log_filename);
				rotation_requested = true;
			}
			/*
			 * If rotation time parameter changed, reset next rotation time,
			 * but don't immediately force a rotation.
			 */
			if (currentLogRotationAge != Log_RotationAge)
			{
				currentLogRotationAge = Log_RotationAge;
				set_next_rotation_time();
			}
		}

		if (!rotation_requested && Log_RotationAge > 0)
		{
			/* Do a logfile rotation if it's time */
			pg_time_t	now = time(NULL);

			if (now >= next_rotation_time)
				rotation_requested = time_based_rotation = true;
		}

		if (!rotation_requested && Log_RotationSize > 0)
		{
			/* Do a rotation if file is too big */
			if (ftell(syslogFile) >= Log_RotationSize * 1024L)
				rotation_requested = true;
		}

		if (rotation_requested)
			logfile_rotate(time_based_rotation);

#ifndef WIN32

		/*
		 * Wait for some data, timing out after 1 second
		 */
		FD_ZERO(&rfds);
		FD_SET(syslogPipe[0], &rfds);
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;

		rc = select(syslogPipe[0] + 1, &rfds, NULL, NULL, &timeout);

		if (rc < 0)
		{
			if (errno != EINTR)
				ereport(LOG,
						(errcode_for_socket_access(),
					   errmsg("select() failed in logger process: %m")));
		}
		else if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds))
		{
			bytesRead = piperead(syslogPipe[0],
								 logbuffer, sizeof(logbuffer));

			if (bytesRead < 0)
			{
				if (errno != EINTR)
					ereport(LOG,
							(errcode_for_socket_access(),
						 errmsg("could not read from logger pipe: %m")));
			}
			else if (bytesRead > 0)
			{
				write_syslogger_file_binary(logbuffer, bytesRead);
				continue;
			}
			else
			{
				/*
				 * Zero bytes read when select() is saying read-ready
				 * means EOF on the pipe: that is, there are no longer any
				 * processes with the pipe write end open.	Therefore, the
				 * postmaster and all backends are shut down, and we are
				 * done.
				 */
				pipe_eof_seen = true;
			}
		}
#else							/* WIN32 */

		/*
		 * On Windows we leave it to a separate thread to transfer data
		 * and detect pipe EOF.  The main thread just wakes up once a
		 * second to check for SIGHUP and rotation conditions.
		 */
		pgwin32_backend_usleep(1000000);
#endif   /* WIN32 */

		if (pipe_eof_seen)
		{
			ereport(LOG,
					(errmsg("logger shutting down")));

			/*
			 * Normal exit from the syslogger is here.	Note that we
			 * deliberately do not close syslogFile before exiting; this
			 * is to allow for the possibility of elog messages being
			 * generated inside proc_exit.	Regular exit() will take care
			 * of flushing and closing stdio channels.
			 */
			proc_exit(0);
		}
	}
}
Exemple #11
0
pid_t
wd_child(int fork_wait_time)
{
	int sock;
	volatile int fd;
	int rtn;
	pid_t pid = 0;
	sigjmp_buf	local_sigjmp_buf;

	pid = fork();
	if (pid != 0)
	{
		if (pid == -1)
			ereport(PANIC,
					(errmsg("failed to fork a watchdog process")));

		return pid;
	}

	on_exit_reset();
	processType = PT_WATCHDOG;

	if (fork_wait_time > 0)
	{
		sleep(fork_wait_time);
	}

	POOL_SETMASK(&UnBlockSig);

	signal(SIGTERM, wd_child_exit);
	signal(SIGINT, wd_child_exit);
	signal(SIGQUIT, wd_child_exit);
	signal(SIGCHLD, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGUSR1, SIG_IGN);
	signal(SIGUSR2, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGALRM, SIG_IGN);

	init_ps_display("", "", "", "");

	if (WD_List == NULL)
	{
		/* memory allocate is not ready */
		wd_child_exit(15);
	}
	/* Create per loop iteration memory context */
	ProcessLoopContext = AllocSetContextCreate(TopMemoryContext,
											   "wd_child_main_loop",
											   ALLOCSET_DEFAULT_MINSIZE,
											   ALLOCSET_DEFAULT_INITSIZE,
											   ALLOCSET_DEFAULT_MAXSIZE);
	
	MemoryContextSwitchTo(TopMemoryContext);


	sock = wd_create_recv_socket(WD_MYSELF->wd_port);

	if (sock < 0)
	{
		/* socket create failed */
		wd_child_exit(15);
	}

	set_ps_display("watchdog", false);

	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* Since not using PG_TRY, must reset error stack by hand */
		if(fd > 0)
			close(fd);

		error_context_stack = NULL;
		
		EmitErrorReport();
		MemoryContextSwitchTo(TopMemoryContext);
		FlushErrorState();
	}
	
	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	/* child loop */
	for(;;)
	{
		MemoryContextSwitchTo(ProcessLoopContext);
		MemoryContextResetAndDeleteChildren(ProcessLoopContext);
		fd = -1;
		WdPacket buf;

		fd = wd_accept(sock);
		if (fd < 0)
		{
			continue;
		}
		rtn = wd_recv_packet(fd, &buf);
		if (rtn == WD_OK)
		{
			wd_send_response(fd, &buf);
		}
		close(fd);
	}
	return pid;
}
Exemple #12
0
/* fork heartbeat sender child */
pid_t
wd_hb_sender(int fork_wait_time, WdHbIf *hb_if)
{
	int sock;
	pid_t pid = 0;
	WdHbPacket pkt;
	WdInfo * p = WD_List;
	char pack_str[WD_MAX_PACKET_STRING];
	int pack_str_len;
	sigjmp_buf	local_sigjmp_buf;

	pid = fork();
	if (pid != 0)
	{
		if (pid == -1)
			ereport(PANIC,
					(errmsg("failed to fork a heartbeat sender child")));
		return pid;
	}

	on_exit_reset();
	processType = PT_HB_SENDER;

	if (fork_wait_time > 0)
	{
		sleep(fork_wait_time);
	}

	POOL_SETMASK(&UnBlockSig);

	signal(SIGTERM, hb_sender_exit);
	signal(SIGINT, hb_sender_exit);
	signal(SIGQUIT, hb_sender_exit);
	signal(SIGCHLD, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGUSR1, SIG_IGN);
	signal(SIGUSR2, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGALRM, SIG_IGN);

	init_ps_display("", "", "", "");
	/* Create per loop iteration memory context */
	ProcessLoopContext = AllocSetContextCreate(TopMemoryContext,
											   "wdhb_sender",
											   ALLOCSET_DEFAULT_MINSIZE,
											   ALLOCSET_DEFAULT_INITSIZE,
											   ALLOCSET_DEFAULT_MAXSIZE);
	
	MemoryContextSwitchTo(TopMemoryContext);

	sock = wd_create_hb_send_socket(hb_if);

	set_ps_display("heartbeat sender", false);

	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* Since not using PG_TRY, must reset error stack by hand */
		error_context_stack = NULL;
		
		EmitErrorReport();
		MemoryContextSwitchTo(TopMemoryContext);
		FlushErrorState();
		sleep(pool_config->wd_heartbeat_keepalive);
	}
	
	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	for(;;)
	{
		MemoryContextSwitchTo(ProcessLoopContext);
		MemoryContextResetAndDeleteChildren(ProcessLoopContext);

		/* contents of packet */
		gettimeofday(&pkt.send_time, NULL);
		strlcpy(pkt.from, pool_config->wd_hostname, sizeof(pkt.from));
		pkt.from_pgpool_port = pool_config->port;

		pkt.status = p->status;

		/* authentication key */
		if (strlen(pool_config->wd_authkey))
		{
			/* calculate hash from packet */
			pack_str_len = packet_to_string_hb(&pkt, pack_str, sizeof(pack_str));
			wd_calc_hash(pack_str, pack_str_len, pkt.hash);
		}

		/* send heartbeat signal */
		wd_hb_send(sock, &pkt, sizeof(pkt), hb_if->addr, hb_if->dest_port);
		ereport(DEBUG1,
				(errmsg("watchdog heartbeat: send heartbeat signal to %s:%d", hb_if->addr, hb_if->dest_port)));
		sleep(pool_config->wd_heartbeat_keepalive);
	}

	return pid;
}
Exemple #13
0
/* fork heartbeat receiver child */
pid_t
wd_hb_receiver(int fork_wait_time, WdHbIf *hb_if)
{
	int sock;
	pid_t pid = 0;
	WdHbPacket pkt;
	struct timeval tv;
	char from[WD_MAX_HOST_NAMELEN];
	int from_pgpool_port;
	char buf[(MD5_PASSWD_LEN+1)*2];
	char pack_str[WD_MAX_PACKET_STRING];
	int pack_str_len;
	sigjmp_buf	local_sigjmp_buf;


	WdInfo * p;

	pid = fork();
	if (pid != 0)
	{
		if (pid == -1)
			ereport(PANIC,
					(errmsg("failed to fork a heartbeat receiver child")));
		return pid;
	}

	on_exit_reset();
	processType = PT_HB_RECEIVER;

	if (fork_wait_time > 0)
	{
		sleep(fork_wait_time);
	}

	POOL_SETMASK(&UnBlockSig);

	signal(SIGTERM, hb_receiver_exit);
	signal(SIGINT, hb_receiver_exit);
	signal(SIGQUIT, hb_receiver_exit);
	signal(SIGCHLD, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGUSR1, SIG_IGN);
	signal(SIGUSR2, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGALRM, SIG_IGN);

	init_ps_display("", "", "", "");
	/* Create per loop iteration memory context */
	ProcessLoopContext = AllocSetContextCreate(TopMemoryContext,
											   "wdhb_hb_receiver",
											   ALLOCSET_DEFAULT_MINSIZE,
											   ALLOCSET_DEFAULT_INITSIZE,
											   ALLOCSET_DEFAULT_MAXSIZE);
	
	MemoryContextSwitchTo(TopMemoryContext);

	sock = wd_create_hb_recv_socket(hb_if);

	set_ps_display("heartbeat receiver", false);

	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* Since not using PG_TRY, must reset error stack by hand */
		error_context_stack = NULL;
		
		EmitErrorReport();
		MemoryContextSwitchTo(TopMemoryContext);
		FlushErrorState();
	}
	
	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	for(;;)
	{
		MemoryContextSwitchTo(ProcessLoopContext);
		MemoryContextResetAndDeleteChildren(ProcessLoopContext);

		/* receive heartbeat signal */
		wd_hb_recv(sock, &pkt);
			/* authentication */
		if (strlen(pool_config->wd_authkey))
		{
			/* calculate hash from packet */
			pack_str_len = packet_to_string_hb(&pkt, pack_str, sizeof(pack_str));
			wd_calc_hash(pack_str, pack_str_len, buf);

			if (strcmp(pkt.hash, buf))
				ereport(ERROR,
					(errmsg("watchdog heartbeat receive"),
						 errdetail("authentication failed")));
		}

		/* get current time */
		gettimeofday(&tv, NULL);

		/* who send this packet? */
		strlcpy(from, pkt.from, sizeof(from));
		from_pgpool_port = pkt.from_pgpool_port;

		p = WD_List;
		while (p->status != WD_END)
		{
			if (!strcmp(p->hostname, from) && p->pgpool_port == from_pgpool_port)
			{
				/* ignore the packet from down pgpool */
				if (pkt.status == WD_DOWN)
				{
					ereport(DEBUG1,
						(errmsg("watchdog heartbeat: received heartbeat signal from \"%s:%d\" whose status is down. ignored",
									from, from_pgpool_port)));
					break;
				}

				/* this is the first packet or the latest packet */
				if (!WD_TIME_ISSET(p->hb_send_time) ||
					WD_TIME_BEFORE(p->hb_send_time, pkt.send_time))
				{
					ereport(DEBUG1,
							(errmsg("watchdog heartbeat: received heartbeat signal from \"%s:%d\"",
									from, from_pgpool_port)));

					p->hb_send_time = pkt.send_time;
					p->hb_last_recv_time = tv;
				}
				else
				{
					ereport(DEBUG1,
							(errmsg("watchdog heartbeat: received heartbeat signal is older than the latest, ignored")));
				}
				break;
			}
			p++;
		}

	}

	return pid;
}
/*
 * Postmaster subroutine to start a syslogger subprocess.
 */
int
SysLogger_Start(void)
{
	pid_t		sysloggerPid;
	char	   *filename;

	if (!Logging_collector)
		return 0;

	/*
	 * If first time through, create the pipe which will receive stderr
	 * output.
	 *
	 * If the syslogger crashes and needs to be restarted, we continue to use
	 * the same pipe (indeed must do so, since extant backends will be writing
	 * into that pipe).
	 *
	 * This means the postmaster must continue to hold the read end of the
	 * pipe open, so we can pass it down to the reincarnated syslogger. This
	 * is a bit klugy but we have little choice.
	 */
#ifndef WIN32
	if (syslogPipe[0] < 0)
	{
		if (pipe(syslogPipe) < 0)
			ereport(FATAL,
					(errcode_for_socket_access(),
					 (errmsg("could not create pipe for syslog: %m"))));
	}
#else
	if (!syslogPipe[0])
	{
		SECURITY_ATTRIBUTES sa;

		memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
		sa.nLength = sizeof(SECURITY_ATTRIBUTES);
		sa.bInheritHandle = TRUE;

		if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, 32768))
			ereport(FATAL,
					(errcode_for_file_access(),
					 (errmsg("could not create pipe for syslog: %m"))));
	}
#endif

	/*
	 * Create log directory if not present; ignore errors
	 */
	mkdir(Log_directory, S_IRWXU);

	/*
	 * The initial logfile is created right in the postmaster, to verify that
	 * the Log_directory is writable.  We save the reference time so that the
	 * syslogger child process can recompute this file name.
	 *
	 * It might look a bit strange to re-do this during a syslogger restart,
	 * but we must do so since the postmaster closed syslogFile after the
	 * previous fork (and remembering that old file wouldn't be right anyway).
	 * Note we always append here, we won't overwrite any existing file.  This
	 * is consistent with the normal rules, because by definition this is not
	 * a time-based rotation.
	 */
	first_syslogger_file_time = time(NULL);
	filename = logfile_getname(first_syslogger_file_time, NULL);

	syslogFile = logfile_open(filename, "a", false);

	pfree(filename);

#ifdef EXEC_BACKEND
	switch ((sysloggerPid = syslogger_forkexec()))
#else
	switch ((sysloggerPid = fork_process()))
#endif
	{
		case -1:
			ereport(LOG,
					(errmsg("could not fork system logger: %m")));
			return 0;

#ifndef EXEC_BACKEND
		case 0:
			/* in postmaster child ... */
			/* Close the postmaster's sockets */
			ClosePostmasterPorts(true);

			/* Lose the postmaster's on-exit routines */
			on_exit_reset();

			/* Drop our connection to postmaster's shared memory, as well */
			PGSharedMemoryDetach();

			/* do the work */
			SysLoggerMain(0, NULL);
			break;
#endif

		default:
			/* success, in postmaster */

			/* now we redirect stderr, if not done already */
			if (!redirection_done)
			{
#ifndef WIN32
				fflush(stdout);
				if (dup2(syslogPipe[1], fileno(stdout)) < 0)
					ereport(FATAL,
							(errcode_for_file_access(),
							 errmsg("could not redirect stdout: %m")));
				fflush(stderr);
				if (dup2(syslogPipe[1], fileno(stderr)) < 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
				int			fd;

				/*
				 * 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, _fileno(stderr)) < 0)
					ereport(FATAL,
							(errcode_for_file_access(),
							 errmsg("could not redirect stderr: %m")));
				close(fd);
				_setmode(_fileno(stderr), _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; close it */
			fclose(syslogFile);
			syslogFile = NULL;
			return (int) sysloggerPid;
	}

	/* we should never reach here */
	return 0;
}
Exemple #15
0
/**
 * This method is called after fork of the sweeper process. It sets up signal
 * handlers and does initialization that is required by a postgres backend.
 */
NON_EXEC_STATIC void
BackoffSweeperMain(int argc, char *argv[])
{
	sigjmp_buf	local_sigjmp_buf;

	IsUnderPostmaster = true;
	isSweeperProcess = true;

	/* Stay away from PMChildSlot */
	MyPMChildSlot = -1;

	/* reset MyProcPid */
	MyProcPid = getpid();

	/* Lose the postmaster's on-exit routines */
	on_exit_reset();

	/* Identify myself via ps */
	init_ps_display("sweeper process", "", "", "");

	SetProcessingMode(InitProcessing);

	/*
	 * Set up signal handlers.  We operate on databases much like a regular
	 * backend, so we use the same signal handling.  See equivalent code in
	 * tcop/postgres.c.
	 */
	pqsignal(SIGHUP, SIG_IGN);
	pqsignal(SIGINT, SIG_IGN);
	pqsignal(SIGALRM, SIG_IGN);
	pqsignal(SIGPIPE, SIG_IGN);
	pqsignal(SIGUSR1, SIG_IGN);

	pqsignal(SIGTERM, die);
	pqsignal(SIGQUIT, quickdie);
	pqsignal(SIGUSR2, BackoffRequestShutdown);

	pqsignal(SIGFPE, FloatExceptionHandler);
	pqsignal(SIGCHLD, SIG_DFL);

	/*
	 * Copied from bgwriter
	 */
	CurrentResourceOwner = ResourceOwnerCreate(NULL, "Sweeper process");

	/* Early initialization */
	BaseInit();

	/* See InitPostgres()... */
	InitProcess();

	SetProcessingMode(NormalProcessing);

	/*
	 * If an exception is encountered, processing resumes here.
	 *
	 * See notes in postgres.c about the design of this coding.
	 */
	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* Prevents interrupts while cleaning up */
		HOLD_INTERRUPTS();

		/* Report the error to the server log */
		EmitErrorReport();

		/*
		 * We can now go away.  Note that because we'll call InitProcess, a
		 * callback will be registered to do ProcKill, which will clean up
		 * necessary state.
		 */
		proc_exit(0);
	}

	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	PG_SETMASK(&UnBlockSig);

	MyBackendId = InvalidBackendId;

	/* main loop */
	BackoffSweeperLoop();

	/* One iteration done, go away */
	proc_exit(0);
}
Exemple #16
0
/*
 * Main entry point for autovacuum controller process.
 *
 * This code is heavily based on pgarch.c, q.v.
 */
int
autovac_start(void)
{
    time_t		curtime;
    pid_t		AutoVacPID;

    /*
     * Do nothing if too soon since last autovacuum exit.  This limits how
     * often the daemon runs.  Since the time per iteration can be quite
     * variable, it seems more useful to measure/control the time since last
     * subprocess exit than since last subprocess launch.
     *
     * However, we *also* check the time since last subprocess launch; this
     * prevents thrashing under fork-failure conditions.
     *
     * Note that since we will be re-called from the postmaster main loop, we
     * will get another chance later if we do nothing now.
     *
     * XXX todo: implement sleep scale factor that existed in contrib code.
     */

    curtime = time(NULL);
    if ((unsigned int) (curtime - last_autovac_stop_time) <
            (unsigned int) autovacuum_naptime)
        return 0;

    if ((unsigned int) (curtime - last_autovac_start_time) <
            (unsigned int) autovacuum_naptime)
        return 0;

    last_autovac_start_time = curtime;

#ifdef EXEC_BACKEND
    switch ((AutoVacPID = autovac_forkexec()))
#else
    switch ((AutoVacPID = fork_process()))
#endif
    {
    case -1:
        ereport(LOG,
                (errmsg("could not fork autovacuum process: %m")));
        return 0;

#ifndef EXEC_BACKEND
    case 0:
        /* in postmaster child ... */
        /* Close the postmaster's sockets */
        ClosePostmasterPorts(false);

        /* Lose the postmaster's on-exit routines */
        on_exit_reset();

        AutoVacMain(0, NULL);
        break;
#endif
    default:
        return (int) AutoVacPID;
    }

    /* shouldn't get here */
    return 0;
}
Exemple #17
0
/* fork lifecheck process*/
static pid_t
fork_a_lifecheck(int fork_wait_time)
{
	pid_t pid;
	sigjmp_buf	local_sigjmp_buf;

	pid = fork();
	if (pid != 0)
	{
		if (pid == -1)
			ereport(ERROR,
					(errmsg("failed to fork a lifecheck process")));
		return pid;
	}
    on_exit_reset();
	processType = PT_LIFECHECK;

	if (fork_wait_time > 0) {
		sleep(fork_wait_time);
	}

	POOL_SETMASK(&UnBlockSig);

	init_ps_display("", "", "", "");

	signal(SIGTERM, wd_exit);	
	signal(SIGINT, wd_exit);	
	signal(SIGQUIT, wd_exit);	
	signal(SIGCHLD, SIG_DFL);
	signal(SIGHUP, SIG_IGN);	
	signal(SIGPIPE, SIG_IGN);

	/* Create per loop iteration memory context */
	ProcessLoopContext = AllocSetContextCreate(TopMemoryContext,
											   "wd_lifecheck_main_loop",
											   ALLOCSET_DEFAULT_MINSIZE,
											   ALLOCSET_DEFAULT_INITSIZE,
											   ALLOCSET_DEFAULT_MAXSIZE);
	
	MemoryContextSwitchTo(TopMemoryContext);

	set_ps_display("lifecheck",false);

	/* wait until ready to go */
	while (WD_OK != is_wd_lifecheck_ready())
	{
		sleep(pool_config->wd_interval * 10);
	}
	ereport(LOG,
			(errmsg("watchdog: lifecheck started")));

	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* Since not using PG_TRY, must reset error stack by hand */
		error_context_stack = NULL;
		
		EmitErrorReport();
		MemoryContextSwitchTo(TopMemoryContext);
		FlushErrorState();
		sleep(pool_config->wd_heartbeat_keepalive);
	}
	
	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	/* watchdog loop */
	for (;;)
	{
		MemoryContextSwitchTo(ProcessLoopContext);
		MemoryContextResetAndDeleteChildren(ProcessLoopContext);

		/* pgpool life check */
		wd_lifecheck();
		sleep(pool_config->wd_interval);
	}

	return pid;
}
Exemple #18
0
int
main(int argc, char **argv)
{
	MyStorage  *storage;
	int			cpid;

	printf("Creating shared memory ... ");
	fflush(stdout);

	storage = (MyStorage *) PGSharedMemoryCreate(8192, false, 5433);

	storage->flag = 1234;

	printf("OK\n");

	printf("Creating semaphores ... ");
	fflush(stdout);

	PGReserveSemaphores(2, 5433);

	PGSemaphoreCreate(&storage->sem);

	printf("OK\n");

	/* sema initial value is 1, so lock should work */

	printf("Testing Lock ... ");
	fflush(stdout);

	PGSemaphoreLock(&storage->sem, false);

	printf("OK\n");

	/* now sema value is 0, so trylock should fail */

	printf("Testing TryLock ... ");
	fflush(stdout);

	if (PGSemaphoreTryLock(&storage->sem))
		printf("unexpected result!\n");
	else
		printf("OK\n");

	/* unlocking twice and then locking twice should work... */

	printf("Testing Multiple Lock ... ");
	fflush(stdout);

	PGSemaphoreUnlock(&storage->sem);
	PGSemaphoreUnlock(&storage->sem);

	PGSemaphoreLock(&storage->sem, false);
	PGSemaphoreLock(&storage->sem, false);

	printf("OK\n");

	/* check Reset too */

	printf("Testing Reset ... ");
	fflush(stdout);

	PGSemaphoreUnlock(&storage->sem);

	PGSemaphoreReset(&storage->sem);

	if (PGSemaphoreTryLock(&storage->sem))
		printf("unexpected result!\n");
	else
		printf("OK\n");

	/* Fork a child process and see if it can communicate */

	printf("Forking child process ... ");
	fflush(stdout);

	cpid = fork();
	if (cpid == 0)
	{
		/* In child */
		on_exit_reset();
		sleep(3);
		storage->flag++;
		PGSemaphoreUnlock(&storage->sem);
		proc_exit(0);
	}
	if (cpid < 0)
	{
		/* Fork failed */
		printf("failed: %s\n", strerror(errno));
		proc_exit(1);
	}

	printf("forked child pid %d OK\n", cpid);

	if (storage->flag != 1234)
		printf("Wrong value found in shared memory!\n");

	printf("Waiting for child (should wait 3 sec here) ... ");
	fflush(stdout);

	PGSemaphoreLock(&storage->sem, false);

	printf("OK\n");

	if (storage->flag != 1235)
		printf("Wrong value found in shared memory!\n");

	/* Test shutdown */

	printf("Running shmem_exit processing ... ");
	fflush(stdout);

	shmem_exit(0);

	printf("OK\n");

	printf("Tests complete.\n");

	proc_exit(0);

	return 0;					/* not reached */
}
Exemple #19
0
Fichier : fts.c Projet : LJoNe/gpdb
/*
 * FtsProbeMain
 */
NON_EXEC_STATIC void
ftsMain(int argc, char *argv[])
{
	sigjmp_buf	local_sigjmp_buf;
	char	   *fullpath;

	IsUnderPostmaster = true;
	am_ftsprobe = true;

	/* Stay away from PMChildSlot */
	MyPMChildSlot = -1;

	/* reset MyProcPid */
	MyProcPid = getpid();
	
	/* Lose the postmaster's on-exit routines */
	on_exit_reset();

	/* Identify myself via ps */
	init_ps_display("ftsprobe process", "", "", "");

	SetProcessingMode(InitProcessing);

	/*
	 * reread postgresql.conf if requested
	 */
	pqsignal(SIGHUP, sigHupHandler);

	/*
	 * Presently, SIGINT will lead to autovacuum shutdown, because that's how
	 * we handle ereport(ERROR).  It could be improved however.
	 */
	pqsignal(SIGINT, ReqFtsFullScan);		/* request full-scan */
	pqsignal(SIGTERM, die);
	pqsignal(SIGQUIT, quickdie); /* we don't do any ftsprobe specific cleanup, just use the standard. */
	pqsignal(SIGALRM, handle_sig_alarm);

	pqsignal(SIGPIPE, SIG_IGN);
	pqsignal(SIGUSR1, procsignal_sigusr1_handler);
	/* We don't listen for async notifies */
	pqsignal(SIGUSR2, RequestShutdown);
	pqsignal(SIGFPE, FloatExceptionHandler);
	pqsignal(SIGCHLD, SIG_DFL);

	/*
	 * Copied from bgwriter
	 */
	CurrentResourceOwner = ResourceOwnerCreate(NULL, "FTS Probe");

	/* Early initialization */
	BaseInit();

	/* See InitPostgres()... */
	InitProcess();	
	InitBufferPoolBackend();
	InitXLOGAccess();

	SetProcessingMode(NormalProcessing);

	/*
	 * If an exception is encountered, processing resumes here.
	 *
	 * See notes in postgres.c about the design of this coding.
	 */
	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* Prevents interrupts while cleaning up */
		HOLD_INTERRUPTS();

		/* Report the error to the server log */
		EmitErrorReport();

		/*
		 * We can now go away.	Note that because we'll call InitProcess, a
		 * callback will be registered to do ProcKill, which will clean up
		 * necessary state.
		 */
		proc_exit(0);
	}

	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	PG_SETMASK(&UnBlockSig);

	/*
	 * Add my PGPROC struct to the ProcArray.
	 *
	 * Once I have done this, I am visible to other backends!
	 */
	InitProcessPhase2();

	/*
	 * Initialize my entry in the shared-invalidation manager's array of
	 * per-backend data.
	 *
	 * Sets up MyBackendId, a unique backend identifier.
	 */
	MyBackendId = InvalidBackendId;

	SharedInvalBackendInit(false);

	if (MyBackendId > MaxBackends || MyBackendId <= 0)
		elog(FATAL, "bad backend id: %d", MyBackendId);

	/*
	 * bufmgr needs another initialization call too
	 */
	InitBufferPoolBackend();

	/* heap access requires the rel-cache */
	RelationCacheInitialize();
	InitCatalogCache();

	/*
	 * It's now possible to do real access to the system catalogs.
	 *
	 * Load relcache entries for the system catalogs.  This must create at
	 * least the minimum set of "nailed-in" cache entries.
	 */
	RelationCacheInitializePhase2();

	/*
	 * In order to access the catalog, we need a database, and a
	 * tablespace; our access to the heap is going to be slightly
	 * limited, so we'll just use some defaults.
	 */
	if (!FindMyDatabase(probeDatabase, &MyDatabaseId, &MyDatabaseTableSpace))
		ereport(FATAL,
				(errcode(ERRCODE_UNDEFINED_DATABASE),
				 errmsg("database \"%s\" does not exit", probeDatabase)));

	/* Now we can mark our PGPROC entry with the database ID */
	/* (We assume this is an atomic store so no lock is needed) */
	MyProc->databaseId = MyDatabaseId;

	fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace);

	SetDatabasePath(fullpath);

	RelationCacheInitializePhase3();

	/* shmem: publish probe pid */
	ftsProbeInfo->fts_probePid = MyProcPid;

	/* main loop */
	FtsLoop();

	/* One iteration done, go away */
	proc_exit(0);
}