PostgreSQLはユーザ提供のコードを別のプロセスとして実行できるように拡張することができます。
このプロセスはpostgres
によって起動、終了、監視され、サーバの状態に密接にリンクしています。
これらのプロセスはPostgreSQLの共有メモリ領域にアタッチしたり、データベースの内部に接続するオプションを持ちます。これらはまた、通常のクライアントに接続された実際のサーバプロセスのように複数のトランザクションを連続して実行することができます。また、アプリケーションはlibpqとリンクすることにより通常のクライアントアプリケーションのようにサーバに接続して動作することができます。
バックグラウンドワーカを使うにあたっては、堅牢性とセキュリティリスクを考慮しなくてはなりません。なぜならば、C
言語で書かれており、データへのアクセスが制限されていないためです。バックグラウンドワーカプロセスを有効にしたいと思っている管理者は厳重に注意して実践すべきです。注意深く検査されたモジュールだけが、バックグラウンドワーカプロセスの実行を許されるべきです。
バックグラウンドワーカはPostgreSQLスタート時にモジュールを shared_preload_libraries
に記すことによって実行できます。バックグラウンドワーカとして実行したいモジュールは RegisterBackgroundWorker(
を BackgroundWorker *worker
)_PG_init()
から呼び出して登録する必要があります。バックグラウンドワーカはシステム起動後も RegisterDynamicBackgroundWorker(
を呼び出すことによって実行することができます。BackgroundWorker *worker, BackgroundWorkerHandle **handle
)RegisterBackgroundWorker
とは異なり、postmasterからのみ呼び出すことができます。 RegisterDynamicBackgroundWorker
は通常のバックエンドから呼び出す必要があります。
その構造、BackgroundWorker
は以下のように定義されます。
typedef void (*bgworker_main_type)(Datum 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; char bgw_library_name[BGW_MAXLEN]; /* bgw_mainがNULLの場合のみ */ char bgw_function_name[BGW_MAXLEN]; /* bgw_mainがNULLの場合のみ */ Datum bgw_main_arg; char bgw_extra[BGW_EXTRALEN]; int bgw_notify_pid; } BackgroundWorker;
bgw_name
は、ログメッセージ、プロセス一覧等で使用される文字列です。
bgw_flags
は、モジュールが要求する機能をOR演算したビットマスクです。可能な値は BGWORKER_SHMEM_ACCESS
(共有メモリへのアクセスを要求)と BGWORKER_BACKEND_DATABASE_CONNECTION
(データベース接続を確立し、その後トランザクションやクエリの実行が可能です)。データベースに接続するために BGWORKER_BACKEND_DATABASE_CONNECTION
を使っているバックグラウンドワーカもまた、 BGWORKER_SHMEM_ACCESS
を使って共有メモリに接続しなければなりません、さもないとワーカの起動に失敗します。
bgw_start_time
は、 postgres
がプロセスを起動するべきタイミングを指定します。そのタイミングは、 BgWorkerStart_PostmasterStart
(postgres
自身が初期化を終えるとすぐに起動します。これを要求するプロセスはデータベース接続に望ましいものではありません。)、 BgWorkerStart_ConsistentState
(ホットスタンバイで一貫性のある状態に到達すると、つまりデータベースに接続して参照のみのクエリを許可する状態になると起動します。)、 BgWorkerStart_RecoveryFinished
(システムが参照/更新クエリを実行すると起動します。)のうちの一つです。この設定はいつプロセスが起動されるかを示すだけであることに注意してください。これらのプロセスは、違う状態になったときに停止するわけではありません。
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
がエントリーポイントを決定するために使用されます。これはpostmater起動時にはpostmasterが必要なライブラリがロードされていないときにバックグラウンドワーカを後で立ち上げるときに有用です。
bgw_library_name
はバックグラウンドワーカの初期エントリーポイントのためのライブラリ名です。 bgw_main
がNULLでない限りそれは無視されます。 bgw_main
がNULLの場合、ワーカプロセスにより動的にロードされるライブラリ名です。 bgw_function_name
は呼び出される関数名を識別するために使用されます。
bgw_function_name
は新しいバックグラウンドワーカから動的にロードされるときに初期エントリーポイントの関数名です。それは bgw_main
がNULLのとき無視されます。
bgw_extra
はバックグラウンドワーカに渡す追加データを含めることが出来ます。
bgw_main_arg
とは異なり、このデータはワーカのメイン関数の引数として渡されていませんが、上述したようにMyBgworkerEntry
を介してアクセスすることが出来ます。
bgw_notify_pid
はプロセスの開始時と終了時にpostmasterにSIGUSR1を送信するPostgreSQLバックエンドプロセスのPIDです。それはpostmasterの起動時間、またはワーカが起動するのを待ちたくない場合に0である必要があります。それ以外の場合は、 MyProcPid
で初期化すべきです。
ひとたび実行すると、このプロセスはBackgroundWorkerInitializeConnection(
またはchar *dbname
, char *username
)BackgroundWorkerInitializeConnectionByOid(
を呼び出すことによって、データベースに接続できます。
これはプロセスにOid dboid
, Oid useroid
)SPI
インタフェースを使用してのトランザクションとクエリの実行を許します。
もし、dbname
がNULLであった場合、またはdboid
がInvalidOid
であった場合には、そのセッションは特定のデータベースに接続しません。しかし、共有カタログにはアクセス出来ます。
もし、username
がNULLの場合、またはuseroid
がInvalidOid
の場合には、そのプロセスは initdb
時に作成されたスーパーユーザとして実行されます。
バックグラウンドワーカはこれら2つの関数をどちらかを一度だけ呼ぶことが出来ます。
これはデータベースを切り替えることができません。
制御が bgw_main
関数に達したとき、シグナルはまずブロックされます。このブロックは解除されなければなりません。このことは、必要があれば、プロセスにそのシグナルハンドラをカスタマイズできることを意味します。シグナルは新しいプロセスで BackgroundWorkerUnblockSignals
を呼び出すことにより、解除でき、 BackgroundWorkerBlockSignals
を呼び出すことでブロックできます。
バックグラウンドワーカは bgw_restart_time
が BGW_NEVER_RESTART
に設定されている場合、または TerminateBackgroundWorker
によって0で終了した場合、postmasterに自動的に登録が解除されて終了します。
それ以外の場合、 bgw_restart_time
で設定された時間の後に再起動します。または、バックエンドの障害のために posmasterが最初期化された場合はすぐに再起動します。
バックグラウンドワーカが何もすることがないときは、割り込み可能な休止状態にすることを考慮しないといけません。これは WaitLatch()
を呼び出すことによって可能になります。
この関数を呼んだときに、 WL_POSTMASTER_DEATH
フラグが設定され、 postgres
自身が終了する緊急事態には、リターンコードを確認するようにしてください。
バックグラウンドワーカを RegisterDynamicBackgroundWorker
関数により登録している場合、登録を実行するバックエンドはワーカの状態に関する情報を取得することが可能です。取得したい場合は RegisterDynamicBackgroundWorker
に BackgroundWorkerHandle *
のアドレスを渡す必要があります。もし登録に成功した場合、 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
になります。
バックグラウンドワーカの実例として、src/test/modules/worker_spi
というモジュールがあります。
これはいくつかの有用な技術を示しています。
登録できるバックグラウンドワーカの数は max_worker_processesによって制限されています。