PostgreSQL 可以擴充為在獨立的進程中執行使用者提供的程式碼。這些進程由 postgres
啟動、停止和監控,這使得它們的生命週期與伺服器的狀態緊密相關。這些進程連接到 PostgreSQL 的共享記憶體區域,並且可以選擇在內部連接到資料庫;它們也可以像常規的客戶端連接的伺服器進程一樣,循序執行多個交易。此外,通過連接到 libpq,它們可以連接到伺服器,並表現得像一個常規的客戶端應用程式。
使用背景工作進程存在相當大的穩定性和安全性風險,因為它們是用 C
語言編寫的,因此它們可以不受限制地訪問資料。希望啟用包含背景工作進程的模組的管理者應格外小心。只有經過仔細審核的模組才應允許運行背景工作進程。
可以在啟動 PostgreSQL 時初始化背景工作進程,方法是將模組名稱包含在 shared_preload_libraries
中。希望運行背景工作進程的模組可以通過從其 _PG_init()
函數中呼叫 RegisterBackgroundWorker(
來註冊它。也可以在系統啟動並運行後通過呼叫 BackgroundWorker
*worker
)RegisterDynamicBackgroundWorker(
來啟動背景工作進程。與只能從 postmaster 進程中呼叫的 BackgroundWorker
*worker
, BackgroundWorkerHandle
**handle
)RegisterBackgroundWorker
不同,RegisterDynamicBackgroundWorker
必須從常規後端或其他背景工作進程中呼叫。
結構 BackgroundWorker
的定義如下
typedef void (*bgworker_main_type)(Datum main_arg); typedef struct BackgroundWorker { char bgw_name[BGW_MAXLEN]; char bgw_type[BGW_MAXLEN]; int bgw_flags; BgWorkerStartTime bgw_start_time; int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */ char bgw_library_name[MAXPGPATH]; char bgw_function_name[BGW_MAXLEN]; Datum bgw_main_arg; char bgw_extra[BGW_EXTRALEN]; pid_t bgw_notify_pid; } BackgroundWorker;
bgw_name
和 bgw_type
是要在日誌訊息、進程清單和類似上下文中使用的字串。bgw_type
對於同一類型的所有背景工作進程應該相同,以便可以將這些工作進程分組在進程清單中,例如。bgw_name
另一方面可以包含有關特定進程的其他資訊。(通常,bgw_name
的字串將以某種方式包含類型,但這不是嚴格要求的。)
bgw_flags
是一個按位或運算的位元遮罩,指示模組想要的功能。可能的值為
bgw_start_time
是伺服器狀態,在此期間 postgres
應啟動進程;它可以是 BgWorkerStart_PostmasterStart
(在 postgres
本身完成其自身初始化後立即啟動;請求此狀態的進程不符合資料庫連線的條件)、BgWorkerStart_ConsistentState
(在熱備份中達到一致狀態後立即啟動,允許進程連接到資料庫並運行只讀查詢)和 BgWorkerStart_RecoveryFinished
(在系統進入正常的讀寫狀態後立即啟動)之一。請注意,在非熱備份的伺服器中,最後兩個值是等效的。請注意,此設定僅指示何時啟動進程;當達到不同狀態時,它們不會停止。
bgw_restart_time
是 postgres
在進程崩潰時應等待以重新啟動進程的時間間隔(以秒為單位)。它可以是任何正值,也可以是 BGW_NEVER_RESTART
,表示在發生崩潰時不重新啟動進程。
bgw_library_name
是在其中尋找背景工作進程的初始進入點的程式庫的名稱。命名的程式庫將由工作進程動態載入,並且 bgw_function_name
將用於識別要呼叫的函數。如果呼叫核心程式碼中的函數,則必須將其設定為 "postgres"
。
bgw_function_name
是用作新背景工作進程的初始進入點的函數的名稱。如果此函數位於動態載入的程式庫中,則必須標記為 PGDLLEXPORT
(而不是 static
)。
bgw_main_arg
是背景工作進程主函數的 Datum
參數。此主函數應採用一個 Datum
類型的參數並返回 void
。bgw_main_arg
將作為參數傳遞。此外,全域變數 MyBgworkerEntry
指向註冊時傳遞的 BackgroundWorker
結構的副本;工作進程可能會發現檢查此結構很有幫助。
在 Windows(以及定義了 EXEC_BACKEND
的任何其他地方)或動態背景工作進程中,通過引用傳遞 Datum
是不安全的,只能通過值傳遞。如果需要參數,則最好傳遞一個 int32 或其他小值,並將其用作共享記憶體中分配的陣列的索引。如果傳遞像 cstring
或 text
這樣的數值,則該指針在新背景工作進程中將無效。
bgw_extra
可包含額外的資料,以傳遞給背景工作程序。與 bgw_main_arg
不同,此資料不會作為引數傳遞給工作程序的主要函式,但可透過 MyBgworkerEntry
存取,如上所述。
bgw_notify_pid
是 PostgreSQL 後端程序的 PID,當程序啟動或結束時,postmaster 應向其傳送 SIGUSR1
。對於在 postmaster 啟動時註冊的工作程序,或者當註冊工作程序的後端不希望等待工作程序啟動時,應為 0。否則,應初始化為 MyProcPid
。
一旦執行,程序可以呼叫 BackgroundWorkerInitializeConnection(
或 char *dbname
, char *username
, uint32 flags
)BackgroundWorkerInitializeConnectionByOid(
連接到資料庫。這允許程序使用 Oid dboid
, Oid useroid
, uint32 flags
)SPI
介面執行交易和查詢。如果 dbname
為 NULL 或 dboid
為 InvalidOid
,則該連線未連接到任何特定的資料庫,但可以存取共用目錄。如果 username
為 NULL 或 useroid
為 InvalidOid
,則程序將以在 initdb
期間建立的超級使用者身分執行。如果將 BGWORKER_BYPASS_ALLOWCONN
指定為 flags
,則可以繞過連接到不允許使用者連線的資料庫的限制。如果將 BGWORKER_BYPASS_ROLELOGINCHECK
指定為 flags
,則可以繞過用於連線到資料庫的角色登入檢查。一個背景工作程序只能呼叫這兩個函式中的一個,而且只能呼叫一次。無法切換資料庫。
當控制權到達背景工作程序的主要函式時,訊號最初是被封鎖的,必須由它解除封鎖;這是為了允許程序在必要時自訂其訊號處理常式。可以透過呼叫 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
(如果它正在執行),並在它不再執行後立即取消註冊。
在某些情況下,註冊背景工作程序的程序可能希望等待工作程序啟動。可以透過將 bgw_notify_pid
初始化為 MyProcPid
,然後將註冊時獲得的 BackgroundWorkerHandle *
傳遞給 WaitForBackgroundWorkerStartup(
函式來完成此操作。此函式將封鎖,直到 postmaster 嘗試啟動背景工作程序,或直到 postmaster 死亡。如果背景工作程序正在執行,則傳回值將為 BackgroundWorkerHandle *handle
, pid_t *
)BGWH_STARTED
,並且 PID 將寫入提供的位址。否則,傳回值將為 BGWH_STOPPED
或 BGWH_POSTMASTER_DIED
。
程序也可以等待背景工作程序關閉,方法是使用 WaitForBackgroundWorkerShutdown(
函式並傳遞註冊時獲得的 BackgroundWorkerHandle *handle
)BackgroundWorkerHandle *
。此函式將封鎖,直到背景工作程序退出或 postmaster 死亡。當背景工作程序退出時,傳回值為 BGWH_STOPPED
,如果 postmaster 死亡,則傳回 BGWH_POSTMASTER_DIED
。
背景工作程序可以傳送非同步通知訊息,方法是透過以下方式使用 NOTIFY
命令:SPI,或直接透過 Async_Notify()
。此類通知將在交易提交時傳送。背景工作程序不應使用 LISTEN
命令註冊以接收非同步通知,因為沒有基礎結構供工作程序使用此類通知。
src/test/modules/worker_spi
模組包含一個工作範例,它展示了一些有用的技術。
已註冊的背景工作程序的最大數量受到 max_worker_processes 的限制。
如果您在文件中看到任何不正確的內容、與您使用特定功能的經驗不符或需要進一步澄清,請使用此表單回報文件問題。