后台工作进程
Warning: 使用后台工作进程存在相当大的稳健性和安全性风险,因为使用C语言编写时,它们可以不受限制地访问数据。 希望启用包含后台工作进程的模块的管理员应该格外小心。 只允许经过仔细审核的模块运行后台工作进程。
通过在shared_preload_libraries服务器配置参数中包含模块名称,可以在启动Greenplum数据库时初始化后台工作程序。 希望运行后台工作程序的模块可以通过从_PG_init()调用RegisterBackgroundWorker(BackgroundWorker *worker)来注册它。 通过调用函数RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle),系统启动并运行后,也可以启动后台工作程序。 与只能在postmaster中调用的RegisterBackgroundWorker不同,必须从常规后端调用RegisterDynamicBackgroundWorker。
因此定义了BackgroundWorker结构:
bgw_name是一个在日志消息,进程列表和类似上下文中使用的字符串。
bgw_flags是一个按位或位掩码,表示模块想要的功能。 可能的值是BGWORKER_SHMEM_ACCESS(请求共享内存访问)和BGWORKER_BACKEND_DATABASE_CONNECTION(请求建立数据库连接的能力,以后可以通过它运行事务和查询)。 使用BGWORKER_BACKEND_DATABASE_CONNECTION连接到数据库的后台工作进程还必须使用BGWORKER_SHMEM_ACCESS附加共享内存,否则工作进程将启动失败。
bgw_restart_time是postgres在重新启动进程之前应该等待的时间间隔(以秒为单位),以防它崩溃。 它可以是任何正值,或BGW_NEVER_RESTART,表示在发生崩溃时不重启进程。
bgw_main是指向启动进程时要运行的函数的指针。 此函数必须采用Datum类型的单个参数并返回void。 bgw_main_arg将作为唯一参数传递给它。 请注意,全局变量MyBgworkerEntry指向在注册时传递的BackgroundWorker结构的副本。 bgw_main可能为NULL; 在这种情况下,将使用bgw_library_name和bgw_function_name来确定入口点。 这对postmaster启动后启动的后台工作进程很有用,其中postmaster没有加载必需的库。
bgw_library_name是库的名称,在该库中应该寻找后台工作程序的初始入口点。 除非bgw_main为NULL,否则它将被忽略。 但是如果bgw_main为NULL,则命名库将由工作进程动态加载,bgw_function_name将用于标识要调用的函数。
bgw_function_name是动态加载库中函数的名称,该库应该用作新后台工作程序的初始入口点。 除非bgw_main为NULL,否则它将被忽略。
bgw_notify_pid是一个Greenplum数据库后端进程的PID,postmaster应该在进程启动或退出时向其发送SIGUSR1。 对于在postmaster启动时注册的工作进程,或者注册工作进程的后端不希望等待工作进程启动时,应该为0。 否则,它应该初始化为MyProcPid。
当控制到达bgw_main函数时,信号最初被阻止,并且必须被它解除阻塞; 这是为了允许进程在必要时自定义其信号处理程序。 通过调用BackgroundWorkerUnblockSignals可以在新进程中取消阻止信号,并通过调用BackgroundWorkerBlockSignals来阻止信号。
如果后台工作程序的bgw_restart_time配置为BGW_NEVER_RESTART, 或者退出时退出代码为0或由TerminateBackgroundWorker终止,则退出时将由postmaster自动取消注册。 否则,它将在通过bgw_restart_time配置的时间段之后重新启动,或者如果postmaster由于后端故障而重新初始化群集时立即重新启动。 需要暂时暂停执行的后端应该使用可中断的睡眠而不是退出; 这可以通过调用WaitLatch()来实现。 确保在调用该函数时设置WL_POSTMASTER_DEATH标志,并在postgres本身已终止的紧急情况下验证返回代码以提示退出。
当使用RegisterDynamicBackgroundWorker函数注册后台工作程序时,执行注册的后端可以获得有关工作进程状态的信息。 希望这样做的后端应该将BackgroundWorkerHandle *的地址作为RegisterDynamicBackgroundWorker的第二个参数传递。 如果工作程序已成功注册,则此指针将使用不透明句柄进行初始化, 该句柄随后可以传递给GetBackgroundWorkerPid(BackgroundWorkerHandle *, pid_t *)或TerminateBackgroundWorker(BackgroundWorkerHandle *)。 GetBackgroundWorkerPid可用于轮询工作进程的状态:返回值BGWH_NOT_YET_STARTED表示工作进程尚未由postmaster启动; BGWH_STOPPED表示它已经启动但不再运行; 和BGWH_STARTED表示它当前正在运行。 在最后一种情况下,PID也将通过第二个参数返回。 TerminateBackgroundWorker使postmaster在运行时将SIGTERM发送给worker,并在它不运行时立即取消注册。
在某些情况下,注册后台工作进程的进程可能希望等待工作进程启动。 这可以通过将bgw_notify_pid初始化为MyProcPid, 然后将在注册时获得的BackgroundWorkerHandle *传递给WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle,pid_t *)函数来实现。 此函数将阻塞,直到postmaster尝试启动后台工作程序,或直到postmaster死亡。 如果后台运行器正在运行,则返回值将为BGWH_STARTED,并且PID将被写入提供的地址。 否则,返回值将为BGWH_STOPPED或BGWH_POSTMASTER_DIED。
worker_spi模块包含一个工作示例,演示了一些有用的技术。
Parent topic: Greenplum数据库参考指南