天天看点

postgresql启动过程一、主进程二、服务器初始化三、服务器主循环四、创建子进程五、子进程主入口六、子进程主循环七、启动结构图

一、主进程

  • src/backend/main/main.c
int
main(int argc, char *argv[])
{
    ...	 
		PostmasterMain(argc, argv); /* does not return */
    ...
}
           

二、服务器初始化

  • src/backend/postmaster/postmaster.c

主进程初始化,然后进行主循环loop

void
PostmasterMain(int argc, char *argv[])
{
    ...
        status = ServerLoop();
    ...
}
           

三、服务器主循环

  • src/backend/postmaster/postmaster.c

通过select等待客户端的连接

static int
ServerLoop(void)
{
	...
        
	for (;;)
	{
		...
			selres = select(nSockets, &rmask, NULL, NULL, &timeout);
		...
		/*
		 * New connection pending on any of our sockets? If so, fork a child
		 * process to deal with it.
		 */
		if (selres > 0)
		{
			int			i;

			for (i = 0; i < MAXLISTEN; i++)
			{
				if (ListenSocket[i] == PGINVALID_SOCKET)
					break;
				if (FD_ISSET(ListenSocket[i], &rmask))
				{
					Port	   *port;

					port = ConnCreate(ListenSocket[i]);
					if (port)
					{
						BackendStartup(port);

						/*
						 * We no longer need the open socket or port structure
						 * in this process
						 */
						StreamClose(port->sock);
						ConnFree(port);
					}
				}
			}
		}

		...
	}
}

           

四、创建子进程

  • src/backend/postmaster/postmaster.c

客户端连接到服务器时,服务器将fork一个子进程进行处理客户端的各种请求。

static int
BackendStartup(Port *port)
{
	...

#ifdef EXEC_BACKEND
	pid = backend_forkexec(port);
#else							/* !EXEC_BACKEND */
	pid = fork_process();
	if (pid == 0)				/* child */
	{
		free(bn);

		/* Detangle from postmaster */
		InitPostmasterChild();

		/* Close the postmaster's sockets */
		ClosePostmasterPorts(false);

		/* Perform additional initialization and collect startup packet */
		BackendInitialize(port);

		/* And run the backend */
		BackendRun(port);
	}
#endif							/* EXEC_BACKEND */
    
	...

	return STATUS_OK;
}
           

五、子进程主入口

  • src/backend/postmaster/postmaster.c

子进程进行相关的初始化后,进行主循环

static void
BackendRun(Port *port)
{
	...

	PostgresMain(ac, av, port->database_name, port->user_name);
}

           

六、子进程主循环

  • src/backend/tcop/postgres.c

    读取客户请求,解析处理请求,响应客户端。

void
PostgresMain(int argc, char *argv[],
			 const char *dbname,
			 const char *username)
{
	...
        
	for (;;)
	{
		...
            
		/*
		 * (3) read a command (loop blocks here)
		 */
		firstchar = ReadCommand(&input_message);

		...
            
		/*
		 * (7) process the command.  But ignore it if we're skipping till
		 * Sync.
		 */
		if (ignore_till_sync && firstchar != EOF)
			continue;

		switch (firstchar)
		{
			case 'Q':			/* simple query */
				{
					...
				}
				break;

			case 'P':			/* parse */
				{
					...
				}
				break;

			case 'B':			/* bind */
				...
				break;

			case 'E':			/* execute */
				{
				...
				}
				break;

			case 'F':			/* fastpath function call */
				...
				break;

			case 'C':			/* close */
				{
					...
				}
				break;

			case 'D':			/* describe */
				{
					...
				}
				break;

			case 'H':			/* flush */
				...
				break;

			case 'S':			/* sync */
				...
				break;

				/*
				 * 'X' means that the frontend is closing down the socket. EOF
				 * means unexpected loss of frontend connection. Either way,
				 * perform normal shutdown.
				 */
			case EOF:
				...

				/* FALLTHROUGH */

			case 'X':

				...
				proc_exit(0);

			case 'd':			/* copy data */
			case 'c':			/* copy done */
			case 'f':			/* copy fail */

				/*
				 * Accept but ignore these messages, per protocol spec; we
				 * probably got here because a COPY failed, and the frontend
				 * is still sending data.
				 */
				break;

			default:
				ereport(FATAL,
						(errcode(ERRCODE_PROTOCOL_VIOLATION),
						 errmsg("invalid frontend message type %d",
								firstchar)));
		}
	}							/* end of input-reading loop */
}
           

七、启动结构图

postgresql启动过程一、主进程二、服务器初始化三、服务器主循环四、创建子进程五、子进程主入口六、子进程主循环七、启动结构图

继续阅读