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

📄 postmaster.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * postmaster.c *	  This program acts as a clearing house for requests to the *	  POSTGRES system.	Frontend programs send a startup message *	  to the Postmaster and the postmaster uses the info in the *	  message to setup a backend process. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.108 1999/07/07 17:17:48 momjian Exp $ * * NOTES * * Initialization: *		The Postmaster sets up a few shared memory data structures *		for the backends.  It should at the very least initialize the *		lock manager. * * Synchronization: *		The Postmaster shares memory with the backends and will have to lock *		the shared memory it accesses.	The Postmaster should never block *		on messages from clients. * * Garbage Collection: *		The Postmaster cleans up after backends if they have an emergency *		exit and/or core dump. * * Communication: * *------------------------------------------------------------------------- */ /* moved here to prevent double define */#include <sys/param.h>			/* for MAXHOSTNAMELEN on most */#ifdef HAVE_NETDB_H#include <netdb.h>				/* for MAXHOSTNAMELEN on some */#endif#ifndef MAXHOSTNAMELEN#define MAXHOSTNAMELEN 256#endif#include "postgres.h"#include <signal.h>#include <string.h>#include <stdlib.h>#include <time.h>#if !defined(NO_UNISTD_H)#include <unistd.h>#endif	 /* !NO_UNISTD_H */#include <ctype.h>#include <sys/types.h>			/* for fd_set stuff */#include <sys/stat.h>			/* for umask */#include <sys/time.h>#include <sys/socket.h>#ifdef HAVE_LIMITS_H#include <limits.h>#else#include <values.h>#endif#include <sys/wait.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifdef __CYGWIN32__#include <getopt.h>#endif#include "storage/ipc.h"#include "libpq/libpq.h"#include "libpq/auth.h"#include "libpq/pqcomm.h"#include "libpq/pqsignal.h"#include "libpq/crypt.h"#include "miscadmin.h"#include "version.h"#include "lib/dllist.h"#include "tcop/tcopprot.h"#include "commands/async.h"#include "nodes/nodes.h"#include "utils/mcxt.h"#include "storage/proc.h"#include "utils/elog.h"#ifndef HAVE_GETHOSTNAME#include "port-protos.h"		/* For gethostname() */#endif#include "storage/fd.h"#include "utils/trace.h"#if !defined(MAXINT)#define MAXINT		   INT_MAX#endif#define INVALID_SOCK	(-1)#define ARGV_SIZE	64 /*  * Max time in seconds for socket to linger (close() to block) waiting  * for frontend to retrieve its message from us.  *//* * Info for garbage collection.  Whenever a process dies, the Postmaster * cleans up after it.	Currently, NO information is required for cleanup, * but I left this structure around in case that changed. */typedef struct bkend{	int			pid;			/* process id of backend */	long		cancel_key;		/* cancel key for cancels for this backend */} Backend;Port	   *MyBackendPort = NULL;/* list of active backends.  For garbage collection only now. */static Dllist *BackendList;/* list of ports associated with still open, but incomplete connections */static Dllist *PortList;static unsigned short PostPortName = 0;static short ActiveBackends = FALSE; /*  * This is a boolean indicating that there is at least one backend that  * is accessing the current shared memory and semaphores. Between the  * time that we start up, or throw away shared memory segments and start  * over, and the time we generate the next backend (because we received a  * connection request), it is false. Other times, it is true.  */static short shmem_seq = 0; /*  * This is a sequence number that indicates how many times we've had to  * throw away the shared memory and start over because we doubted its  * integrity.	It starts off at zero and is incremented every time we  * start over.  We use this to ensure that we use a new IPC shared memory  * key for the new shared memory segment in case the old segment isn't  * entirely gone yet.  *  * The sequence actually cycles back to 0 after 9, so pathologically there  * could be an IPC failure if 10 sets of backends are all stuck and won't  * release IPC resources.  */static IpcMemoryKey ipc_key; /*  * This is the base IPC shared memory key.  Other keys are generated by  * adding to this.  */static int	MaxBackends = DEF_MAXBACKENDS; /*  * MaxBackends is the actual limit on the number of backends we will  * start. The default is established by configure, but it can be  * readjusted from 1..MAXBACKENDS with the postmaster -N switch. Note  * that a larger MaxBackends value will increase the size of the shared  * memory area as well as cause the postmaster to grab more kernel  * semaphores, even if you never actually use that many backends.  */static int	NextBackendTag = MAXINT;	/* XXX why count down not up? */static char *progname = (char *) NULL;static char **real_argv;static int	real_argc;/* * Default Values */static char Execfile[MAXPATHLEN] = "";static int	ServerSock_INET = INVALID_SOCK;		/* stream socket server */#ifndef __CYGWIN32__static int	ServerSock_UNIX = INVALID_SOCK;		/* stream socket server */#endif/* * Set by the -o option */static char ExtraOptions[MAXPATHLEN] = "";/* * These globals control the behavior of the postmaster in case some * backend dumps core.	Normally, it kills all peers of the dead backend * and reinitializes shared memory.  By specifying -s or -n, we can have * the postmaster stop (rather than kill) peers and not reinitialize * shared data structures. */static bool Reinit = true;static int	SendStop = false;static bool NetServer = false;	/* if not zero, postmaster listen for								 * non-local connections *//* * GH: For !HAVE_SIGPROCMASK (NEXTSTEP), TRH implemented an * alternative interface. */#ifdef HAVE_SIGPROCMASKstatic sigset_t oldsigmask,			newsigmask;#elsestatic int	orgsigmask = sigblock(0);#endif/* * State for assigning random salts and cancel keys. * Also, the global MyCancelKey passes the cancel key assigned to a given * backend from the postmaster to that backend (via fork). */static unsigned int random_seed = 0;extern char *optarg;extern int	optind,			opterr;/* * postmaster.c - function prototypes */static void pmdaemonize(void);static Port *ConnCreate(int serverFd);static void reset_shared(unsigned short port);static void pmdie(SIGNAL_ARGS);static void reaper(SIGNAL_ARGS);static void dumpstatus(SIGNAL_ARGS);static void CleanupProc(int pid, int exitstatus);static int	DoBackend(Port *port);static void ExitPostmaster(int status);static void usage(const char *);static int	ServerLoop(void);static int	BackendStartup(Port *port);static int	readStartupPacket(void *arg, PacketLen len, void *pkt);static int	processCancelRequest(Port *port, PacketLen len, void *pkt);static int	initMasks(fd_set *rmask, fd_set *wmask);static long PostmasterRandom(void);static void RandomSalt(char *salt);static void SignalChildren(SIGNAL_ARGS);static int	CountChildren(void);#ifdef CYR_RECODEvoid		GetCharSetByHost(char *, int, char *);#endif#ifdef USE_ASSERT_CHECKINGint			assert_enabled = 1;#endifstatic voidcheckDataDir(const char *DataDir, bool *DataDirOK){	if (DataDir == NULL)	{		fprintf(stderr, "%s does not know where to find the database system "				"data.  You must specify the directory that contains the "				"database system either by specifying the -D invocation "			 "option or by setting the PGDATA environment variable.\n\n",				progname);		*DataDirOK = false;	}	else	{		char		path[MAXPATHLEN];		FILE	   *fp;		sprintf(path, "%s%cbase%ctemplate1%cpg_class",				DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR);#ifndef __CYGWIN32__		fp = AllocateFile(path, "r");#else		fp = AllocateFile(path, "rb");#endif		if (fp == NULL)		{			fprintf(stderr, "%s does not find the database system.  "					"Expected to find it "			   "in the PGDATA directory \"%s\", but unable to open file "					"with pathname \"%s\".\n\n",					progname, DataDir, path);			*DataDirOK = false;		}		else		{			char	   *reason;			/* reason ValidatePgVersion failed.  NULL if didn't */			FreeFile(fp);			ValidatePgVersion(DataDir, &reason);			if (reason)			{				fprintf(stderr,						"Database system in directory %s "						"is not compatible with this version of "						"Postgres, or we are unable to read the "						"PG_VERSION file.  "						"Explanation from ValidatePgVersion: %s\n\n",						DataDir, reason);				free(reason);				*DataDirOK = false;			}			else				*DataDirOK = true;		}	}}intPostmasterMain(int argc, char *argv[]){	extern int	NBuffers;		/* from buffer/bufmgr.c */	int			opt;	char	   *hostName;	int			status;	int			silentflag = 0;	bool		DataDirOK;		/* We have a usable PGDATA value */	char		hostbuf[MAXHOSTNAMELEN];	int			nonblank_argc;	/*	 * We need three params so we can display status.  If we don't get	 * them from the user, let's make them ourselves.	 */	if (argc < 5)	{		int			i;		char	   *new_argv[6];		for (i = 0; i < argc; i++)			new_argv[i] = argv[i];		for (; i < 5; i++)			new_argv[i] = "";		new_argv[5] = NULL;		if (!Execfile[0] && FindExec(Execfile, argv[0], "postmaster") < 0)		{			fprintf(stderr, "%s: could not find postmaster to execute...\n",					argv[0]);			exit(1);		}		new_argv[0] = Execfile;		execv(new_argv[0], new_argv);		/* How did we get here, error! */		perror(new_argv[0]);		fprintf(stderr, "PostmasterMain execv failed on %s\n", argv[0]);		exit(1);	}	progname = argv[0];	real_argv = argv;	real_argc = argc;	/*	 * don't process any dummy args we placed at the end for status	 * display	 */	for (nonblank_argc = argc; nonblank_argc > 0; nonblank_argc--)		if (argv[nonblank_argc - 1] != NULL && argv[nonblank_argc - 1][0] != '\0')			break;	/*	 * for security, no dir or file created can be group or other	 * accessible	 */	umask((mode_t) 0077);	if (!(hostName = getenv("PGHOST")))	{		if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)			strcpy(hostbuf, "localhost");		hostName = hostbuf;	}	MyProcPid = getpid();	DataDir = getenv("PGDATA"); /* default value */	opterr = 0;	while ((opt = getopt(nonblank_argc, argv, "A:a:B:b:D:dim:MN:no:p:Ss")) != EOF)	{		switch (opt)		{			case 'A':#ifndef USE_ASSERT_CHECKING				fprintf(stderr, "Assert checking is not enabled\n");#else				/*				 * Pass this option also to each backend.				 */				assert_enabled = atoi(optarg);				strcat(ExtraOptions, " -A ");				strcat(ExtraOptions, optarg);#endif				break;			case 'a':				/* Can no longer set authentication method. */				break;			case 'B':				/*				 * The number of buffers to create.  Setting this option				 * means we have to start each backend with a -B # to make				 * sure they know how many buffers were allocated.				 */				NBuffers = atoi(optarg);				strcat(ExtraOptions, " -B ");				strcat(ExtraOptions, optarg);				break;			case 'b':				/* Set the backend executable file to use. */				if (!ValidateBinary(optarg))					strcpy(Execfile, optarg);				else				{					fprintf(stderr, "%s: invalid backend \"%s\"\n",							progname, optarg);					exit(2);				}				break;			case 'D':				/* Set PGDATA from the command line. */				DataDir = optarg;				break;			case 'd':				/*				 * Turn on debugging for the postmaster and the backend				 * servers descended from it.				 */				if ((optind < nonblank_argc) && *argv[optind] != '-')				{					DebugLvl = atoi(argv[optind]);					optind++;				}				else					DebugLvl = 1;				pg_options[TRACE_VERBOSE] = DebugLvl;				break;			case 'i':				NetServer = true;				break;			case 'm':				/* Multiplexed backends no longer supported. */				break;			case 'M':				/*				 * ignore this flag.  This may be passed in because the				 * program was run as 'postgres -M' instead of				 * 'postmaster'				 */				break;			case 'N':				/*				 * The max number of backends to start. Can't set to less				 * than 1 or more than compiled-in limit.				 */				MaxBackends = atoi(optarg);				if (MaxBackends < 1)					MaxBackends = 1;				if (MaxBackends > MAXBACKENDS)					MaxBackends = MAXBACKENDS;				break;			case 'n':				/* Don't reinit shared mem after abnormal exit */				Reinit = false;				break;			case 'o':				/*				 * Other options to pass to the backend on the command				 * line -- useful only for debugging.				 */				strcat(ExtraOptions, " ");				strcat(ExtraOptions, optarg);				break;			case 'p':				/* Set PGPORT by hand. */				PostPortName = (unsigned short) atoi(optarg);				break;			case 'S':				/*				 * Start in 'S'ilent mode (disassociate from controlling				 * tty). You may also think of this as 'S'ysV mode since				 * it's most badly needed on SysV-derived systems like				 * SVR4 and HP-UX.				 */				silentflag = 1;				break;			case 's':				/*				 * In the event that some backend dumps core, send				 * SIGSTOP, rather than SIGUSR1, to all its peers.	This				 * lets the wily post_hacker collect core dumps from				 * everyone.				 */				SendStop = true;				break;			default:				/* usage() never returns */				usage(progname);				break;		}	}	/*	 * Select default values for switches where needed	 */	if (PostPortName == 0)		PostPortName = (unsigned short)pq_getport();	/*	 * Check for invalid combinations of switches	 */	if (NBuffers < 2 * MaxBackends || NBuffers < 16)	{		/* Do not accept -B so small that backends are likely to starve for		 * lack of buffers.  The specific choices here are somewhat arbitrary.		 */		fprintf(stderr, "%s: -B must be at least twice -N and at least 16.\n",				progname);		exit(1);	}	checkDataDir(DataDir, &DataDirOK);	/* issues error messages */	if (!DataDirOK)	{		fprintf(stderr, "No data directory -- can't proceed.\n");		exit(2);	}	if (!Execfile[0] && FindExec(Execfile, argv[0], "postgres") < 0)	{		fprintf(stderr, "%s: could not find backend to execute...\n",				argv[0]);		exit(1);	}	if (NetServer)	{		status = StreamServerPort(hostName, PostPortName, &ServerSock_INET);		if (status != STATUS_OK)		{			fprintf(stderr, "%s: cannot create INET stream port\n",					progname);			exit(1);		}	}#ifndef __CYGWIN32__	status = StreamServerPort(NULL, PostPortName, &ServerSock_UNIX);	if (status != STATUS_OK)	{

⌨️ 快捷键说明

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