|
ここでは、キューへのメッセージの登録とキューからのメッセージの取り出しを行う ATMI C 言語関数 tpenqueue(3c)、tpdequeue(3c)、およびいくつかの補助関数の使用方法について説明します。
キュー機能を使用するクライアント プログラムまたはサーバ プログラムをコーディングする Oracle TUXEDO プログラマには、Oracle Tuxedo ATMI にバインドされた C 言語についての知識が必要です。Oracle Tuxedo プログラミングに関する全般的な説明については、『C 言語を使用した Oracle Tuxedo アプリケーションのプログラミング』を参照してください。ATMI 関数の詳細については、『Oracle Tuxedo C リファレンス』を参照してください。
Oracle Tuxedo /Q のキューにメッセージを登録する呼び出しは、アプリケーションに対応付けられているあらゆるクライアント プロセスまたはサーバ プロセスから行うことができます。たとえば、次の発信元があります。
ここでは、Oracle Tuxedo /Q プログラミングについて、図「キュー サービスの呼び出し」の主に左側部分について説明します。この図では、クライアント (または、クライアントとして機能するプロセス) は tpenqueue(3c) を呼び出し、TMQUEUE(5) サーバを通して利用できるキュー スペースを指定して、メッセージをキューに登録しています。クライアントは、その後、TMQUEUE への tpdequeue(3c) 呼び出しを介して、応答を取得します。
図「キュー サービスの呼び出し」では、キューに入れられたメッセージが、サーバ TMQFORWARD(5) によってキューから取り出され、処理のために tpcall(3c) を介してアプリケーション サーバに送信されています。tpcall() に対する応答が受信されると、TMQFORWARD は応答メッセージをキューに登録します。TMQFORWARD の主な目的は、キュー スペースと既存のアプリケーション サービスとの間にインタフェースを提供することです。そのため、アプリケーションにコードを追加する必要はありません。そのため、ここでは、クライアントとキュー スペースとの間の処理を中心に説明します。
キュー機能の使い方を簡単に示すサンプルがソフトウェアに提供されています。詳細については、「サンプル アプリケーション」を参照してください。
#include <atmi.h>
int tpenqueue(char *qspace, char *qname, TPQCTL *ctl,
char *data, longlen, longflags)
tpenqueue() が呼び出されると、qspace で識別されるキュー スペース内の qname キューにメッセージを格納するようにシステムが指示されます。メッセージは data が指すバッファ内にあり、その長さは len で示されます。flags にビット設定を行うと、システムに tpenqueue() 呼び出しの処理方法が通知されます。登録されたメッセージおよび応答の処理方法のさらに詳しい情報は、ctl が指す TMQCTL 構造体で定義されます。
tpenqueue(3c) の処理を制御するいくつかの重要な引数があります。その一部について、以下に説明します。
qspace は、管理者によって既に作成されたキュー スペースを識別します。サーバがコンフィグレーション ファイルの SERVERS セクションで定義されている場合、そのサーバが提供するサービス名は、実際のキュー スペース名 (GROUPS セクションの OPENINFO パラメータの一部として指定されます) のエリアスになります。たとえば、アプリケーションがサーバ TMQUEUE を使用する場合、qspace 引数が指す値は、TMQUEUE が宣言するサービス名になります。サービス名のエリアスが何も定義されていない場合、デフォルトのサービス名はサーバ名 TMQUEUE と同じになります。その場合、コンフィグレーション ファイルには次の内容が記述されています。
TMQUEUE
SRVGRP = QUE1 SRVID = 1
GRACE = 0 RESTART = Y CONV = N
CLOPT = "-A"
CLOPT = "-s TMQUEUE"
サーバ グループ QUE1 のエントリには、OPENINFO パラメータを使用して、リソース マネージャ、デバイスのパス名、およびキュー スペース名を指定します。クライアント プログラムにおける qspace 引数は、次のように記述されます。
if (tpenqueue("TMQUEUE", "STRING", (TPQCTL *)&qctl,
(char *)reqstr, 0,0) == -1) {
Error checking
}
TMQUEUE(5) リファレンス ページの例では、サーバを作成してコンフィグレーション ファイルで指定する際に、サービスのエリアスを指定する方法が示されています。「サンプル アプリケーション」のサンプル プログラムでも、サービスのエリアスが指定されています。
キュー スペース内で、キューを使用してサービスを呼び出している場合、メッセージ キューは要求を処理できるアプリケーション サービスに従って命名されます。qname は、そのようなアプリケーション サービスを指すポインタです。それ以外の場合、qname は、アプリケーション (メッセージをキューに登録したアプリケーション、または別のアプリケーション) によってキューから取り出されるまで、メッセージを格納しておく場所を単に示す名前です。
data は、処理対象のメッセージが格納されたバッファを指すポインタです。そのバッファは、tpalloc(3c) を呼び出して割り当てられたものであることが必要です。len は、メッセージの長さを指定します。Oracle Tuxedo のバッファ タイプには、メッセージの長さを指定する必要がないもの (FML など) もあります。その場合、len は無視されます。data は NULL にすることもできます。その場合、len は無視され、メッセージはデータ部分なしでキューに登録されます。
flags の値は、tpenqueue() 呼び出しの処理方法を Oracle Tuxedo システムに通知するために使用されます。次は、有効なフラグです。
TPNOTRAN
TPNOBLOCK
TPEBLOCK が設定されます。このフラグが設定されていて、ターゲットのキューが別のアプリケーションによって排他的にオープンされているなどのブロッキング条件が存在する場合には、呼び出しは異常終了して tperrno に TPEDIAGNOSTIC が設定され、TPQCTL 構造体の診断フィールドは QMESHARE に設定されます。後者の場合、Oracle Tuxedo システム以外の Oracle Products に基づくほかのアプリケーションが、キューイング サービス API (QSAPI) を使用して読み取りと書き込み、またはそのいずれかを排他的に行うためにキューをオープンしています。
TPNOBLOCK が設定されていない場合に、ブロッキング状態が存在すると、その状態が解消されるかタイムアウト (トランザクション タイムアウトまたはブロッキング タイムアウト) が発生するまで、呼び出し側はブロックされます。タイムアウトが発生した場合、呼び出しは失敗し、tperrno() に TPETIME が設定されます。
TPNOTIME
TPSIGRSTRT
TPGOTSIG が設定されます。
tpenqueue() の 3 番目の引数は、TPQCTL 型の構造体へのポインタです。TPQCTL 構造体には、アプリケーションで使用されるメンバーと Oracle Tuxedo システムで使用されるメンバーがあり、アプリケーション プログラムとキュー機能間の両方向でパラメータがやり取りされます。tpenqueue() を呼び出すクライアントは、フラグを設定して、システム側で入力する必要のあるフィールドをマークします。この構造体は、tpdequeue() でも使用されます。一部のフィールドは、アプリケーションが tpdequeue() を呼び出すまで使用されません。次のコード例は、この構造体全体を示しています。
#define TMQNAMELEN 15
#define TMMSGIDLEN 32
#define TMCORRIDLEN 32
struct tpqctl_t { /* キュー プリミティブの制御パラメータ */
long flags; /* どの値が設定されるかを示します。 */
long deq_time; /* キューから取り出すときの絶対時間/相対時間 */
long priority; /* 登録優先順位 */
long diagnostic; /* 失敗の原因を示します。 */
char msgid[TMMSGIDLEN]; /* 既存メッセージの ID (そのメッセージの前に登録されます) */
char corrid[TMCORRIDLEN]; /* メッセージを識別するときに使用される相関識別子 */
char replyqueue[TMQNAMELEN+1]; /* 応答メッセージ用のキューの名前 */
char failurequeue[TMQNAMELEN+1]; /* 異常終了メッセージを登録するキューの名前 */
CLIENTID cltid; /* 発信元クライアントのクライアント識別子 */
long urcode; /* アプリケーション ユーザ戻りコード */
long appkey; /* アプリケーション認証クライアント キー */
long delivery_qos; /* サービスの配信品質 */
long reply_qos; /* サービスの応答メッセージの品質 */
long exp_time; /* 有効期限の時間 */
};
typedef struct tpqctl_t TPQCTL;
以下は、tpenqueue() の入力情報を制御する flags パラメータの有効なフラグです。
TPNOFLAGS
TPQTOP
TPQTOP と TPQBEFOREMSGID は、相互に排他的なフラグです。
TPQBEFOREMSGID
ctl->msgid によって識別されるメッセージの前に登録されます。この要求は、順序付けを無効にするようにキューが設定されているかどうかによって、使用できない場合があります。TPQTOP と TPQBEFOREMSGID は、相互に排他的なフラグです。メッセージ識別子の値は 32 バイト全体が意味を持つので、ctl->msgid で識別される値は、たとえば NULL 文字を埋め込むなどして、完全に初期化する必要があります。
TPQTIME_ABS
ctl->deq_time で指定された時間の経過後、メッセージが処理されます。deq_time は、使用しているオペレーティング システムで利用できる場合は、time(2) または mktime(3C)、あるいは Oracle Tuxedo システムで提供される gp_mktime(3c) によって生成される絶対時間です。ctl->deq_time に設定される値は、世界協定時 (UTC) 1970 年 1 月 1 日 00:00:00 から経過した秒数です。絶対時間は、キュー マネージャ プロセスが存在するマシン クロックに基づいて設定されます。TPQTIME_ABS と TPQTIME_REL は、相互に排他的なフラグです。
TPQTIME_REL
ctl->deq_time は、キューへの登録が完了してから、送信されたメッセージが処理されるまでの遅延秒数を指定します。TPQTIME_ABS と TPQTIME_REL は、相互に排他的なフラグです。
TPQPRIORITY
ctl->priority に格納されます。優先順位は、1 以上 100 以下の範囲でなければなりません。優先順位によって順序付けられたキューでは、数値が高いほど優先順位も高くなり、高い数値のメッセージが低い数値のメッセージより先にキューから取り出されます。優先順位によって順序付けられていないキューの場合、値は情報にすぎません。
TPQCORRID
ctl->corrid に指定された相関識別子の値が使用されます。この識別子は、キューに登録されたすべての応答メッセージまたは異常終了メッセージに付加されるので、アプリケーションは応答を特定の要求に結び付けることができます。相関識別子の値は 32 バイト全体が意味を持つので、ctl->corrid に指定される値は、たとえば NULL 文字を埋め込むなどして、完全に初期化する必要があります。
TPQREPLYQ
ctl->replyqueue に指定された応答キューが、キューに入れられたメッセージに対応付けられます。メッセージへの応答はすべて、要求メッセージと同じキュー スペース内の、指定されたキューに登録されます。この文字列は NULL で終了し、15 文字以下であることが必要です。サービスに対する応答が生成されても、応答キューが指定されていないか存在しない場合は、その応答は削除されます。
TPQFAILUREQ
ctl->failurequeue に指定されている異常終了キューが、キューに入れられたメッセージに対応付けられます。(1) キューに登録されたメッセージが TMQFORWARD() によって処理され、(2) TMQFORWARD が -d オプションで開始され、さらに (3) サービスが異常終了して NULL 以外の応答を返す場合は、その応答と関連する tpurcode によって構成される異常終了メッセージが、元の要求メッセージと同じキュー スペース内で指定されたキューに登録されます。この文字列は NULL で終了し、15 文字以下であることが必要です。
TPQDELIVERYQOS、TPQREPLYQOS
TPQDELIVERYQOS フラグが設定されていると、ctl->delivery_qos で指定されたフラグにより、メッセージの配信サービスの品質が制御されます。その場合、相互に排他的な 3 つのフラグ TPQQOSDEFAULTPERSIST、TPQQOSPERSISTENT、TPQQOSNONPERSISTENT のいずれかを ctl->delivery_qos に設定しなければなりません。TPQDELIVERYQOS フラグが設定されていない場合、ターゲットのキューのデフォルトの配信ポリシーがメッセージに対するサービスの配信品質を指定します。
TPQREPLYQOS フラグが設定されていると、ctl->reply_qos で指定されるフラグが、メッセージの応答に対するサービスの品質を制御します。その場合、相互に排他的な 3 つのフラグ TPQQOSDEFAULTPERSIST、TPQQOSPERSISTENT、TPQQOSNONPERSISTENT のいずれかを ctl->reply_qos に設定しなければなりません。TPQREPLYQOS フラグは、TMQFORWARD によって処理されるメッセージから応答が返されるときに使用されます。サービスを呼び出すときに TMQFORWARD を使用しないアプリケーションでは、自身の応答メカニズムのヒントとして TPQREPLYQOS フラグを使用できます。
ctl->replyqueue キューのデフォルトの配信ポリシーが応答に対するサービスの配信品質を指定します。デフォルトの配信方針は、メッセージに対する応答がキューに登録されるときに決定される点に注意してください。つまり、元のメッセージがキューに登録されてから応答が登録されるまでの間に、応答キューのデフォルトの配信方針が変更された場合、応答が最後に登録される時点で有効な方針が使用されます。
ctl->delivery_qos と ctl->reply_qos の有効なフラグです。
TPQEXPTIME_ABS
ctl->exp_time に格納された値で示されます。ctl->exp_time の値は、time(2)、mktime(3C)、または gp_mktime(3c) によって生成された絶対時間、つまり世界協定時 (UTC) 1970 年 1 月 1 日 00:00:00 から経過した秒数に設定されなければなりません。
TPQEXPTIME_ABS、TPQEXPTIME_REL、および TPQEXPTIME_NONE は、相互に排他的なフラグです。この 3 つのどのフラグも設定されていない場合、ターゲットのキューに対応しているデフォルトの有効期限の時間がメッセージに適用されます。
TPQEXPTIME_REL
ctl->exp_time に格納された値で示されます。
TPQEXPTIME_ABS、TPQEXPTIME_REL、および TPQEXPTIME_NONE は、相互に排他的なフラグです。この 3 つのどのフラグも設定されていない場合、ターゲットのキューに対応しているデフォルトの有効期限の時間がメッセージに適用されます。
TPQEXPTIME_NONE
TPQEXPTIME_ABS、TPQEXPTIME_REL、および TPQEXPTIME_NONE は、相互に排他的なフラグです。この 3 つのどのフラグも設定されていない場合、ターゲットのキューに対応しているデフォルトの有効期限の時間がメッセージに適用されます。
また、TPQCTL の urcode フィールドにユーザ戻りコードを設定することができます。この値は、メッセージをキューから取り出すために tpdequeue(3c) を呼び出すアプリケーションに返されます。
tpenqueue() からの出力では、次のフィールドが TPQCTL 構造体に設定されます。
long flags; /* どの値が設定されるかを示します。 */
char msgid[32]; /* キューに登録されたメッセージの ID */
long diagnostic; /* 失敗の原因を示します。 */
tpenqueue() からの出力情報を制御する flags パラメータの有効なビットの一覧を次に示します。tpenqueue() の呼び出し時にこのフラグがオンになっていると、/Q サーバ TMQUEUE(5) は、構造体の対応する要素にメッセージ識別子を挿入します。tpenqueue() の呼び出し時にこのフラグ ビットをオフにしていると、TMQUEUE() によって構造体の関連要素にメッセージ識別子は設定されません。
TPQMSGID
tpenqueue() の呼び出しが成功すると、メッセージ識別子が ctl->msgid に格納されます。メッセージ識別子の値は 32 バイト全体が意味を持つので、ctl->msgid に格納される値は、たとえば NULL 文字を埋め込むなどして、完全に初期化する必要があります。初期化に使用される実際の埋め込み文字は、Oracle Tuxedo /Q コンポーネントのリリースによって異なります。
制御構造体の残りのメンバーは、tpenqueue() への入力に使用されません。
tpenqueue() の呼び出しが異常終了して tperrno(5) に TPEDIAGNOSTIC が設定された場合、失敗の原因を示す値が ctl->diagnostic に返されます。次は、返される値です。
QMEINVAL]
QMEBADRMID]
QMENOTOPEN]
QMETRAN]
TPNOTRAN フラグを設定して呼び出しが行われ、キューにメッセージを登録するトランザクションの開始を試みたときに、エラーが発生しました。この診断は、Oracle Tuxedo リリース 7.1 以降のキュー マネージャからは返されません。
QMEBADMSGID]
QMESYSTEM]
QMEOS]
QMEABORTED]
QMEPROTO]
QMEBADQUEUE]
QMENOSPACE]
QMENOSPACE が返されます。(1) キュー スペースに割り当てられたディスク容量 (永続的)、(2) キュー スペースに割り当てられたメモリ容量 (非永続的)、(3) 同時にアクティブ状態になるトランザクションの最大数 (キュー スペースで許容される数であることが必要です)、(4) キュー スペースに一度に入れることができる最大メッセージ数、(5) キューイング サービス コンポーネントが処理できる並列アクションの最大数、または (6) キューイング サービス コンポーネントを同時に使用できる認証されたユーザの最大数。
QMERELEASE]
QMESHARE]
キューの作成時に、管理者が tpenqueue() 呼び出しでキュー上のメッセージの順序を無効にできるようにした場合、次の 2 つの方法でこの機能を利用できます。この 2 つの方法は、相互に排他的です。flags に TPQTOP を設定すると、メッセージをキューの先頭に置くことができます。または、flags に TPQBEFOREMSGID、ctl->msgid に既存のメッセージの ID を設定して、メッセージを特定の既存のメッセージの前に置くこともできます。この方法では、メッセージ ID を使用できるように、以前の呼び出しで取得されたメッセージ ID が保存されていることが必要です。管理者は、キューでサポートされている方法を通知する必要があります。キューは、この 2 つのいずれかまたは両方を使用できるように、あるいはどちらも使用できないように作成できます。
ctl->priority に値を設定して、メッセージの優先順位を指定することができます。この値は、1 以上 100 以下の範囲でなければなりません。数値が高いほど優先順位も高くなります。キューの順序付けパラメータの中に priority が含まれていない場合、ここで優先順位を設定しても取り出しの順序には影響しません。ただし、優先順位の値は保持されるので、メッセージがキューから取り出されるときに検査されます。
deq_time に、絶対時間またはキューへの登録が完了してからの相対時間として、メッセージが処理されるまで時間を指定できます。flags に、TPQTIME_ABS または TPQTIME_REL のいずれかを設定して、値の処理方法を指定できます。キューは、time を順序付けの基準として作成することができます。その場合、メッセージは使用可能時間によって順序付けされます。
Oracle Tuxedo /Q には、gp_mktime(3c) 関数が提供されています。この関数は、tm 構造体の日付と時刻を 1970 年 1 月 1 日から経過した秒数に変換します。time(2) および mktime(3C) 関数を gp_mktime(3c) の代わりに使用することもできます。値は、time_t 型 (typedef'd で指定された long 型) で返されます。キューからメッセージが取り出される絶対時間を設定するには、次の手順に従います。ここでは、2001 年 12 月 9 日正午 12:00 を使用します。
tm 構造体に入力します。#include <stdio.h>
#include <time.h>
static char *const wday[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "-unknown-"
};
struct tm time_str;
/*...*/
time_str.tm_year = 2001 - 1900;
time_str.tm_mon = 12 - 1;
time_str.tm_mday = 9;
time_str.tm_hour = 12;
time_str.tm_min = 0;
time_str.tm_sec = 1;
time_str.tm_isdst = -1;
gp_mktime を呼び出して deq_time に値を代入し、flags を設定して絶対時間が提供されることを示します。 #include <atmi.h>
TPQCTL qctl;
if ((qctl->deq_time = (long)gp_mktime(&time_str)) == -1) {
/* エラーのチェック */
}
qctl->flags = TPQTIME_ABS
tpenqueue() を呼び出します。if (tpenqueue(qspace, qname, qctl, *data,*len,*flags) == -1) {
/* エラーのチェック */
}
キューからメッセージを取り出す相対時間、たとえば、キューへの登録操作が完了してから nnn 秒などを指定する場合、deq_time に秒数を指定し、flags に TPQTIME_REL を設定します。
tpenqueue() の呼び出し側がトランザクション モードにある場合に、TPNOTRAN が設定されていないと、キューへの登録は呼び出し側のトランザクション内で行われます。呼び出し側は、tpenqueue() が成功したか失敗したかによって、メッセージがキューに登録されたかどうかを判断できます。呼び出しが正常に行われると、メッセージがキューに登録されたことが保証されます。呼び出しが失敗すると、メッセージがキューに登録された部分も含めて、トランザクションがロールバックされます。
tpenqueue() の呼び出し側がトランザクション モードにない場合、または TPNOTRAN が設定されている場合、メッセージは呼び出し側のトランザクションとは別のトランザクションでキューに登録されます。tpenqueue() への呼び出しが正常な戻り値を返した場合、メッセージがキューに登録されたことが保証されます。tpenqueue() の呼び出しが通信エラーまたはタイムアウトによって失敗した場合は、その障害がメッセージ登録の前に発生したのか後に発生したのか、呼び出し側には判断できません。
呼び出し側がトランザクション モードにないときに TPNOTRAN を指定しても意味がありません。
#include <atmi.h>
int tpdequeue(char *qspace, char *qname, TPQCTL *ctl, \
char **data, long *len, long flags)
この呼び出しが行われると、qspace で識別されるキュー スペース内の qname キューからメッセージを取り出すようにシステムが指示されます。メッセージは、*data が指すアドレスにあるバッファ (tpalloc(3c) によって割り当てられたもの) に挿入されます。len はデータの長さを示します。tpdequeue() から返された len が 0 の場合、そのメッセージにはデータ部分がないことを示します。flags にビット設定を行うと、システムに tpdequeue() 呼び出しの処理方法が通知されます。ctl が指す TPQCTL 構造体には、この呼び出しの処理方法についての詳細な情報が記述されます。
tpdequeue(3c) の処理を制御するいくつかの重要な引数があります。その一部について、以下に説明します。
qspace は、管理者によって既に作成されたキュー スペースを識別します。TMQUEUE サーバがコンフィグレーション ファイルの SERVERS セクションで定義されている場合、そのサーバが提供するサービス名は、実際のキュー スペース名 (GROUPS セクションの OPENINFO パラメータの一部として指定されます) のエリアスになります。たとえば、アプリケーションがサーバ TMQUEUE を使用する場合、qspace 引数が指す値は、TMQUEUE が宣言するサービス名になります。サービス名のエリアスが何も定義されていない場合、デフォルトのサービス名はサーバ名 TMQUEUE と同じになります。その場合、コンフィグレーション ファイルには次が記述されています。
TMQUEUE
SRVGRP = QUE1 SRVID = 1
GRACE = 0 RESTART = Y CONV = N
CLOPT = "-A"
または
CLOPT = "-s TMQUEUE"
サーバ グループ QUE1 のエントリには、OPENINFO パラメータを使用して、リソース マネージャ、デバイスのパス名、およびキュー スペース名を指定します。クライアント プログラムにおける qspace 引数は、次のように記述されます。
if (tpdequeue("TMQUEUE", "REPLYQ", (TPQCTL *)&qctl,
(char **)&reqstr, &len,TPNOTIME) == -1) {
Error checking
}
TMQUEUE(5) リファレンス ページの例では、サーバを作成してコンフィグレーション ファイルで指定する際に、サービスのエリアスを指定する方法が示されています。「サンプル アプリケーション」のサンプル プログラムでも、サービスまたはキュー スペース名のエリアスが指定されています。
キュー スペース内のキュー名は、そのキュー スペースにアクセスするアプリケーション間で一貫していなければなりません。これは、応答キューでは特に重要です。qname が応答キューを参照する場合、管理者はほかのキューと同じ方法で応答キュー、そして多くの場合、エラー キューも作成します。qname は、メッセージまたは応答を取り出すキューを指すポインタです。
この 2 つの引数は、tpenqueue() で使用される場合と若干意味が異なります。*data は、キューから取り出されたメッセージをシステムが格納するバッファのアドレスを指します。tpdequeue() が呼び出された場合に、この値が NULL であることはエラーです。
tpdequeue() が戻ると、len は取り出されたデータのデータ長情報を持つ long 型を指します。0 は応答にデータがなかったことを示します。アプリケーションによっては、これは正当で正常な応答です。長さ 0 の応答を受信した場合でも、それをキューに登録された要求の正常処理を示すために使用できます。バッファが tpdequeue() 呼び出しの前と比べて変更されているかどうかを確認する場合は、tpdequeue() 呼び出しの前にデータ長を保存し、それを呼び出しが終了した後で len と比較します。
flags の値は、tpdequeue() 呼び出しの処理方法を Oracle Tuxedo システムに通知するために使用されます。次は、有効なフラグです。
TPNOTRAN
TPNOBLOCK
TPEBLOCK が設定されます。このフラグが設定されていて、ターゲットのキューが別のアプリケーションによって排他的にオープンされているなどのブロッキング条件が存在する場合には、呼び出しは異常終了して tperrno に TPEDIAGNOSTIC が設定され、TPQCTL 構造体の診断フィールドは QMESHARE に設定されます。後者の場合、Oracle Tuxedo システム以外の Oracle Products に基づくほかのアプリケーションが、キューイング サービス API (QSAPI) を使用して読み取りと書き込み、またはそのいずれかを排他的に行うためにキューをオープンしています。
TPNOBLOCK が設定されていない場合に、ブロッキング状態が存在すると、その状態が解消されるかタイムアウト (トランザクション タイムアウトまたはブロッキング タイムアウト) が発生するまで、呼び出し側はブロックされます。(TPQCTL 構造体の) flags に TPQWAIT オプションが指定されている場合は、このブロッキング条件には、キュー自体のブロッキングは含まれません。
TPNOTIME
TPNOCHANGE
data が指すバッファのタイプは変更されません。デフォルトでは、*data が指すバッファとは異なるタイプのバッファが受信されると、受信側が着信バッファのタイプを識別する限り、*data のバッファ タイプは、受信されたバッファのタイプに変更されます。つまり、受信されたバッファのタイプとサブタイプは、*data が指すバッファのタイプとサブタイプと一致しなければなりません。
TPSIGRSTRT
TPGOTSIG が設定されます。
tpdequeue() の 3 番目の引数は、TPQCTL 型の構造体へのポインタです。TPQCTL 構造体には、アプリケーションで使用されるメンバーと Oracle Tuxedo システムで使用されるメンバーがあり、アプリケーション プログラムとキュー機能間の両方向でパラメータがやり取りされます。tpdequeue() を呼び出すクライアントはフラグを設定して、システムで値が提供されるべきフィールドをマークします。前述のように、この構造体は tpenqueue() でも使用されます。一部のメンバーは、tpenqueue() だけに適用されます。この構造体全体のサンプル コードは、「tpqctl_t 構造体」に示されています。
tpdequeue() への入力では、次のフィールドを TPQCTL 構造体に設定します。
long flags; /* どの値が設定されるかを示します。*/
char msgid[32]; /* キューから取り出すメッセージの ID */
char corrid[32]; /* キューから取り出すメッセージの相関識別子 */
次は、tpdequeue() の入力として有効なフラグです。
TPNOFLAGS
TPQGETBYMSGID
ctl->msgid で識別されるメッセージ識別子を持つメッセージが取り出されることが要求されます。メッセージ識別子は、以前に呼び出された tpenqueue() で決定されています。メッセージがあるキューから別のキューに移動された場合、メッセージ識別子は変更されます。メッセージ識別子の値は 32 バイト全体が意味を持つので、ctl->msgid で識別される値は、たとえば NULL 文字を埋め込むなどして、完全に初期化される必要があります。
TPQGETBYCORRID
ctl->corrid で指定された相関識別子を持つメッセージを取り出すことが要求されます。相関識別子は、アプリケーションが tpenqueue() でキューにメッセージを登録したときに指定されます。相関識別子の値は 32 バイト全体が意味を持つので、ctl->corrid に指定される値は、たとえば NULL 文字を埋め込むなどして、完全に初期化する必要があります。
TPQWAIT
TPQWAIT が TPQGETBYMSGID または TPQGETBYCORRID と併せて設定されている場合、指定されたメッセージ識別子または相関識別子を持つメッセージがキューに存在しないときは、エラーが返されません。代わりに、基準を満たすメッセージを取り出すことができるようになるまで、プロセスは待機します。プロセスには呼び出し側のトランザクション タイムアウトが適用されます。また、トランザクション モードではない場合、TMQUEUE プロセスで -t オプションで指定されたタイムアウトが適用されます。
tpdequeue() は -1 を返し tperrno() を TPEDIAGNOSTIC に設定し、TPQCTL 構造体の診断フィールドを QMESYSTEM に設定します。
TPQWAIT 制御パラメータを指定する tpdequeue() の各要求では、条件を満たすメッセージがすぐに利用できない場合、キュー マネージャ (TMQUEUE) のアクション オブジェクトを使用できる必要があります。アクション オブジェクトが使用できない場合、tpdequeue() 要求は失敗します。利用できるキュー マネージャのアクション数は、キュー スペースの作成時または変更時に指定されます。待機中のキューからの取り出し要求が完了すると、対応するアクション オブジェクトは別の要求に使用できるようになります。
TPQPEEK
TPQPEEK を使用してメッセージを破棄せずにキューから取り出す場合、その取り出し要求をシステムが処理している短時間の間、非ブロッキング状態のほかのメッセージ取り出し操作にメッセージが認識されないことがあります。たとえば、特定の選択基準 (メッセージ識別子や相関識別子など) を使用してメッセージをキューから取り出す操作が、破棄せずに取り出しが現在行われているメッセージを探している場合などがあります。
次は、tpdequeue() からの出力情報を制御する flags パラメータの有効なビットです。どのフラグ ビットでも、tpdequeue() の呼び出し時にオンになっていると、メッセージがキューに登録されたときに提供された値が、構造体の対応するフィールド (「tpqctl_t 構造体」を参照) に格納され、そのビットは設定されたままになります。値が使用できない (つまり、メッセージがキューに登録されたときに値が指定されなかった) 場合、または tpdequeue() を呼び出したときにビットが設定されなかった場合、tpdequeue() はフラグがオフの状態で完了します。
TPQPRIORITY
tpdequeue() の呼び出しが成功し、メッセージが明示的な優先順位でキューに登録された場合、その優先順位は ctl->priority に格納されます。優先順位は 1 以上 100 以内の範囲内で、数値が高いほど優先順位も高くなります。つまり、高い数値のメッセージが低い数値のメッセージよりも先にキューから取り出されます。優先順位によって順序付けられていないキューの場合、値は情報にすぎません。
TPQMSGID
TPQCORRID
tpdequeue() の呼び出しが成功し、メッセージが相関識別子によってキューに登録されていた場合、相関識別子が ctl->corrid に格納されます。相関識別子の値は、32 バイト全体が意味を持ちます。Oracle Tuxedo /Q が提供するメッセージの応答には、すべて元の要求メッセージの相関識別子が付いています。
TPQDELIVERYQOS
tpdequeue() の呼び出しが成功し、メッセージがサービスの配信品質と共にキューに登録されていた場合、TPQQOSDEFAULTPERSIST、TPQQOSPERSISTENT、または TPQQOSNONPERSISTENT フラグが ctl->delivery_qos に格納されます。メッセージがキューに登録されたときに配信サービスの品質が明示的に指定されていない場合は、対象となるキューのデフォルトの配信方針によってメッセージ配信の品質が決まります。
TPQREPLYQOS
tpdequeue() の呼び出しが成功し、メッセージがサービスの応答品質と共にキューに登録されていた場合、TPQQOSDEFAULTPERSIST、TPQQOSPERSISTENT、または TPQQOSNONPERSISTENT フラグが ctl->reply_qos に格納されます。メッセージがキューに登録されていたときに応答のサービス品質が明示的に指定されていない場合、ctl->replyqueue キューのデフォルトの配信ポリシーによって、すべての応答に対する配信サービスの品質が決まります。
TPQREPLYQ
tpdequeue() の呼び出しが成功し、メッセージが応答キューと共にキューに登録されていた場合、その応答キューの名前が ctl->replyqueue に格納されます。メッセージへの応答は、要求メッセージと同じキュー スペース内の指定されたキューに登録されます。
TPQFAILUREQ
tpdequeue() の呼び出しが成功し、メッセージが異常終了キューと共にキューに登録されていた場合、その異常終了キューの名前が ctl->failurequeue に格納されます。異常終了メッセージは、要求メッセージと同じキュー スペース内の指定された異常終了キューに登録されます。
flags パラメータの残りのビットは、tpdequeue() が呼び出されるとクリア (0 に設定) されます。これには、TPQTOP、TPQBEFOREMSGID、TPQTIME_ABS、TPQTIME_REL、TPQEXPTIME_ABS、TPQEXPTIME_REL、および TPQEXPTIME_NONE が含まれます。これらのビットは、tpenqueue() の入力情報を制御する flags パラメータの有効なビットです。
tpdequeue() の呼び出しが失敗し、tperrno(5) に TPEDIAGNOSTIC が設定された場合は、失敗の原因を示す値が ctl->diagnostic に返されます。ctl->diagnostic の有効なコードには、「TPQCTL 構造体」に示されている tpenqueue() の値 (QMENOSPACE と QMERELEASE を除く) のほかに、次のものがあります。
QMENOMSG]
QMEINUSE]
TPQCTL 構造体の flags に TPQWAIT が設定されて tpdequeue() が呼び出された場合に、メッセージをすぐに取り出すことができないと、tpdequeue() が呼び出し側に制御を返す前に、TMQUEUE サーバは tpdequeue() 要求に一致するメッセージがキューに到着するのを待ちます。TMQUEUE プロセスは待機中の要求を無視し、ほかのプロセスの要求を処理しながら、最初の要求の条件が満たされるのを待ちます。TPQGETBYMSGID や TPQGETBYCORRID も指定されている場合、サーバは指定されたメッセージ識別子や相関識別子を持つメッセージをキューから取り出せるようになるまで待ちます。このどちらのフラグも設定されていない場合、サーバは任意のメッセージがキューに登録されるまで待ちます。呼び出しがトランザクション モードの場合、サーバの待機時間は、呼び出し側のトランザクション タイムアウトによって制御されます。呼び出しがトランザクション モードでない場合、TMQUEUE サーバの CLOPT パラメータに指定される -t オプションで制御されます。
TMQUEUE サーバは、要求を処理するアクション リソースを利用できる限り、複数の待機中 tpdequeue() 要求を同時に処理できます。十分なアクション リソースがキュー スペースに対して設定されていない場合、tpdequeue() は失敗します。使用しているシステムがこれに該当する場合は、キュー スペースに対するアクション リソースの数を増やしてください。
キューからのメッセージの取り出しで、エラー処理の最良の方法を考慮する場合、次の 2 種類のエラーを区別しておきます。
デフォルトでは、メッセージがトランザクション内でキューから取り出され、そのトランザクションがロールバックされると、retry パラメータが 0 より大きい場合は、そのメッセージはキューに戻されて、再度キューからの取り出しと実行が可能になります。一時的な障害が解消されるように (たとえば、データベースのロックを別のトランザクションが解除するように) 少し時間をおいてから、メッセージの取り出しと実行を再度試みます。通常、再試行の回数に上限を設定することも、アプリケーション不備によってリソースを著しく浪費することを防ぐために有用です。管理者がキューを設定するときに、再試行の回数と遅延時間 (秒単位) の両方を指定できます。再試行の回数 0 は、再試行が行われないことを示します。再試行の回数が上限に達すると、管理者がキュー スペースに設定するエラー キューにメッセージが移動されます。エラー キューが設定されていない場合、再試行回数の上限に達したメッセージは単に削除されます。エラー キューにあるメッセージは、管理者によって処理されなければなりません。管理者は、アプリケーションの要件を満たす方法で発信元に通知する必要があります。選択されたメッセージ処理方法は、メッセージをキューに登録した発信元プログラムにほとんど透過的です。メッセージは一度正常にキューに登録されると、tpenqueue() のパラメータおよびキューの属性に従って処理されることが実質的には保証されます。メッセージがエラー キューに移動されたことの通知は、キューのパラメータを適切に調整されたシステムではほとんどありません。
異常終了キュー (通常、キュー スペースのエラー キューとは異なります) は、キューに登録された各メッセージと対応付けられます。このキューは、異常終了メッセージを置く場所として、キューにメッセージを登録する呼び出しで指定されます。特定の要求に対する異常終了メッセージは、アプリケーション生成の相関識別子で識別できます。相関識別子は、キューにメッセージを登録するときに、そのメッセージと対応付けられます。
成功するまで (または事前に定義された回数まで) 再試行を繰り返すというデフォルトの動作は、時間が経過すれば解決されるような一時的な障害が失敗の原因であり、メッセージが後から適切に処理される場合は適しています。
障害が一時的なものではない場合もあります。たとえば、存在しないアカウントでの操作を要求するメッセージがキューに入れられている場合 (アプリケーションも適当な時間に存在していない場合) です。その場合、再試行してリソースを浪費しないようにします。アプリケーション プログラマまたは管理者が、特定の操作の失敗が一時的ではないと判断した場合、単に再試行回数を 0 に設定します。ただし、この場合、このようなメッセージが入るキュー スペースのエラー キューを継続的にクリアするメカニズム (キューを定期的に読み取るバックグラウンドのクライアントなど) が必要です。また、同じサービスに対する障害でも、一時的なもの (データベース ロックの競合など) であったり、永続的なもの (アカウントが存在しないなど) であったりする場合が多くあります。
メッセージが TMQFORWARD によって処理される (キューから取り出され、tpcall() を介してアプリケーションに渡される) 場合、tpcall() が返す情報には、TPESVCFAIL エラーが一時的な障害と永続的な障害のどちらによって生じたものであるかを示すメカニズムはありません。
キューからの取り出しをアプリケーションが処理する場合、簡単な解決方法はたとえ操作が失敗しても、そのサービスに対して成功を返すことです。つまり、TPSUCCESS を設定して tpreturn を実行します。これにより、トランザクションはコミット可能になり、メッセージはキューから削除されます。応答メッセージが使用されている場合、サービスから返されるバッファの情報によって操作の失敗を示すことができ、メッセージが応答キューに登録されます。tpreturn の rcode 引数も、アプリケーション固有の情報を返すために使用できます。
サービスが失敗し、トランザクションをロールバックする必要がある場合、TMQFORWARD が処理をそれ以上行わずに、2 番目のトランザクションを実行してキューからメッセージを削除するかどうかは明確ではありません。デフォルトでは、TMQFORWARD は失敗したサービスに対するメッセージを削除しません。TMQFORWARD のトランザクションはロールバックされ、メッセージはキューに格納されます。TMQFORWARD にコマンドライン オプションを指定すると、サービスが失敗して 0 より長い応答メッセージが返された場合に、メッセージがキューから削除されます。メッセージは、2 番目のトランザクションで削除されます。この処理を行うには、キューに遅延時間および再試行回数を設定する必要があります。メッセージが失敗したキューに対応付けられている場合、メッセージがキューから削除されたトランザクションと同じトランザクションで、応答データが異常終了キューに登録されます。
アプリケーションがキューに登録されたメッセージに対する応答を要求している場合、次の手順に従います。
TPSUCCESS を返し、tpreturn の rcode 引数に情報を示すコードを返すようにコーディングします。 tpenqueue() を呼び出してキューにメッセージを登録する際に、次のフラグ ビットがオンになるように flags を設定します。TPQCORRID TPQREPLYQ
TPQFAILUREQ TPQMSGID
この呼び出しを行う前に、corrid、replyqueue、および failurequeue の値を設定します。呼び出しから制御が戻ったら、corrid を保存します。
tpdequeue() を呼び出して応答を確認する際に、qname 引数に応答キューを指定し、次のフラグ ビットがオンになるように flags を設定します。TPQCORRID TPQREPLYQ
TPQFAILUREQ TPQMSGID
TPQGETCORRID
この呼び出しを行う前に、保存した相関識別子を使用して corrid に入力します。tpdequeue() の呼び出しが失敗し、tperrno(5) に TPEDIAGNOSTIC が設定された場合、詳しい情報を diagnostic から取得できます。エラー コード QMENOMSG を受信した場合、キューから取り出すことのできるメッセージがなかったことを示します。
tpdequeue() 呼び出しを設定します。この呼び出しでは、qname が異常終了キューの名前を指し、次のフラグ ビットがオンになるように flags を設定します。TPQCORRID TPQREPLYQ
TPQFAILUREQ TPQMSGID
TPQGETBYCORRID
corrid に相関識別子を挿入します。呼び出しから制御が戻ったら、len を調べてデータが受信されたかどうかを確認し、また、urcode を調べてサービスがユーザ戻りコードを返したかどうかを確認します。
メッセージの順次処理は、あるサービスがそのトランザクションがコミットされる前に、連鎖的に次のサービス用にメッセージをキューに登録することによって行われます。最初の発信元のプロセスは、reply_queue に対する一連の tpdequeue() 呼び出しによって順次処理の進行状況を追跡できます。ただし、各メンバーが同じ相関識別子を使用し、長さ 0 の応答を返すことが必要です。
また、非請求通知を使用して、順次処理全体が成功したという通知を最初の発信元に返すこともできます。順次処理の最後のトランザクションが tpcommit で終了したことを確認するには、tpdequeue() から戻された TPQCTL 構造体、またはサービスに渡された TPSVCINFO 構造体で渡されるクライアント識別子を使用して、tpnotify を呼び出す操作を追加します。最初の発信元であるクライアントは、tpsetunsol を呼び出して、使用されている非請求メッセージ ハンドラを指定しておかなければなりません。
キューへのメッセージの登録およびキューからのメッセージの取り出しに関するこれまでの説明では、キューが要求/応答の一形態として使用されていることが暗黙の前提になっていました。メッセージ自体はサービス要求である必要はありません。キュー機能は、あるプロセスから別のプロセスに、サービス要求と同じように効果的にデータを転送できます。アプリケーション間またはクライアント間のこの通信方式は、ピア ツー ピア通信と呼ばれます。
使用するアプリケーションが、このような目的で Oracle Tuxedo /Q を使用することに適している場合は、管理者に別のキューを作成してもらい、そのキューからメッセージを取り出す独自の受信用プログラムをコーディングします。
|