postgres源码学习之登录
- 互联网
- 2025-08-27 06:03:01

postgres源码学习之登录 进程概览接受新的连接新增进程代码示例 子进程处理逻辑权限认证等待sql输入 进程概览
当执行完pg_ctl -l logfile start后,postgres将运行以下进程
/usr/local/pgsql/bin/postgrespostgres: checkpointerpostgres: background writerpostgres: walwriterpostgres: autovacuum launcherpostgres: logical replication launcher 查询进程状态如下: 其中第一个进程/usr/local/pgsql/bin/postgres为master,后文中会用master指代该进程,其会监听5432端口及本地socket接收新的连接; 参考postgres文档 接受新的连接 新增进程使用psql test连接后,将会有一个新的进程产生,进程状态如下:
/usr/local/pgsql/bin/postgrespostgres: checkpointerpostgres: background writerpostgres: walwriterpostgres: autovacuum launcherpostgres: logical replication launcherpostgres: postgres test [local] idle 代码示例通过gdb -p 54382 master进程的调用栈如下 从调用栈中不难看出,master的会在ServerLoop函数中进行循环接收新的连接,并创建新的进程处理该连接。 代码如下:
for (;;) { time_t now; nevents = WaitEventSetWait(pm_wait_set, DetermineSleepTime(), events, lengthof(events), 0 /* postmaster posts no wait_events */ ); /* * Latch set by signal handler, or new connection pending on any of * our sockets? If the latter, fork a child process to deal with it. */ for (int i = 0; i < nevents; i++) { // ... if (events[i].events & WL_SOCKET_ACCEPT) { ClientSocket s; if (AcceptConnection(events[i].fd, &s) == STATUS_OK) BackendStartup(&s); // 此函数会创建新的进程并处理 } }BackenStartup函数内容如下:
static int BackendStartup(ClientSocket *client_sock) { // ... pid = postmaster_child_launch(B_BACKEND, (char *) &startup_data, sizeof(startup_data), client_sock); // ..忽略其中的细节,不难看出实际上调用了postmaster_child_launch函数,其主要内容如下
pid_t postmaster_child_launch(BackendType child_type, char *startup_data, size_t startup_data_len, ClientSocket *client_sock) { pid_t pid; pid = fork_process(); if (pid == 0) /* child */ { child_process_kinds[child_type].main_fn(startup_data, startup_data_len); pg_unreachable(); /* main_fn never returns */ } #endif /* EXEC_BACKEND */ return pid; }其中child_proccess_kinds定义如下:
child_process_kind child_process_kinds[] = { [B_INVALID] = {"invalid", NULL, false}, [B_BACKEND] = {"backend", BackendMain, true}, [B_AUTOVAC_LAUNCHER] = {"autovacuum launcher", AutoVacLauncherMain, true}, [B_AUTOVAC_WORKER] = {"autovacuum worker", AutoVacWorkerMain, true}, [B_BG_WORKER] = {"bgworker", BackgroundWorkerMain, true}, /* * WAL senders start their life as regular backend processes, and change * their type after authenticating the client for replication. We list it * here for PostmasterChildName() but cannot launch them directly. */ [B_WAL_SENDER] = {"wal sender", NULL, true}, [B_SLOTSYNC_WORKER] = {"slot sync worker", ReplSlotSyncWorkerMain, true}, [B_STANDALONE_BACKEND] = {"standalone backend", NULL, false}, [B_ARCHIVER] = {"archiver", PgArchiverMain, true}, [B_BG_WRITER] = {"bgwriter", BackgroundWriterMain, true}, [B_CHECKPOINTER] = {"checkpointer", CheckpointerMain, true}, [B_STARTUP] = {"startup", StartupProcessMain, true}, [B_WAL_RECEIVER] = {"wal_receiver", WalReceiverMain, true}, [B_WAL_SUMMARIZER] = {"wal_summarizer", WalSummarizerMain, true}, [B_WAL_WRITER] = {"wal_writer", WalWriterMain, true}, [B_LOGGER] = {"syslogger", SysLoggerMain, false}, };postmaster_child_launch函数调用传入的第一个参数为B_BACKEND,所以新进程将进入BackendMain函数进行处理。从函数调用fork_process,可以看出新的进程为master的子进程。
子进程处理逻辑新的子进程启动后,对该连接进行权限认证,如果认证通过后,将等待客户端输入sql语句。
权限认证代码调用的逻辑为 BackendMain->PostgresMain->InitPostgres->PerformAuthentication 代码片段如下:
void BackendMain(char *startup_data, size_t startup_data_len){ // ... PostgresMain(MyProcPort->database_name, MyProcPort->user_name); } void PostgresMain(const char *dbname, const char *username){ sigjmp_buf local_sigjmp_buf; // ... /* Early initialization */ BaseInit(); InitPostgres(dbname, InvalidOid, /* database to connect to */ username, InvalidOid, /* role to connect as */ (!am_walsender) ? INIT_PG_LOAD_SESSION_LIBS : 0, NULL); /* no out_dbname */ // ... } void InitPostgres(const char *in_dbname, Oid dboid, const char *username, Oid useroid, bits32 flags, char *out_dbname) { bool bootstrap = IsBootstrapProcessingMode(); bool am_superuser; char *fullpath; char dbname[NAMEDATALEN]; int nfree = 0; elog(DEBUG3, "InitPostgres"); InitProcessPhase2(); SharedInvalBackendInit(false); ProcSignalInit(); /* * Perform client authentication if necessary, then figure out our * postgres user ID, and see if we are a superuser. * * In standalone mode, autovacuum worker processes and slot sync worker * process, we use a fixed ID, otherwise we figure it out from the * authenticated user name. */ if (bootstrap || AmAutoVacuumWorkerProcess() || AmLogicalSlotSyncWorkerProcess()) { ... } else if (!IsUnderPostmaster) { ... } else if (AmBackgroundWorkerProcess()) { ... } else { /* normal multiuser case */ Assert(MyProcPort != NULL); PerformAuthentication(MyProcPort); } ...其中PerformAuthentication为远端客户端登录进行权限认证的函数体。
等待sql输入完成权限认证后,子进程将进入idle状态,等待sql输入。其调用栈如下: 接收sql后及其执行过程,在下一节我们在进行说明。
postgres源码学习之登录由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“postgres源码学习之登录”