章 45. 后台工作进程

PostgreSQL可以扩展为在单独的进程中运行用户提供的代码。命令postgres启动、 停止和监控这样的进程,允许它们的生命周期与服务器状态紧密关联。这些进程可以选择连接 PostgreSQL的共享内存并与数据库内部连接;它们也可以串行地运行多个事务,就像 常规的客户端连接的服务器进程。另外,通过链接到libpq,它们可以连接到服务器并 且和常规的客户端应用表现一样。

警告

使用后台工作进程有着相当大的鲁棒性和安全风险,这是因为它们是用C语言写的,有着不受限制的数据 访问方式。乐于使用包含后台工作进程的模块的管理员们应当极度地当心。只有仔细审计过的模块才 应该被允许运行后台工作进程。

只有在shared_preload_libraries中列出的模块能够运行后台工作进程。想要运行后台工作 程序的模块需要通过从它的_PG_init()调用 RegisterBackgroundWorker(BackgroundWorker *worker)来注册 这个程序。BackgroundWorker结构是这样定义的:

typedef void (*bgworker_main_type)(void *main_arg);
typedef struct BackgroundWorker
{
    char        bgw_name[BGW_MAXLEN];
    int         bgw_flags;
    BgWorkerStartTime bgw_start_time;
    int         bgw_restart_time;       /* 以秒计,或者是BGW_NEVER_RESTART */
    bgworker_main_type bgw_main;
    Datum       bgw_main_arg;
} BackgroundWorker;

bgw_name是用于日志消息、进程列表和类似环境的一个字符串。

bgw_flags是一个按位与的比特掩码,显示模块想要的容量。可能的值有 BGWORKER_SHMEM_ACCESS (要求访问共享内存)和 BGWORKER_BACKEND_DATABASE_CONNECTION(要求能够建立一个数据库连接,通 过这个连接稍后可以运行事务和查询)。一个使用 BGWORKER_BACKEND_DATABASE_CONNECTION连接数据库的后台工作程序还必须用 BGWORKER_SHMEM_ACCESS连接共享内存,否则程序的启动会失败。

bgw_start_time是某种服务器状态,在此期间应当由 postgres启动进程;它可以是下面几个值之一: BgWorkerStart_PostmasterStartpostgres完成自身初始化后就立即启动; 请求此种启动方式的进程不能进行数据库连接),BgWorkerStart_ConsistentState( 一旦在热备份系统中达到了一致状态就启动,允许进程连接到数据库并运行只读查询),以及 BgWorkerStart_RecoveryFinished(只要系统进入普通读写状态就启动)。注意在非热备 份系统的服务器中后两个值是作用相当的。注意此设置只在进程将启动时显示;进入不同状态时进程不停。

bgw_restart_time是以秒记的时间间隔。一旦进程崩溃, postgres应当在重启进程前等待这一段时间。它可以是任何的正值,或者 是BGW_NEVER_RESTART以表明在进程崩溃时不重启进程。

bgw_main是当进程被启动时指向所运行函数的一个指针。该函数必须使 用void *类型的单一参数并返回void类型的值。 bgw_main_arg将作为唯一参数被传递给此函数。注意全局变量 MyBgworkerEntry指向进程注册时传递的 BackgroundWorker结构的一份拷贝。

进程一旦运行,就可以通过调用 BackgroundWorkerInitializeConnection(char *dbname, char *username) 连接到一个数据库。这样进程可以使用SPI接口运行事务和查询。如果 dbname值为NULL,会话不被连接到任何特定数据库,但是可以获取共享的目录。如果 username值为NULL,进程会以initdb运行时创建的超级用户身份来运行。 每个后台进程只能调用一次BackgroundWorkerInitializeConnection,它不能切换数据库。

控制到达bgw_main函数时信号是锁定的,并且必须由此函数解锁;这样在必要时可以允许 进程定制它的信号处理程序。通过调用BackgroundWorkerUnblockSignals可以在新进程 中为信号解锁,通过调用BackgroundWorkerBlockSignals可以加锁。

后台工作程序是被预期连续运行的;如果它们干净的退出了,postgres会立即重启它们。 当它们无事可做时,考虑进入可中断的睡眠;通过调用WaitLatch()可以实现这 一点。确定调用该函数时设置了WL_POSTMASTER_DEATH标志,并且在postgres 自身终止的紧急情况下为提示的退出验证返回码。

worker_spi contrib模块包含一个展示一些有用技术的范例。