27.6. 非同期通知

PostgreSQL は、LISTENNOTIFY コマンドを使用した、非同期通知をサポートします。 クライアントセッションは、LISTENコマンドを使用して処理対象とする特定の通知条件を登録します。 (通知監視を取り止めるにはUNLISTENコマンドを使用します。) 任意のセッションでその条件名によるNOTIFYコマンドが実行されると、特定条件を監視しているすべてのセッションは非同期に通知を受けとります。 通知元から通知先へはこれ以上の情報は渡されません。 従って、通常通信しなければならない実際のデータはデータベーステーブルを介して転送されます。 一般的に、条件名は関連するリレーション名と同じものですが、必ず関連するリレーションが必要とされるわけではありません。

libpqアプリケーションは、通常のSQLによる問い合わせと同じようにLISTENUNLISTENコマンドを発行することができます。 NOTIFYメッセージの到着は、続いてPQnotifiesを呼び出せば検出できます。

PQnotifiesは、サーバから受信した通知メッセージの未処理リストから次の通知を返します。 保留中の通知がなくなれば ヌルポインタを返します。 PQnotifies が通知を返すと、その通知は処理済みとみなされ、通知リストから取り除かれます。

PGnotify* PQnotifies(PGconn *conn);

typedef struct pgNotify {
    char *relname;              /* 通知条件名 */
    int  be_pid;                /* サーバプロセスのプロセスID */
    char *extra;                /* 通知パラメータ */
} PGnotify;

PQnotifiesで返されたPGnotifyオブジェクトの処理が終ったら、PQfreememを使用して確実に解放してください。 PGnotify ポインタを解放することは重要です。 relnameextraフィールドは別の割り当てを表していません。 (現在、extraフィールドは使用されておらず、常に空文字列へのポインタとなります。)

注意: PostgreSQL6.4以降、be_pidは通知元のサーバプロセスのものを示します。 以前のバージョンでは、be_pid は常に接続しているサーバプロセスの PID でした。

例27-2で、非同期通知を使用したサンプルプログラムを示しています。

PQnotifies() は実際にサーバのデータを読み出すわけではありません。 これは単に、他のlibpq 関数が吸収してしまっていた通知メッセージを返すだけです。 libpq の以前のリリースでは、通知メッセージを適切な時点で確実に受け取るには、空の問い合わせでもなんでも、とにかく一定時間ごとに問い合わせを送り、そして PQexec() を実行するたびに PQnotifies() をチェックするしかありませんでした。 今でもこの方法は動作しますが、処理能力の無駄使いをすることになるのでやめておくべきでしょう。

実行すべき問い合わせがない時に通知メッセージをチェックするよい方法は、まず PQconsumeInput() を呼び出し、それから PQnotifies() をチェックすることです。 サーバからのデータの到着を select() で待つことができ、不必要な動作で CPU パワーを消費してしまうことがありません (select()で使用するファイル記述子番号の取得については、PQsocket() を参照してください)。 なお、これは問い合わせに PQsendQueryPQgetResult を使った時でも、またはおなじみの PQexec を使った時でも動作します。 しかし通知がコマンドの処理中に届いていないかどうか、PQgetResult あるいは PQexec の実行ごとに PQnotifies() を調べることを忘れないようにしておくべきです。