一、主程序
- 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 */
}