postgresql源码学习(45)—— PostmasterMain(2) GUC参数简介及设置
一、 GUC参数简介
1. 参数分类
GUC(Grand Unified Configuration)参数,其实指的就是pg中的各类参数。如果按生效时分类,主要有以下6类(guc.h文件):
typedef enum
{PGC_INTERNAL, // 只能通过内部进程设置的参数,用户不能设置PGC_POSTMASTER, // 只能在postmaster启动时,通过读取配置文件或解析命令行参数配置(重启生效)PGC_SIGHUP, // 只能在postmaster启动时,或者改变配置文件后发送SIGHUP信号设置(重启或执行pg_reload_conf();生效)PGC_SU_BACKEND, //只能在postmaster启动时,或者客户端新建连接时生效,已建立的连接会忽略(这类参数只能由超级用户设置)PGC_BACKEND, // 只能在postmaster启动时,或者客户端新建连接时生效,已建立的连接会忽略PGC_SUSET, // 只能在postmaster启动时,或者由超级用户通过SQL(set命令)设置PGC_USERSET // 任何用户任何时候均可配置
} GucContext;
2. 参数来源
参数来源由GucSource描述(guc.h文件),按照优先级从低到高的顺序排列,相同参数优先级更高的来源值会生效。
typedef enum
{PGC_S_DEFAULT, /* 默认值 */PGC_S_DYNAMIC_DEFAULT, /* 通过初始化计算得到 */PGC_S_ENV_VAR, /* 来自环境变量 */PGC_S_FILE, /* 来自postgresql.conf */PGC_S_ARGV, /* 来自postmaster命令行 */PGC_S_GLOBAL, /* 数据库全局设置 */PGC_S_DATABASE, /* 数据库安装时设置 */PGC_S_USER, /* 用户设置 */PGC_S_DATABASE_USER, /* 用户在单个数据库中的设置*/PGC_S_CLIENT, /* 通过客户端连接请求传送过来的数据包设置 */PGC_S_OVERRIDE, /* 特殊场景强制覆盖默认值 */PGC_S_INTERACTIVE, /* 仅作为错误报告的分界线 */PGC_S_TEST, /* 仅用作测试 */PGC_S_SESSION /* SET命令设置 */
} GucSource; // 以上来源优先级从低到高
3. 参数组成
每种类型的GUC参数都有两部分组成:共性部分+特性部分。
- 共性部分:由config_generic结构体描述
- 特性部分:每种具体数据类型(boolean,int,float,string)的参数都有对应结构体(例如config_int),且结构体的第一项都是指向共性部分的指针。
共性部分代码(以下均在guc_tables.h)
struct config_generic
{/* constant fields, must be set correctly in initial value
常量区域,必须正确设置为初始化值 */const char *name; /* 参数名 - MUST BE FIRST */GucContext context; /* 参数类型(按生效时间,即前面提到的GucContext) */enum config_group group; /* 参数分组 */const char *short_desc; /* 简单描述 */const char *long_desc; /* 详细描述 */int flags; /* 标志位, see guc.h *//* variable fields, initialized at runtime
变量区域,在运行时初始化 */enum config_type vartype; /* 参数值数据类型 */int status; /* 参数状态 */GucSource source; /* 参数来源 */GucSource reset_source; /* 参数值为reset_value时的参数来源*/GucContext scontext; /* 参数设置上下文 */GucContext reset_scontext; /* 参数值为reset_value时的上下文 */GucStack *stack; /* 堆栈,用于保存前一个值 */void *extra; /* "extra" pointer 指向当前真实值 */char *last_reported; /* if variable is GUC_REPORT, value last sent to client (NULL if not yet sent) */char *sourcefile; /* 配置所在源文件 */int sourceline; /* 在源文件中的行号 */
};
按数据类型分类如下:
enum config_type
{PGC_BOOL,PGC_INT,PGC_REAL, // 实数PGC_STRING,PGC_ENUM
};
特性部分,以config_int为例
struct config_int
{/* 第一部分一定指向共性结构 */struct config_generic gen;/* constant fields, must be set correctly in initial value: */int *variable; /* 参数当前被设置值 */int boot_val; /* 参数初始值 */int min; /* 参数最小值 */int max; /* 参数最大值 */GucIntCheckHook check_hook;GucIntAssignHook assign_hook; /* 用于设置reset_val */GucShowHook show_hook;/* variable fields, initialized at runtime: */int reset_val;void *reset_extra;
};
4. 参数配置基本过程
- 初始化GUC参数:将参数设置为默认值
- 解析postmaster命令行参数:根据postmaster命令行参数进行配置
- 读取参数文件:根据postgresql.conf文件中的设置值再次配置
铺垫了这么多,终于又回到PostmasterMain函数上,我们接着上次的代码继续往下看。
二、 初始化GUC参数
这个对应的只有一句
/** Options setup*/InitializeGUCOptions();opterr = 1;
InitializeGUCOptions函数主要干两件事:
- 循环调用InitializeOneGUCOption函数,为每个变量设置前面提到的共性和特性部分
- 调用InitializeGUCOptionsFromEnvironment函数:根据环境变量的值进行初始化
/** Initialize GUC options during program startup.** Note that we cannot read the config file yet, since we have not yet* processed command-line switches.*/
void
InitializeGUCOptions(void)
{int i;/* 时区初始化 */pg_timezone_initialize();/** 该函数统计参数个数并分配相应的config_generic类型的全局指针数组guc_variables以保存每个参数结构体的地址,并且对该数据进行排序。*/build_guc_variables();/** 遍历参数数组,并为每个参数的共性及特性结构体部分填充值*/for (i = 0; i < num_guc_variables; i++){InitializeOneGUCOption(guc_variables[i]);}guc_dirty = false;reporting_enabled = false;/* 避免事务相关设置被覆盖 */SetConfigOption("transaction_isolation", "read committed",PGC_POSTMASTER, PGC_S_OVERRIDE);SetConfigOption("transaction_read_only", "no",PGC_POSTMASTER, PGC_S_OVERRIDE);SetConfigOption("transaction_deferrable", "no",PGC_POSTMASTER, PGC_S_OVERRIDE);/* 由于历史原因,部分参数需要从环境变量中获取值 */InitializeGUCOptionsFromEnvironment();
}
三、 解析postmaster命令行参数
- 解析postmaster命令行参数,并用于设置GUC参数值。代码很长,这里省略一部分,有点类似shell的写法。
while ((opt = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:S:sTt:W:-:")) != -1){switch (opt){case 'B':SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);break;case 'b':/* Undocumented flag used for binary upgrades */IsBinaryUpgrade = true;break;
…case 'N':SetConfigOption("max_connections", optarg, PGC_POSTMASTER, PGC_S_ARGV);break;case 'n':/* Don't reinit shared mem after abnormal exit */Reinit = false;break;
…default:write_stderr("Try \"%s --help\" for more information.\n",progname);ExitPostmaster(1);}}
四、 读取参数文件
SelectConfigFiles函数首先在指定目录下找到配置文件,然后调用词法分析程序解析文件。对于解析到的每个参数及其参数值,调用SetConfigOption函数完成参数修改。
设置完成后还会进行参数合法性检验,如果一切合法,则将当前目录转入数据目录。进行后续操作。
/** Locate the proper configuration files and data directory, and read postgresql.conf for the first time.*/if (!SelectConfigFiles(userDoption, progname))ExitPostmaster(2);
五、 杂七杂八
下面内容比较散也比较少,合在一部分。
1. 创建数据库集群锁定文件
调用CreateDataDirLockFile()函数在数据目录建立数据库集群的lock文件postmaster.pid,这样就能保证不会对同一个数据库集群"启动两次"。虽然也会建立socket lock文件,但仍是认为数据目录的锁文件更可信。
/** Create lockfile for data directory.** We want to do this before we try to grab the input sockets, because the data directory interlock is more reliable than the socket-file interlock.*/CreateDataDirLockFile(true); /** Read the control file (for error checking and config info).*/LocalProcessControlFile(false);/** Register the apply launcher. */ApplyLauncherRegister();
CreateDataDirLockFile函数定义
由于调用此函数前已经将目录切换至pg数据目录,因此函数中只需使用相对目录
void
CreateDataDirLockFile(bool amPostmaster)
{CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, "", true, DataDir);
}
CreateLockFile这个函数很长,但它做的就是在数据目录中创建一个postmaster.pid文件
2. 共享库预加载
pg丰富的插件,其中不少就是通过共享库来实现的。这里就是调用process_shared_preload_libraries()函数来导入在shared_preload_libraries参数中指定的共享库。
/** process any libraries that should be preloaded at postmaster start*/process_shared_preload_libraries();/** Initialize SSL library, if specified.*/
#ifdef USE_SSLif (EnableSSL){(void) secure_initialize(true);LoadedSSL = true;}
#endif/** Now that loadable modules have had their chance to register background workers, calculate MaxBackends.*/InitializeMaxBackends();
3. 共享内存初始化
这里调用各模块的共享内存的使用量估计函数,计算总共所需的共享内存的量并申请。详细可以看CreateSharedMemoryAndSemaphores()函数。
/** Set up shared memory and semaphores.*/reset_shared();
4. 启动syslogger子进程
/** If enabled, start up syslogger collection subprocess*/SysLoggerPID = SysLogger_Start();
参考
《PostgreSQL数据库内核分析》第二章
Postgres中postmaster代码解析(上) - JavaShuo
PG守护进程(Postmaster)——初始化GUC配置参数 - 肥叔菌 - 博客园
postgresql源码学习(45)—— PostmasterMain(2) GUC参数简介及设置相关推荐
- PostgreSQL源码学习(一)编译安装与GDB入门
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 PostgreSQL源码学习(一)编译安装与GDB入门 前言 一.安装PostgreSQL 1.获取源码 2.配置 3.编译 3.安装 ...
- PostgreSQL源码学习(1)--PG13代码结构
PostgreSQL源码学习(1)–PG13代码结构 PostgreSQL代码结构 Bootstrap:用于支持Bootstrap运行模式,该模式主要用来创建初始的模板数据库. Main:主程序模块, ...
- postgresql源码学习(27)—— 事务日志⑦-日志落盘上层函数 XLogFlush
一. 预备知识 1. XLOG什么时候需要落盘 事务commit之前 log buffer被覆盖之前 后台进程定期落盘 2. 两个核心结构体 这两个结构体定义代码在xlog.c,它们在日志落盘过程中非 ...
- postgresql源码学习(51)—— 提交日志CLOG 原理 用途 管理函数
一. CLOG是什么 CLOG(commit log)记录事务的最终状态. 物理上,是$PGDATA/pg_xact目录下的一些文件 逻辑上,是一个数组,下标为事务id,值为事务最终状态 1. 事务最 ...
- postgresql源码学习(49)—— MVCC⑤-cmin与cmax 同事务内的可见性判断
一. 难以理解的场景 postgresql源码学习(十九)-- MVCC④-可见性判断 HeapTupleSatisfiesMVCC函数_Hehuyi_In的博客-CSDN博客 在前篇的可见性判断中有 ...
- postgresql源码学习(57)—— pg中的四种动态库加载方法
一. 基础知识 1. 什么是库 库其实就是一些通用代码,可以在程序中重复使用,比如一些数学函数,可以不需要自己编写,直接调用相关函数即可实现,避免重复造轮子. 在linux中,支持两种类型的库: 1. ...
- postgresql源码学习(52)—— vacuum①-准备工作与主要流程
关于vacuum的基础知识,参考,本篇从源码层继续学习 https://blog.csdn.net/Hehuyi_In/article/details/102992065 https://blog.c ...
- postgresql源码学习(53)—— vacuum②-lazy vacuum之heap_vacuum_rel函数
一. table_relation_vacuum函数 1. 函数定义 前篇最后(https://blog.csdn.net/Hehuyi_In/article/details/128749517),我 ...
- postgresql源码学习(一)—— 源码编译安装与gdb调试入门
一. postgresql源码编译安装 因为只是用来调试的测试环境,把基本的软件装好和库建好就可以,一切从简. 1. 创建用户和目录 mkdir -p /data/postgres/base/ mkd ...
最新文章
- CCS Font 知识整理总结
- 【Java 网络编程】UDP 服务器 客户端 通信 ( DatagramSocket | DatagramPacket | UDP 发送数据包 | UDP 接收数据包 | 端口号分配使用机制 )
- NTU 课程笔记 CV6422 假设检验
- 随笔汇总_索取资料请进入
- python代码解读软件_5种带你轻松分析Python代码的软件库
- Flag counter被博客园禁了的解决方法
- 一个关于Remoting的简单例子
- 计算机专业人毕业设计外文翻译,计算机专业毕业设计外文翻译.doc
- pytorch分布式训练(二):torch.nn.parallel.DistributedDataParallel
- Python3网络爬虫开发实战,抓包工具 Charles 的使用
- SpringCloud系列-Ribbon的基本应用
- java跨库调用存储_java-调用spring数据其余存储库方法不会返回...
- php 模拟客户端访问,PHP通过伪造和模拟客户端COOKIE登陆来采集抓取远程网址
- DataSet如何处理海量数据
- java语法让反编译报错_java 反编译
- 商城前端模板_新零售时代如何玩转微信商城
- 主流编程语言的特点以及优缺点(一)
- 在Excel中如何实现快速互换两列内容
- 巴塞尔协议中的计算公式_十分钟读懂巴塞尔协议
- 涨姿势!3D游戏里的男女性角色是这样建模出来的