postgresql源码学习(45)—— PostmasterMain(2) GUC参数简介及设置

67 篇文章 52 订阅
30 篇文章 1 订阅

一、 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命令行参数

  1.       解析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_SSL
    if (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配置参数 - 肥叔菌 - 博客园

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hehuyi_In

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值