天天看點

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啟動過程一、主程式二、伺服器初始化三、伺服器主循環四、建立子程式五、子程式主入口六、子程式主循環七、啟動結構圖

繼續閱讀