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

📄 postmaster.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
		while (offset < len)		{			char	   *nameptr = ((char *) buf) + offset;			int32		valoffset;			char	   *valptr;			if (*nameptr == '\0')				break;			/* found packet terminator */			valoffset = offset + strlen(nameptr) + 1;			if (valoffset >= len)				break;			/* missing value, will complain below */			valptr = ((char *) buf) + valoffset;			if (strcmp(nameptr, "database") == 0)				port->database_name = pstrdup(valptr);			else if (strcmp(nameptr, "user") == 0)				port->user_name = pstrdup(valptr);			else if (strcmp(nameptr, "options") == 0)				port->cmdline_options = pstrdup(valptr);			else			{				/* Assume it's a generic GUC option */				port->guc_options = lappend(port->guc_options,											pstrdup(nameptr));				port->guc_options = lappend(port->guc_options,											pstrdup(valptr));			}			offset = valoffset + strlen(valptr) + 1;		}		/*		 * If we didn't find a packet terminator exactly at the end of the		 * given packet length, complain.		 */		if (offset != len - 1)			ereport(FATAL,					(errcode(ERRCODE_PROTOCOL_VIOLATION),					 errmsg("invalid startup packet layout: expected terminator as last byte")));	}	else	{		/*		 * Get the parameters from the old-style, fixed-width-fields startup		 * packet as C strings.  The packet destination was cleared first so a		 * short packet has zeros silently added.  We have to be prepared to		 * truncate the pstrdup result for oversize fields, though.		 */		StartupPacket *packet = (StartupPacket *) buf;		port->database_name = pstrdup(packet->database);		if (strlen(port->database_name) > sizeof(packet->database))			port->database_name[sizeof(packet->database)] = '\0';		port->user_name = pstrdup(packet->user);		if (strlen(port->user_name) > sizeof(packet->user))			port->user_name[sizeof(packet->user)] = '\0';		port->cmdline_options = pstrdup(packet->options);		if (strlen(port->cmdline_options) > sizeof(packet->options))			port->cmdline_options[sizeof(packet->options)] = '\0';		port->guc_options = NIL;	}	/* Check a user name was given. */	if (port->user_name == NULL || port->user_name[0] == '\0')		ereport(FATAL,				(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),			 errmsg("no PostgreSQL user name specified in startup packet")));	/* The database defaults to the user name. */	if (port->database_name == NULL || port->database_name[0] == '\0')		port->database_name = pstrdup(port->user_name);	if (Db_user_namespace)	{		/*		 * If user@, it is a global user, remove '@'. We only want to do this		 * if there is an '@' at the end and no earlier in the user string or		 * they may fake as a local user of another database attaching to this		 * database.		 */		if (strchr(port->user_name, '@') ==			port->user_name + strlen(port->user_name) - 1)			*strchr(port->user_name, '@') = '\0';		else		{			/* Append '@' and dbname */			char	   *db_user;			db_user = palloc(strlen(port->user_name) +							 strlen(port->database_name) + 2);			sprintf(db_user, "%s@%s", port->user_name, port->database_name);			port->user_name = db_user;		}	}	/*	 * Truncate given database and user names to length of a Postgres name.	 * This avoids lookup failures when overlength names are given.	 */	if (strlen(port->database_name) >= NAMEDATALEN)		port->database_name[NAMEDATALEN - 1] = '\0';	if (strlen(port->user_name) >= NAMEDATALEN)		port->user_name[NAMEDATALEN - 1] = '\0';	/*	 * Done putting stuff in TopMemoryContext.	 */	MemoryContextSwitchTo(oldcontext);	/*	 * If we're going to reject the connection due to database state, say so	 * now instead of wasting cycles on an authentication exchange. (This also	 * allows a pg_ping utility to be written.)	 */	switch (port->canAcceptConnections)	{		case CAC_STARTUP:			ereport(FATAL,					(errcode(ERRCODE_CANNOT_CONNECT_NOW),					 errmsg("the database system is starting up")));			break;		case CAC_SHUTDOWN:			ereport(FATAL,					(errcode(ERRCODE_CANNOT_CONNECT_NOW),					 errmsg("the database system is shutting down")));			break;		case CAC_RECOVERY:			ereport(FATAL,					(errcode(ERRCODE_CANNOT_CONNECT_NOW),					 errmsg("the database system is in recovery mode")));			break;		case CAC_TOOMANY:			ereport(FATAL,					(errcode(ERRCODE_TOO_MANY_CONNECTIONS),					 errmsg("sorry, too many clients already")));			break;		case CAC_OK:		default:			break;	}	return STATUS_OK;}/* * The client has sent a cancel request packet, not a normal * start-a-new-connection packet.  Perform the necessary processing. * Nothing is sent back to the client. */static voidprocessCancelRequest(Port *port, void *pkt){	CancelRequestPacket *canc = (CancelRequestPacket *) pkt;	int			backendPID;	long		cancelAuthCode;	Backend    *bp;#ifndef EXEC_BACKEND	Dlelem	   *curr;#else	int			i;#endif	backendPID = (int) ntohl(canc->backendPID);	cancelAuthCode = (long) ntohl(canc->cancelAuthCode);	/*	 * See if we have a matching backend.  In the EXEC_BACKEND case, we can no	 * longer access the postmaster's own backend list, and must rely on the	 * duplicate array in shared memory.	 */#ifndef EXEC_BACKEND	for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))	{		bp = (Backend *) DLE_VAL(curr);#else	for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++)	{		bp = (Backend *) &ShmemBackendArray[i];#endif		if (bp->pid == backendPID)		{			if (bp->cancel_key == cancelAuthCode)			{				/* Found a match; signal that backend to cancel current op */				ereport(DEBUG2,						(errmsg_internal("processing cancel request: sending SIGINT to process %d",										 backendPID)));				kill(bp->pid, SIGINT);			}			else				/* Right PID, wrong key: no way, Jose */				ereport(DEBUG2,				 (errmsg_internal("bad key in cancel request for process %d",								  backendPID)));			return;		}	}	/* No matching backend */	ereport(DEBUG2,			(errmsg_internal("bad pid in cancel request for process %d",							 backendPID)));}/* * canAcceptConnections --- check to see if database state allows connections. */static enum CAC_statecanAcceptConnections(void){	/* Can't start backends when in startup/shutdown/recovery state. */	if (Shutdown > NoShutdown)		return CAC_SHUTDOWN;	if (StartupPID)		return CAC_STARTUP;	if (FatalError)		return CAC_RECOVERY;	/*	 * Don't start too many children.	 *	 * We allow more connections than we can have backends here because some	 * might still be authenticating; they might fail auth, or some existing	 * backend might exit before the auth cycle is completed. The exact	 * MaxBackends limit is enforced when a new backend tries to join the	 * shared-inval backend array.	 */	if (CountChildren() >= 2 * MaxBackends)		return CAC_TOOMANY;	return CAC_OK;}/* * ConnCreate -- create a local connection data structure */static Port *ConnCreate(int serverFd){	Port	   *port;	if (!(port = (Port *) calloc(1, sizeof(Port))))	{		ereport(LOG,				(errcode(ERRCODE_OUT_OF_MEMORY),				 errmsg("out of memory")));		ExitPostmaster(1);	}	if (StreamConnection(serverFd, port) != STATUS_OK)	{		StreamClose(port->sock);		ConnFree(port);		port = NULL;	}	else	{		/*		 * Precompute password salt values to use for this connection. It's		 * slightly annoying to do this long in advance of knowing whether		 * we'll need 'em or not, but we must do the random() calls before we		 * fork, not after.  Else the postmaster's random sequence won't get		 * advanced, and all backends would end up using the same salt...		 */		RandomSalt(port->cryptSalt, port->md5Salt);	}	return port;}/* * ConnFree -- free a local connection data structure */static voidConnFree(Port *conn){#ifdef USE_SSL	secure_close(conn);#endif	free(conn);}/* * ClosePostmasterPorts -- close all the postmaster's open sockets * * This is called during child process startup to release file descriptors * that are not needed by that child process.  The postmaster still has * them open, of course. * * Note: we pass am_syslogger as a boolean because we don't want to set * the global variable yet when this is called. */voidClosePostmasterPorts(bool am_syslogger){	int			i;	/* Close the listen sockets */	for (i = 0; i < MAXLISTEN; i++)	{		if (ListenSocket[i] != -1)		{			StreamClose(ListenSocket[i]);			ListenSocket[i] = -1;		}	}	/* If using syslogger, close the read side of the pipe */	if (!am_syslogger)	{#ifndef WIN32		if (syslogPipe[0] >= 0)			close(syslogPipe[0]);		syslogPipe[0] = -1;#else		if (syslogPipe[0])			CloseHandle(syslogPipe[0]);		syslogPipe[0] = 0;#endif	}}/* * reset_shared -- reset shared memory and semaphores */static voidreset_shared(int port){	/*	 * Create or re-create shared memory and semaphores.	 *	 * Note: in each "cycle of life" we will normally assign the same IPC keys	 * (if using SysV shmem and/or semas), since the port number is used to	 * determine IPC keys.	This helps ensure that we will clean up dead IPC	 * objects if the postmaster crashes and is restarted.	 */	CreateSharedMemoryAndSemaphores(false, port);}/* * SIGHUP -- reread config files, and tell children to do same */static voidSIGHUP_handler(SIGNAL_ARGS){	int			save_errno = errno;	PG_SETMASK(&BlockSig);	if (Shutdown <= SmartShutdown)	{		ereport(LOG,				(errmsg("received SIGHUP, reloading configuration files")));		ProcessConfigFile(PGC_SIGHUP);		SignalChildren(SIGHUP);		if (BgWriterPID != 0)			kill(BgWriterPID, SIGHUP);		if (AutoVacPID != 0)			kill(AutoVacPID, SIGHUP);		if (PgArchPID != 0)			kill(PgArchPID, SIGHUP);		if (SysLoggerPID != 0)			kill(SysLoggerPID, SIGHUP);		/* PgStatPID does not currently need SIGHUP */		/* Reload authentication config files too */		load_hba();		load_ident();#ifdef EXEC_BACKEND		/* Update the starting-point file for future children */		write_nondefault_variables(PGC_SIGHUP);#endif	}	PG_SETMASK(&UnBlockSig);	errno = save_errno;}/* * pmdie -- signal handler for processing various postmaster signals. */static voidpmdie(SIGNAL_ARGS){	int			save_errno = errno;	PG_SETMASK(&BlockSig);	ereport(DEBUG2,			(errmsg_internal("postmaster received signal %d",							 postgres_signal_arg)));	switch (postgres_signal_arg)	{		case SIGTERM:			/*			 * Smart Shutdown:			 *			 * Wait for children to end their work, then shut down.			 */			if (Shutdown >= SmartShutdown)				break;			Shutdown = SmartShutdown;			ereport(LOG,					(errmsg("received smart shutdown request")));			/*			 * We won't wait out an autovacuum iteration ...			 */			if (AutoVacPID != 0)			{				/* Use statement cancel to shut it down */				kill(AutoVacPID, SIGINT);				break;			/* let reaper() handle this */			}			if (DLGetHead(BackendList))				break;			/* let reaper() handle this */			/*			 * No children left. Begin shutdown of data base system.			 */			if (StartupPID != 0 || FatalError)				break;			/* let reaper() handle this */			/* Start the bgwriter if not running */			if (BgWriterPID == 0)				BgWriterPID = StartBackgroundWriter();			/* And tell it to shut down */			if (BgWriterPID != 0)				kill(BgWriterPID, SIGUSR2);			/* Tell pgarch to shut down too; nothing left for it to do */			if (PgArchPID != 0)				kill(PgArchPID, SIGQUIT);			/* Tell pgstat to shut down too; nothing left for it to do */			if (PgStatPID != 0)				kill(PgStatPID, SIGQUIT);			break;		case SIGINT:			/*			 * Fast Shutdown:			 *			 * Abort all children with SIGTERM (rollback active transactions			 * and exit) and shut down when they are gone.			 */			if (Shutdown >= FastShutdown)				break;			Shutdown = FastShutdown;			ereport(LOG,					(errmsg("received fast shutdown request")));			if (DLGetHead(BackendList) || AutoVacPID != 0)			{				if (!FatalError)				{					ereport(LOG,							(errmsg("aborting any active transactions")));					SignalChildren(SIGTERM);					if (AutoVacPID != 0)						kill(AutoVacPID, SIGTERM);					/* reaper() does the rest */				}				break;			}			/*			 * No children left. Begin shutdown of data base system.			 *			 * Note: if we previously got SIGTERM then we may send SIGUSR2 to			 * the bgwriter a second time here.  This should be harmless.			 */			if (StartupPID != 0 || FatalError)				break;			/* let reaper() handle this */			/* Start the bgwriter if not running */			if (BgWriterPID == 0)				BgWriterPID = StartBackgroundWriter();			/* And tell it to shut down */			if (BgWriterPID != 0)				kill(BgWriterPID, SIGUSR2);

⌨️ 快捷键说明

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