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_PostmasterStart (postgres自身が初期化を終えるとすぐに起動します。これを要求するプロセスはデータベース接続に望ましいものではありません。)、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というオプションモジュールがあります。これはいくつかの有用な技術を示します。