上篇介绍了怎么加一个常规参数,同时也留下了一个问题,如何加一个奇葩参数设置功能,使任意一个session设置参数值,全局所有连接立即生效。
如何实现呢?我们来分析下。
如果要使当前session生效,直接设置即可,它能直接读写当前进程的参数值。那其它的session呢?首先我们明确一个问题,数据库一旦正常运行起来后,所有的动作都是在事务中进行的,如果一个连接session在等待任务中,其它连接session的一些语句动作是无法直接影响到处于等待连接的session的。但是不同连接session肯定是有相互影响的,比方说A session建个表,B session读写这个表,肯定是可以的,任何session中事务只要提交那么就对全局都可见,这是数据库的基础,比方说是在StartTransaction()函数中的AtStart_Cache()函数会根据主进程的消息判断本地Cache是否需要更新。也就是说可以延迟点间接的更新到当前数据库的最新状态。一开始也是想以这样的方式去实现参数生效功能,后来看了下pg_reload_conf()函数恍然大悟,何必这么麻烦,直接用postgres进程间信号即可,因为postgres已经有通知所有session重新读参数功能了,要做的就只要把参数写进去通知大家重读参数文件就可以了。
那么现在的问题就转化成了如何写参数了,遗憾的是没有发现内核有对postgresql.conf文件参数的写相关功能,postgresql.conf 文件是从 postgresql.conf.sample COPY过来的,并不是动态生成的。不过postgresql.conf有include_if_exists 用法,如果存在某个参数文件就追加到后面,那么我们就可以增加一个新的参数文件,里面就写我们在设置的参数值。
以函数方式实现,在date.c的增加相关代码:
extern char *ConfigFileName;
extern bool oracle_style;
extern FILE * AllocateFile(const char *name, const char *mode);
Datum swap_oracle_mode(PG_FUNCTION_ARGS)
{
char conf_path[512] = { 0 };
int pos = 0;
int count = 1;
char *tmpFile = ConfigFileName;
FILE *fp;
if (NULL == ConfigFileName)
{
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("can't open the config file")));
}
while ('\0' != *tmpFile) //找到参数文件路径
{
if (*tmpFile == '\\' || *tmpFile == '/')
{
pos = count;
}
count++;
tmpFile++;
}
if (pos + strlen("oracle.conf") > sizeof(conf_path))
{
elog(ERROR, "can't create the oracle.conf file");
}
memcpy(conf_path, ConfigFileName, pos);
memcpy(conf_path + pos, "oracle.conf", strlen("oracle.conf")); //生成新路径名字
fp = AllocateFile(conf_path, "w+");
if (NULL == fp)
{
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("can't open the config file")));
return;
}
else
{
if (oracle_style) //在新参数文件中写入参数命令
{
fprintf(fp, "oracle_style = off\n");
}
else
{
fprintf(fp, "oracle_style = on\n");
}
if (FreeFile(fp))
{
elog(ERROR,"can't write oracle.conf file ");
return;
}
if (kill(PostmasterPid, SIGHUP)) /*****通知其它进程重读参数****/
{
ereport(WARNING,
(errmsg("failed to send signal to postmaster: %m")));
}
}
PG_RETURN_BOOL(true);
}
在pg_proc.h中增加函数注册
DATA(insert OID = 9995 (swap_oracle_mode PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 16 "" _null_ _null_ _null_ _null_ _null_ swap_oracle_mode _null_ _null_ _null_));
执行swap_oracle_mode()函数刚修改oracle_style 参数值,覆写到新参数文件 oracle.conf,通知其它连接重读参数,当然别忘了在postgresql.conf中加上一句:
include_if_exists = 'oracle.conf'
小功告成,看看效果,session 1执行参数修改函数,session 2在session 1修改函数前后分别查oracle_style参数值。
postgres=# ---session 1;
postgres=# show oracle_style;
oracle_style
--------------
on
(1 row)
postgres=# select swap_oracle_mode();
swap_oracle_mode
------------------
t
(1 row)
postgres=# show oracle_style;
oracle_style
--------------
off
(1 row)
postgres=# ---session 2;
postgres=# show oracle_style;
oracle_style
--------------
on
(1 row)
postgres=# show oracle_style; --session 1 swap_oracle_mode()执行前
oracle_style
--------------
on
(1 row)
postgres=# show oracle_style; --session 2 swap_oracle_mode()执行后
oracle_style
--------------
off
(1 row)