在postgresql中,为什么_PG_init被调用两次?

时间:2015-01-20 03:29:16

标签: postgresql function

我在postgresql中写了一个函数。这是我的初始化函数:

void _PG_init(){
  int line = 0, errcode2 = 0;
  char buf[1024], db_log[1024];
  dbglog("first call\n");

  l = (local_t*)palloc(sizeof(local_t));
  if(!l) die(ERROR_NOMEM);
  dbglog("first palloc local_t\n");
  memset(l, 0, sizeof(local_t));
  session_init_lock = 0;

  sprintf(buf, "%s/" PREFIX "/privacyprot.log", getenv("HOME"));
  l->logfile = fopen(buf, "a+");
  if(!(l->logfile)) die(ERROR_NOMEM);
  l->begin_time = time(NULL);
  return;

}

我知道首次加载此lib时,会立即调用_PG_init,但是,“first call”日志会被打印两次。如何解决这个问题,我只想要一个单一的线程。

1 个答案:

答案 0 :(得分:3)

由于您的测试方式,您可能会看到它被调用两次。

每个后端进程调用一次,当它通过显式LOAD来电,local_preload_librariesLANGUAGE c调用后加载到该进程中引用该共享库的函数。

是的,按程序进行。 PostgreSQL是一个多进程架构,每个进程有一个fork()个连接。每个后端都可以读取postmaster内存,因为fork()使其复制写入,但是当写入将页面复制到进程的私有地址空间时,进程无法通过写入全局变量(如多线程程序)进行通信。相反,它们使用显式分配的共享内存段进行通这是一个默认的无共享模型,而不是多线程编程的默认共享模型。

如果您希望PG_init完全被调用一次,则必须使用shared_preload_libraries使邮件管理员在启动时加载您的库,然后在后端获取fork()之前。在这种情况下,它无法访问数据库或所有常用设施,因此它主要注册挂钩和回调,请求共享内存段和锁定分配,然后继续正常启动。您也可以在此阶段注册后台工作进程。

通过在postmaster启动期间请求自己的共享内存,您的扩展可以使用此内存,以及PostgreSQL提供的其他IPC机制(如锁和锁存器),以便在后端之间进行通信。

您将在contrib/目录中找到扩展中基本使用共享内存的一些示例。

请参阅:

以及从那里链接的各种资源。