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

In postgresql, Why is _PG_init called twice?

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

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;

}

我知道当这个库第一次加载时,_PG_init 将被立即调用,但是,"first call" 日志被打印了两次。如何解决这个问题,我只想要一个线程。

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

当它通过显式 LOAD 调用、local_preload_libraries 或调用引用该共享的 LANGUAGE c 函数加载到该进程时,每个后端进程调用一次图书馆。

是的,每个进程。 PostgreSQL 是一种 多进程架构 ,每个进程有一个 fork()ed 连接。每个后端都可以读取 postmaster 内存,因为 fork() 使其成为写时复制,但是写入时将页面复制到进程的私有地址 space 进程无法像在多线程程序中那样通过写入全局变量进行通信.相反,他们使用显式分配的共享内存段进行通信。这是一个默认不共享的模型,与多线程编程的默认共享一切模型相反。

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

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

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

参见:

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