⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 postmaster.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
		{			/*			 * Found entry for freshly-dead backend, so remove it.			 */			DLRemove(curr);			free(bp);			DLFreeElem(curr);		}		curr = next;	}	if (pid == CheckPointPID)	{		CheckPointPID = 0;		checkpointed = 0;	}	else	{		/*		 * Tell the collector about backend termination		 */		pgstat_beterm(pid);	}	FatalError = true;}/* * Log the death of a child process. */static voidLogChildExit(int lev, const char *procname, int pid, int exitstatus){	if (WIFEXITED(exitstatus))		ereport(lev,		/*		 * translator: %s is a noun phrase describing a child process,		 * such as "server process"		 */				(errmsg("%s (PID %d) exited with exit code %d",						procname, pid, WEXITSTATUS(exitstatus))));	else if (WIFSIGNALED(exitstatus))		ereport(lev,		/*		 * translator: %s is a noun phrase describing a child process,		 * such as "server process"		 */				(errmsg("%s (PID %d) was terminated by signal %d",						procname, pid, WTERMSIG(exitstatus))));	else		ereport(lev,		/*		 * translator: %s is a noun phrase describing a child process,		 * such as "server process"		 */				(errmsg("%s (PID %d) exited with unexpected status %d",						procname, pid, exitstatus)));}/* * Send a signal to all backend children. */static voidSignalChildren(int signal){	Dlelem	   *curr,			   *next;	Backend    *bp;	curr = DLGetHead(BackendList);	while (curr)	{		next = DLGetSucc(curr);		bp = (Backend *) DLE_VAL(curr);		if (bp->pid != MyProcPid)		{			ereport(DEBUG2,					(errmsg_internal("sending signal %d to process %d",									 signal,									 (int) bp->pid)));			kill(bp->pid, signal);		}		curr = next;	}}/* * BackendStartup -- start backend process * * returns: STATUS_ERROR if the fork failed, STATUS_OK otherwise. */static intBackendStartup(Port *port){	Backend    *bn;				/* for backend cleanup */	pid_t		pid;#ifdef LINUX_PROFILE	struct itimerval prof_itimer;#endif	/*	 * Compute the cancel key that will be assigned to this backend. The	 * backend will have its own copy in the forked-off process' value of	 * MyCancelKey, so that it can transmit the key to the frontend.	 */	MyCancelKey = PostmasterRandom();	/*	 * Make room for backend data structure.  Better before the fork() so	 * we can handle failure cleanly.	 */	bn = (Backend *) malloc(sizeof(Backend));	if (!bn)	{		ereport(LOG,				(errcode(ERRCODE_OUT_OF_MEMORY),				 errmsg("out of memory")));		return STATUS_ERROR;	}	/*	 * Flush stdio channels just before fork, to avoid double-output	 * problems. Ideally we'd use fflush(NULL) here, but there are still a	 * few non-ANSI stdio libraries out there (like SunOS 4.1.x) that	 * coredump if we do. Presently stdout and stderr are the only stdio	 * output channels used by the postmaster, so fflush'ing them should	 * be sufficient.	 */	fflush(stdout);	fflush(stderr);#ifdef LINUX_PROFILE	/*	 * Linux's fork() resets the profiling timer in the child process. If	 * we want to profile child processes then we need to save and restore	 * the timer setting.  This is a waste of time if not profiling,	 * however, so only do it if commanded by specific -DLINUX_PROFILE	 * switch.	 */	getitimer(ITIMER_PROF, &prof_itimer);#endif#ifdef __BEOS__	/* Specific beos actions before backend startup */	beos_before_backend_startup();#endif	pid = fork();	if (pid == 0)				/* child */	{		int			status;#ifdef LINUX_PROFILE		setitimer(ITIMER_PROF, &prof_itimer, NULL);#endif#ifdef __BEOS__		/* Specific beos backend startup actions */		beos_backend_startup();#endif		free(bn);		status = BackendFork(port);		if (status != 0)			ereport(LOG,					(errmsg("connection startup failed")));		proc_exit(status);	}	/* in parent, error */	if (pid < 0)	{		int			save_errno = errno;#ifdef __BEOS__		/* Specific beos backend startup actions */		beos_backend_startup_failed();#endif		free(bn);		errno = save_errno;		ereport(LOG,			  (errmsg("could not fork new process for connection: %m")));		report_fork_failure_to_client(port, save_errno);		return STATUS_ERROR;	}	/* in parent, normal */	ereport(DEBUG2,			(errmsg_internal("forked new backend, pid=%d socket=%d",							 (int) pid, port->sock)));	/*	 * Everything's been successful, it's safe to add this backend to our	 * list of backends.	 */	bn->pid = pid;	bn->cancel_key = MyCancelKey;	DLAddHead(BackendList, DLNewElem(bn));	return STATUS_OK;}/* * Try to report backend fork() failure to client before we close the * connection.	Since we do not care to risk blocking the postmaster on * this connection, we set the connection to non-blocking and try only once. * * This is grungy special-purpose code; we cannot use backend libpq since * it's not up and running. */static voidreport_fork_failure_to_client(Port *port, int errnum){	char		buffer[1000];	/* Format the error message packet (always V2 protocol) */	snprintf(buffer, sizeof(buffer), "E%s%s\n",			 gettext("could not fork new process for connection: "),			 strerror(errnum));	/* Set port to non-blocking.  Don't do send() if this fails */	if (FCNTL_NONBLOCK(port->sock) < 0)		return;	send(port->sock, buffer, strlen(buffer) + 1, 0);}/* * split_opts -- split a string of options and append it to an argv array * * NB: the string is destructively modified! * * Since no current POSTGRES arguments require any quoting characters, * we can use the simple-minded tactic of assuming each set of space- * delimited characters is a separate argv element. * * If you don't like that, well, we *used* to pass the whole option string * as ONE argument to execl(), which was even less intelligent... */static voidsplit_opts(char **argv, int *argcp, char *s){	while (s && *s)	{		while (isspace((unsigned char) *s))			++s;		if (*s == '\0')			break;		argv[(*argcp)++] = s;		while (*s && !isspace((unsigned char) *s))			++s;		if (*s)			*s++ = '\0';	}}/* * BackendFork -- perform authentication, and if successful, set up the *		backend's argument list and invoke backend main(). * * This used to perform an execv() but we no longer exec the backend; * it's the same executable as the postmaster. * * returns: *		Shouldn't return at all. *		If PostgresMain() fails, return status. */static intBackendFork(Port *port){	char	  **av;	int			maxac;	int			ac;	char		debugbuf[32];	char		protobuf[32];#ifdef EXEC_BACKEND	char		pbuf[NAMEDATALEN + 256];#endif	int			i;	int			status;	struct timeval now;	struct timezone tz;	char		remote_host[NI_MAXHOST];	char		remote_port[NI_MAXSERV];	/*	 * Let's clean up ourselves as the postmaster child	 */	IsUnderPostmaster = true;	/* we are a postmaster subprocess now */	ClientAuthInProgress = true;	/* limit visibility of log messages */	/* We don't want the postmaster's proc_exit() handlers */	on_exit_reset();	/*	 * Signal handlers setting is moved to tcop/postgres...	 */	/* Close the postmaster's other sockets */	ClosePostmasterPorts(true);	/* Save port etc. for ps status */	MyProcPort = port;	/* Reset MyProcPid to new backend's pid */	MyProcPid = getpid();	/*	 * Initialize libpq and enable reporting of ereport errors to the	 * client. Must do this now because authentication uses libpq to send	 * messages.	 */	pq_init();					/* initialize libpq to talk to client */	whereToSendOutput = Remote; /* now safe to ereport to client */	/*	 * We arrange for a simple exit(0) if we receive SIGTERM or SIGQUIT	 * during any client authentication related communication. Otherwise	 * the postmaster cannot shutdown the database FAST or IMMED cleanly	 * if a buggy client blocks a backend during authentication.	 */	pqsignal(SIGTERM, authdie);	pqsignal(SIGQUIT, authdie);	pqsignal(SIGALRM, authdie);	PG_SETMASK(&AuthBlockSig);	/*	 * Get the remote host name and port for logging and status display.	 */	remote_host[0] = '\0';	remote_port[0] = '\0';	if (getnameinfo_all(&port->raddr.addr, port->raddr.salen,						remote_host, sizeof(remote_host),						remote_port, sizeof(remote_port),				   (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV))	{		getnameinfo_all(&port->raddr.addr, port->raddr.salen,						remote_host, sizeof(remote_host),						remote_port, sizeof(remote_port),						NI_NUMERICHOST | NI_NUMERICSERV);	}	if (Log_connections)		ereport(LOG,				(errmsg("connection received: host=%s port=%s",						remote_host, remote_port)));	if (LogSourcePort)	{		/* modify remote_host for use in ps status */		char		tmphost[NI_MAXHOST];		snprintf(tmphost, sizeof(tmphost), "%s:%s", remote_host, remote_port);		StrNCpy(remote_host, tmphost, sizeof(remote_host));	}	/*	 * PreAuthDelay is a debugging aid for investigating problems in the	 * authentication cycle: it can be set in postgresql.conf to allow	 * time to attach to the newly-forked backend with a debugger. (See	 * also the -W backend switch, which we allow clients to pass through	 * PGOPTIONS, but it is not honored until after authentication.)	 */	if (PreAuthDelay > 0)		sleep(PreAuthDelay);	/*	 * Ready to begin client interaction.  We will give up and exit(0)	 * after a time delay, so that a broken client can't hog a connection	 * indefinitely.  PreAuthDelay doesn't count against the time limit.	 */	if (!enable_sig_alarm(AuthenticationTimeout * 1000, false))		elog(FATAL, "could not set timer for authorization timeout");	/*	 * Receive the startup packet (which might turn out to be a cancel	 * request packet).	 */	status = ProcessStartupPacket(port, false);	if (status != STATUS_OK)		return 0;				/* cancel request processed, or error */	/*	 * Now that we have the user and database name, we can set the process	 * title for ps.  It's good to do this as early as possible in	 * startup.	 */	init_ps_display(port->user_name, port->database_name, remote_host);	set_ps_display("authentication");	/*	 * Now perform authentication exchange.	 */	ClientAuthentication(port); /* might not return, if failure */	/*	 * Done with authentication.  Disable timeout, and prevent	 * SIGTERM/SIGQUIT again until backend startup is complete.	 */	if (!disable_sig_alarm(false))		elog(FATAL, "could not disable timer for authorization timeout");	PG_SETMASK(&BlockSig);	if (Log_connections)		ereport(LOG,				(errmsg("connection authorized: user=%s database=%s",						port->user_name, port->database_name)));	/*	 * Don't want backend to be able to see the postmaster random number	 * generator state.  We have to clobber the static random_seed *and*	 * start a new random sequence in the random() library function.	 */	random_seed = 0;	gettimeofday(&now, &tz);	srandom((unsigned int) now.tv_usec);	/* ----------------	 * Now, build the argv vector that will be given to PostgresMain.	 *	 * The layout of the command line is	 *		postgres [secure switches] -p databasename [insecure switches]	 * where the switches after -p come from the client request.	 *	 * The maximum possible number of commandline arguments that could come	 * from ExtraOptions or port->cmdline_options is (strlen + 1) / 2; see	 * split_opts().	 * ----------------	 */	maxac = 10;					/* for fixed args supplied below */	maxac += (strlen(ExtraOptions) + 1) / 2;	if (port->cmdline_options)		maxac += (strlen(port->cmdline_options) + 1) / 2;	av = (char **) MemoryContextAlloc(TopMemoryContext,									  maxac * sizeof(char *));	ac = 0;	av[ac++] = "postgres";	/*	 * Pass the requested debugging level along to the backend.	 */	if (debug_flag > 0)	{		snprintf(debugbuf, sizeof(debugbuf), "-d%d", debug_flag);		av[ac++] = debugbuf;	}	/*	 * Pass any backend switches specified with -o in the postmaster's own	 * command line.  We assume these are secure. (It's OK to mangle	 * ExtraOptions since we are now in the child process; this won't	 * change the postmaster's copy.)	 */	split_opts(av, &ac, ExtraOptions);	/* Tell the backend what protocol the frontend is using. */	snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto);	av[ac++] = protobuf;	/*	 * Tell the backend it is being called from the postmaster, and which	 * database to use.  -p marks the end of secure switches.	 */	av[ac++] = "-p";#ifdef EXEC_BACKEND	Assert(UsedShmemSegID != 0 && UsedShmemSegAddr != NULL);	/* database name at the end because it might contain commas */	snprintf(pbuf, NAMEDATALEN + 256, "%d,%d,%d,%p,%s", port->sock, canAcceptConnections(),			 UsedShmemSegID, UsedShmemSegAddr, port->database_name);	av[ac++] = pbuf;#else	av[ac++] = port->database_name;#endif	/*	 * Pass the (insecure) option switches from the connection request.	 * (It's OK to mangle port->cmdline_options now.)	 */	if (port->cmdline_options)		split_opts(av, &ac, port->cmdline_options);	av[ac] = (char *) NULL;	Assert(ac < maxac);	/*	 * Release postmaster's working memory context so that backend can	 * recycle the space.  Note this does not trash *MyProcPort, because	 * ConnCreate() allocated that space with malloc() ... else we'd need	 * to copy the Port data here.	Also, subsidiary data such as the	 * username isn't lost either; see ProcessStartupPacket().	 */	MemoryContextSwitchTo(TopMemoryContext

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -