Postgres数据库的进程结构---菜鸟的PG分析之路
来源:互联网 发布:edg网络黄金 编辑:程序博客网 时间:2024/05/22 09:07
if (argc > 1 && strcmp(argv[1], "--boot") == 0)AuxiliaryProcessMain(argc, argv);/* does not return */else if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)GucInfoMain();/* does not return */else if (argc > 1 && strcmp(argv[1], "--single") == 0)PostgresMain(argc, argv, NULL,/* no dbname */ strdup(get_user_name_or_exit(progname)));/* does not return */elsePostmasterMain(argc, argv);/* does not return */
Postgres数据库所有服务进程的入口均位于src/backend/main目录下的main函数,在启动PG数据库的命令行参数中,只要没有指定--single选项,程序都会跳转到PostgresMain所在的分支进行启动;只有当指定了以single模式启动,才会执行PostgresMain分支。程序在进入PostmasterMain分支执行前,会首先对数据库的内存上下文管理进行初始化,具体包括为顶层的TopMemoryContext分配内存空间、将全局变量CurrentMemoryContext指向刚分配的TopMemoryContext、以及初始化ErrorContext。在完成这一些列的内存上下文的初始化工作后,程序进入到PostmasterMain分支执行。
在PostmasterMain函数的执行过程中,会首先设置全局变量IsPostmasterEnvironment = true, 表明系统处在多用户模式下;接着会为Postmaster进程分配执行的内存上下文PostmasterContext,并切换到PostmasterContext上下文中;接着注册一系列的信号处理函数:并接下来设置数据库的工作目录以及从配置文件中载入GUC全局变量等;在设置好监听的网络端口后,会首先启动系统日志进程syslogger 子进程,具体的启动也是通过fork 函数载入 Postgres文件并设置对应的命令行参数为"--forklog"完成的。
pqsignal(SIGHUP, SIGHUP_handler);/* reread config file and have * children do same */pqsignal(SIGINT, pmdie);/* send SIGTERM and shut down */pqsignal(SIGQUIT, pmdie);/* send SIGQUIT and die */pqsignal(SIGTERM, pmdie);/* wait for children and shut down */pqsignal(SIGALRM, SIG_IGN); /* ignored */pqsignal(SIGPIPE, SIG_IGN); /* ignored */pqsignal(SIGUSR1, sigusr1_handler); /* message from child process */pqsignal(SIGUSR2, dummy_handler);/* unused, reserve for children */pqsignal(SIGCHLD, reaper);/* handle child termination */在启动完成系统日志进程syslogger 进程后,会调用StartDataBase启动其它的辅助子进程,StartDataBase实质上是一个宏定义函数,实质是调用StartChildProcess函数并给其传递形参StartupProcess。
/* * We're ready to rock and roll... */StartupPID = StartupDataBase();Assert(StartupPID != 0);pmState = PM_STARTUP;/* Some workers may be scheduled to start now */maybe_start_bgworker();status = ServerLoop();/* * ServerLoop probably shouldn't ever return, but if it does, close down. */ExitPostmaster(status != STATUS_OK);abort();/* not reached */#define StartupDataBase() StartChildProcess(StartupProcess)
typedef enum{NotAnAuxProcess = -1,CheckerProcess = 0,BootstrapProcess,StartupProcess,BgWriterProcess,CheckpointerProcess,WalWriterProcess,WalReceiverProcess,NUM_AUXPROCTYPES/* Must be last! */} AuxProcType;
StartupProcess是AuxProcType枚举类型的一种,剩余其它枚举类型包括启动后台写进程BgWriter的BgWriterProcess、启动WalWriter预写式日志进程的WalWriterProcess等。在通过StartupDataBase() 实际fork其它辅助子进程的过程中,也是通过设置命令行参数为postgres --forkboot StartupProcess,并载入Postgres文件进行的。
#define StartupDataBase()StartChildProcess(StartupProcess)#define StartBackgroundWriter() StartChildProcess(BgWriterProcess)#define StartCheckpointer()StartChildProcess(CheckpointerProcess)#define StartWalWriter()StartChildProcess(WalWriterProcess)#define StartWalReceiver()StartChildProcess(WalReceiverProcess)StartChildProcess也是通过载入Postgres可执行文件并设置对应的命令行参数来工作的,
snprintf(typebuf, sizeof(typebuf), "-x%d", type);av[ac++] = typebuf;
在启动完全部的子进程后,PostmasterMain函数会进入到ServerLoop函数中,循环检测其它辅助进程的执行状态,但发现某个子进程意外退出时,重新启动对应的字进程。
/* If we have lost the log collector, try to start a new one */if (SysLoggerPID == 0 && Logging_collector)SysLoggerPID = SysLogger_Start();/* * If no background writer process is running, and we are not in a * state that prevents it, start one. It doesn't matter if this * fails, we'll just try again later. Likewise for the checkpointer. */if (pmState == PM_RUN || pmState == PM_RECOVERY ||pmState == PM_HOT_STANDBY){if (CheckpointerPID == 0)CheckpointerPID = StartCheckpointer();if (BgWriterPID == 0)BgWriterPID = StartBackgroundWriter();}
回到Postgres程序的入口main函数,前面分析过当需要启动系统日志子进程是会设置postgres的命令行参数为"--forklog", 启动其它辅助子进程会设置命令行参数为“-forkboot”;所以在启动辅助子进程时,Postgres会进入到SubPostmasterMain(argc, argv);分支执行下去。而SubPostmasterMain函数的相关注释及函数体如下。
#ifdef EXEC_BACKENDif (argc > 1 && strncmp(argv[1], "--fork", 6) == 0)SubPostmasterMain(argc, argv);/* does not return */#endif
/* * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent *<span style="white-space:pre"></span>to what it would be if we'd simply forked on Unix, and then *<span style="white-space:pre"></span>dispatch to the appropriate place. * * The first two command line arguments are expected to be "--forkFOO" * (where FOO indicates which postmaster child we are to become), and * the name of a variables file that we can read to load data that would * have been inherited by fork() on Unix. Remaining arguments go to the * subprocess FooMain() routine. */voidSubPostmasterMain(int argc, char *argv[]){}
SubPostmasterMain函数会做一些共享内存的相关设置工作,然后根据命令行参数分别进入相应代码的执行分支。"--forkbackend" 分支用于启动用户服务子进程;其它分支"--forkboot" 、 "--forkavlauncher"、"--forkavworker"、"--forkbgworker"、"--forkcol"、"--forklog"也是类似的。 通过代码发现"--forkboot" 分支只是进行了事务执行环境和日志管理系统的初始化,并没有启动其他的子进程,因而辅助子进程的启动应该是在postmasrer的ServerLoop中进行的。ServerLoop会循环检测辅助子进程的状态,当发现子进程没有运行时启动相应的子进程。
/* If we have lost the log collector, try to start a new one */if (SysLoggerPID == 0 && Logging_collector)SysLoggerPID = SysLogger_Start();/* * If no background writer process is running, and we are not in a * state that prevents it, start one. It doesn't matter if this * fails, we'll just try again later. Likewise for the checkpointer. */if (pmState == PM_RUN || pmState == PM_RECOVERY ||pmState == PM_HOT_STANDBY){if (CheckpointerPID == 0)CheckpointerPID = StartCheckpointer();if (BgWriterPID == 0)BgWriterPID = StartBackgroundWriter();}/* * Likewise, if we have lost the walwriter process, try to start a new * one. But this is needed only in normal operation (else we cannot * be writing any new WAL). */if (WalWriterPID == 0 && pmState == PM_RUN)WalWriterPID = StartWalWriter();/* * If we have lost the autovacuum launcher, try to start a new one. We * don't want autovacuum to run in binary upgrade mode because * autovacuum might update relfrozenxid for empty tables before the * physical files are put in place. */if (!IsBinaryUpgrade && AutoVacPID == 0 &&
0 0
- Postgres数据库的进程结构---菜鸟的PG分析之路
- pg数据库的配置文件 /tmp/postgres-reg.ini
- pg的进程架构
- postgres数据库的测试
- PG数据库的维护 postgresql
- Postgresql学习笔记【3】-pg的进程
- Postgres数据库的自动备份
- Postgres数据库的自动备份
- postgres数据库简单的使用
- Postgres修改数据库的owner
- Pg数据库导出表结构
- Postgres 数据库分析工具
- PG的两种集群技术:Pgpool-II与Postgres-XL
- PG的两种集群技术:Pgpool-II与Postgres-XL
- C# 访问PG数据库的方法
- 0024-pg数据库的sequence问题
- pg查看每个数据库对应的目录
- Postgres进程之间如何协作的?
- 关于PHP程序员解决问题的能力
- Linux kernel 分析之十八:设计模式-文件系统与抽象工厂
- Linux下Nagios的安装与配置
- 启动第二个Activity
- Android基础之HttpUrlConnection小案例
- Postgres数据库的进程结构---菜鸟的PG分析之路
- 学习CSS(7)
- JAVA基础之IO流
- 通过“分布式系统的8大谬误”反思APP的设计 第二篇 谬误2:网络没有时延
- Shiro源码分析之两种Session的方式
- eclipse git 插件集成与本地使用(傻瓜教程 一)
- 给部分培训学生的建议
- iOS中UITableview实现跨区域拖动效果的实现
- 产生一个随机序列