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 的限制。
如果您在文件中發現任何不正確、與您對特定功能的經驗不符或需要進一步澄清的內容,請使用 此表單 報告文件問題。