第 27 章 使用 pg_options
注意
由 Massimo Dal Zotto 供稿
可选文件 data/pg_options 包含后端使用的运行时选项,用于控制跟踪消息和其他后端可调参数。这个文件的有趣之处在于,后端收到 SIGHUP 信号时会重新读取它,因此无需重启 Postgres 就可以即时更改运行时选项。该文件中指定的选项可以是跟踪包(backend/utils/misc/trace.c)使用的调试标志,也可以是后端用来控制其行为的数值参数。新的选项和参数必须在 backend/utils/misc/trace.c 和
backend/include/utils/trace.h 中定义。
例如,假设我们想为文件 foo.c 中的代码添加条件跟踪消息和一个可调的数值参数。我们只需把常量 TRACE_FOO 和 OPT_FOO_PARAM 加入
backend/include/utils/trace.h:
/* file trace.h */
enum pg_option_enum {
...
TRACE_FOO, /* trace foo functions */
OPT_FOO_PARAM, /* foo tunable parameter */
NUM_PG_OPTIONS /* must be the last item of enum */
};
并在 backend/utils/misc/trace.c 中加入对应的一行:
/* file trace.c */
static char *opt_names[] = {
...
"foo", /* trace foo functions */
"fooparam" /* foo tunable parameter */
};两个文件中的选项必须以完全相同的顺序指定。现在在 foo 源文件中就可以这样引用新的标志:
/* file foo.c */
#include "trace.h"
#define foo_param pg_options[OPT_FOO_PARAM]
int
foo_function(int x, int y)
{
TPRINTF(TRACE_FOO, "entering foo_function, foo_param=%d", foo_param);
if (foo_param > 10) {
do_more_foo(x, y);
}
}
使用私有跟踪标志的现有文件只需加上以下代码即可改造:
#include "trace.h" /* int my_own_flag = 0; -- removed */ #define my_own_flag pg_options[OPT_MY_OWN_FLAG]
所有 pg_options 在后端启动时都被初始化为零。如果需要不同的默认值,必须在 PostgresMain 开头添加一些初始化代码。现在我们可以通过向 data/pg_options 文件写入值来设置 foo_param 并启用 foo 跟踪:
# file pg_options ... foo=1 fooparam=17
新选项会在每个新后端启动时被读取。要让更改对所有正在运行的后端生效,需要向 postmaster 发送 SIGHUP。该信号会自动被发送到所有后端。也可以直接向某个特定后端发送 SIGHUP,只对它激活更改。
pg_options 也可以通过 Postgres 的 -T 开关来指定:
postgres options -T "verbose=2,query,hostlookup-"
用于打印错误和调试消息的函数现在可以使用 syslog(2) 设施。打印到 stdout 或 stderr 的消息都带有一个时间戳前缀,其中还包含后端 pid:
#timestamp #pid #message 980127.17:52:14.173 [29271] StartTransactionCommand 980127.17:52:14.174 [29271] ProcessUtility: drop table t; 980127.17:52:14.186 [29271] SIIncNumEntries: table is 70% full 980127.17:52:14.186 [29286] Async_NotifyHandler 980127.17:52:14.186 [29286] Waking up sleeping backend process 980127.19:52:14.292 [29286] Async_NotifyFrontEnd 980127.19:52:14.413 [29286] Async_NotifyFrontEnd done 980127.19:52:14.466 [29286] Async_NotifyHandler done
这种格式提高了日志的可读性,让人能准确了解哪个后端在什么时间做了什么。它也让编写简单的 awk 或 perl 脚本来监控日志、检测数据库错误或问题、或计算事务时间统计变得更容易。
打印到 syslog 的消息使用日志设施 LOG_LOCAL0。是否使用 syslog 可以用 syslog pg_option 控制。遗憾的是,许多函数直接调用 printf()
把消息打印到 stdout 或 stderr,这样的输出既无法重定向到 syslog,也无法加上时间戳。最好把所有对 printf 的调用都替换为 PRINTF 宏,并把输出到 stderr 的调用改为使用
EPRINTF,这样我们就能以统一的方式控制所有输出。
新的 pg_options 机制比定义新的后端选项开关更方便,原因如下:
我们不必为想要控制的每样东西定义不同的开关。所有选项都定义为存储在数据目录中一个外部文件里的关键字。
我们不必为了更改某个选项的设置而重启Postgres。通常后端选项是指定给 postmaster 并在每个后端启动时传递给它的。现在它们从文件中读取。
我们可以在后端运行时即时更改选项。这样我们就可以只在问题出现时才激活调试消息来研究问题。我们还可以为可调参数尝试不同的值。
The format of the pg_options file is as follows:
#commentoption=integer_value# set value foroptionoption# setoption= 1option+ # setoption= 1option- # setoption= 0
Note that keyword can also be
an abbreviation of the option name defined in
backend/utils/misc/trace.c.
目前定义在
backend/utils/misc/trace.c 中的选项如下:
- all
全局跟踪标志。允许的值有:
- 0
单独启用各条跟踪消息
- 1
启用所有跟踪消息
- -1
禁用所有跟踪消息
- verbose
详细程度标志。允许的值有:
- 0
不打印消息。这是默认值。
- 1
打印信息消息。
- 2
打印更多信息消息。
- query
查询跟踪标志。允许的值有:
- 0
不打印查询。
- 1
以一行打印压缩形式的查询。
- 4
打印完整查询。
- plan
打印查询计划。
- parse
打印解析器输出。
- rewritten
打印重写后的查询。
- parserstats
打印解析器统计信息。
- plannerstats
打印规划器统计信息。
- executorstats
打印执行器统计信息。
- shortlocks
目前未用,但将来启用特性时需要。
- locks
跟踪锁。
- userlocks
跟踪用户锁。
- spinlocks
跟踪自旋锁。
- notify
跟踪通知函数。
- malloc
目前未用。
- palloc
目前未用。
- lock_debug_oidmin
被锁跟踪的最小关系 oid。
- lock_debug_relid
被锁跟踪的关系 oid(非零时)。
- lock_read_priority
目前未用。
- deadlock_timeout
死锁检查计时器。
- syslog
syslog 标志。允许的值有:
- 0
消息输出到 stdout/stderr。
- 1
消息输出到 stdout/stderr 和 syslog。
- 2
消息只输出到 syslog。
- hostlookup
在 ps_status 中启用主机名查找。
- showportnumber
在 ps_status 中显示端口号。
- notifyunlock
notify 之后解锁 pg_listener。
- notifyhack
从 pg_listener 中移除重复元组。
例如我的 pg_options 文件包含下列值:
verbose=2 query hostlookup showportnumber
一些使用私有变量和选项开关的现有代码已被改为使用 pg_options
特性,主要是在 postgres.c 中。最好把所有现有代码都改成这种方式,这样我们就可以去掉 Postgres 命令行上的许多开关,并拥有更多可调选项,而选项值集中放在一个地方。