Oracle Tuxedoシステムでは、関数が失敗すると、
tperrno(5)変数を使用してプロセスに情報が提供されます。すべてのATMI関数は、正常に処理が行われた場合、整数またはポインタを返します。エラーが発生した場合、
-1または
NULLを返し、
tperrno()にエラーの原因を示す値を設定します。サービス・ルーチンを終了させるために使用する
tpreturn()や
tpforward()など、呼出し側に戻らない関数の場合、成功か失敗かを確認する唯一の方法はリクエスタの
tperrno()変数です。
tperrordetail(3c)および
tpstrerrordetail(3c)関数を使用すると、現在のスレッドへのOracle Tuxedoシステムの最新の呼出しで発生したエラーの詳細を取得できます。
tperrordetail()は、そのシンボリック名で表される整数値を返します。この整数値は、
tpstrerrordetail()の引数として使用され、エラー・メッセージを表す文字列を指すポインタを取得します。このポインタは、
userlog(3c)または
fprintf()の引数として使用できます。返されるシンボリック名については、
『Oracle Tuxedo ATMI C言語関数リファレンス』の
「tperrordetail(3c)」を参照してください。
tpurcode(5)は、ユーザー定義の条件だけを通知します。
tpurcodeの値は、
tpreturn()の
rcode引数の値に設定されます。
tpreturn()でエラーまたはトランザクション・タイムアウトが発生しないかぎり、
tpreturn()の
rval引数の値に関係なく、
tpurcodeの値が設定されます。
|
|
|
|
|
|
|
|
|
|
|
|
|
TPESVCFAIL、 TPESVCERR、 TPEBLOCK、および TPGOTSIG
|
|
TPEHAZARD2および TPEHEURISTIC2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
脚注1にあるように、
tperrno(5)によって通知される4種類のエラーは、すべてのATMI関数で発生するエラーです。それ以外のエラーの種類は、特定のATMI関数だけで発生します。以下に、一部のエラーの種類について詳しく説明します。
Oracle Tuxedoのシステム・エラーは、問題がアプリケーション・レベルではなく
システム・レベルで発生していることを示します。Oracle Tuxedoのシステム・エラーが発生すると、エラーの原因を示すメッセージが中央イベント・ログに書き込まれ、
tperrno(5)に
TPESYSTEMが返されます。詳細は、
11-41ページの「中央イベント・ログ」を参照してください。これらのエラーは、アプリケーションではなくシステムで発生するので、エラーの修正についてはシステム管理者に問い合せてください。
呼出し記述子のエラーは、呼出し記述子の数が上限値を超えている場合、または無効な値を参照している場合に発生します。非同期呼び出しや会話型呼出しでは、未処理の呼出し記述子の数が上限値を超えると、
TPELIMITが返されます。操作に対して無効な呼出し記述子の値が指定されている場合は、
TPEBADDESCが返されます。
呼出し記述子エラーが発生するのは、非同期呼び出しまたは会話型呼出しを行った場合だけです。(呼出し記述子は同期呼出しには使用されません。)非同期呼出しでは、呼出し記述子を使用して対応するリクエストに応答を関連付けることができます。会話型送受信用の関数は、呼出し記述子を使用して接続を識別します。つまり、接続を開始する呼出しでは、呼出し記述子を使用できることが大切です。
呼出し記述子エラーのトラブルシューティングでは、アプリケーション・レベルで特定のエラーを調べます。
システムでは、コンテキスト(またはOracle Tuxedoアプリケーションへの関連付け)ごとに未処理の呼出し記述子(応答)を50個まで使用できます。この上限値はシステムで定義されているので、アプリケーションで再定義することはできません。
会話型接続を同時に行う場合の呼出し記述子に関する制限は、応答時の制限ほど厳しくありません。上限値は、アプリケーション管理者が構成ファイルに定義します。アプリケーションが実行中ではない場合、管理者は構成ファイルの
RESOURCESセクションの
MAXCONVパラメータを変更できます。アプリケーションが実行中の場合も、
MACHINESセクションは動的に変更できます。詳細は、
『Oracle Tuxedoコマンド・リファレンス』の
「tmconfig、wtmconfig(1)」を参照してください。
呼出し記述子は無効になることがあります。無効な記述子が参照されると、次の場合に、
tperrno(5)にエラーが返されます。
•
|
呼出し記述子を使用してメッセージを取得したが、それがエラー・メッセージの場合( TPEBADDESC)
|
•
|
無効になった呼出し記述子の再利用を試みた場合( TPEBADDESC)
|
呼出し記述子が無効になるのは、以下のような場合です。
•
|
トランザクションがタイムアウトになった場合。 tpgetrply()の呼出しでタイムアウトが通知された場合、指定された記述子を使用してメッセージを取得することはできず、記述子は無効になります。
|
会話型接続の確立後に
tpsend()と
tprecv()が
TPEEVENTエラーで失敗した場合、イベントが発生します。
tpsend()でデータを送信できるかどうかは、発生したイベントによって決まります。システムは、関数呼出しに渡される
reventパラメータに
TPEEVENTを返します。行われる処理は、発生したイベントによって異なります。
処理の結果として複製オブジェクトが生成されるような操作が試みられると、
tperrno(5)に
TPEMATCHエラー・コードが返されます。次の表は、
TPEMATCHエラー・コードを返す関数とその原因を示しています。
|
|
|
指定された svcnameは、既にサーバーに対して通知されています。ただし、その処理は func以外の関数で行われています。この関数は失敗しても、 svcnameは現在の関数で通知されたままになります。つまり、 funcは現在の関数名を置き換えません。
|
|
tranidは、別のプロセスがすでに再開したトランザクション識別子を指しています。その場合、呼出し側のトランザクションの状態は変化しません。
|
|
指定されたサブスクリプション情報は、すでにイベント・ブローカに登録されています。
|
これらの関数の詳細は、『Oracle Tuxedo ATMI C言語関数リファレンス』を参照してください。
一般的な通信呼出しのエラーは、呼出しが同期または非同期で行われたかどうかに関係なく、どのような通信呼出しでも発生する可能性があります。
tperrno(5)には、
TPESVCFAIL、
TPESVCERR、
TPEBLOCK、または
TPGOTSIGエラーが返されます。
TPESVCFAILおよびTPESVCERRエラー
引数の処理中に
tpreturn()でエラーが発生すると、システムはエラーを元のリクエスタに返し、
tperrno(5)に
TPESVCERRを設定します。受信側では、
tperrno()の値を調べてエラーの発生を確認します。システムでは、
tpreturn()関数からのデータ送信は行われず、
tpgetrply()でエラーが発生した場合は、呼出し記述子が無効なものとみなされます。
tpreturn()で
TPESVCERRエラーが発生していない場合、
rvalに返された値で呼出しが成功したか失敗したかを判断できます。アプリケーションで
rvalパラメータに
TPFAILが指定されると、システムは
tperrno(5)に
TPESVCFAILを返し、呼出し側にデータ・メッセージを送信します。
rvalに
TPSUCCESSが設定されると、呼出し側に制御が正常に戻り、
tperrno()は設定されず、呼出し側がデータを受信します。
TPEBLOCKおよび
TPGOTSIGエラー・コードは、メッセージのリクエスト側に返される場合も応答側に返される場合もあるので、すべての通信呼出しに対して返される可能性があります。
ブロッキング状態が発生している場合に、リクエストを同期または非同期に送信するプロセスでブロッキング状態を無視するように
flagsパラメータに
TPPNOBLOCKが設定されていると、システムは
TPEBLOCKを返します。たとえば、システムのキューがすべていっぱいになっている場合、リクエストが送信されるとブロッキング状態になります。
tpcall()がブロッキング状態を示していない場合は、通信の送信部分だけに影響します。リクエストの送信に成功すると、その呼出しが応答を待っている間にブロッキング状態が存在したとしても、
TPEBLOCKは返されません。
flagsに
TPNOBLOCKを設定して呼出しを行った場合、
tpgetrply()が応答を待っている間にブロッキング状態が発生すると、
tpgetrply()に
TPEBLOCKが返されます。この状況は、メッセージがその時点で使用できない場合などに発生します。
TPGOTSIGエラーは、シグナルによってシステム・コールに割込みが発生したことを示します。このような状況は、実際にはエラーではありません。通信用の関数で
flagsパラメータに
TPSIGRSTRTが設定されていると、呼出しは失敗せず、
tperrno(5)に
TPGOTSIGエラー・コードは返されません。
関数に有効な引数だけを渡すようにすると、無効な引数によるアプリケーション・レベルでのエラーを修正できます。
管理リクエストが失敗すると、
tpadmcall(3c)関数は
tperrno(5)に
TPEMIBを返します。
outbufは更新され、エラーの原因を示すFML32フィールドが設定されて呼出し側に返されます。エラーの原因の詳細は、
『ファイル形式、データ記述、MIBおよびシステム・プロセス・リファレンス』の
「MIB(5)」および
「TM_MIB(5)」を参照してください。
バッファ・タイプを識別するためのデータ構造体やシステム表にエントリがないと、エラーが発生します。エントリ・タイプのエラーを示す
TPENOENTの意味は、そのエラーを戻す関数によって異なります。
表11-2は、このエラーを戻す関数とエラーの様々な原因を示しています。
|
|
|
システムで認識できないバッファ・タイプがリクエストされています。バッファ・タイプやサブタイプを認識するには、Oracle Tuxedoシステム・ライブラリに定義されているタイプ・スイッチ・データ構造体にそのエントリがあることが必要です。詳細は、 『ファイル形式、データ記述、MIBおよびシステム・プロセス・リファレンス』の 「tuxtypes(5)」および 「typesw(5)」を参照してください。
アプリケーション・レベルでは、既知のタイプを参照しなければなりません。参照していない場合は、システム管理者に問い合せてください。
|
|
エントリ用の領域が掲示板に残っていないため、呼出し側プロセスがアプリケーションに参加できません。システム管理者に問い合せてください。
|
|
呼出し側プロセスが参照しているサービスは、掲示板にエントリがないため、システムに認識されません。アプリケーション・レベルでサービスを正しく参照しなければなりません。正しく参照していない場合は、システム管理者に問い合せてください。
|
|
指定されたサービスに接続できません。そのようなサービス名が存在していないか、または会話型サービスではありません。
|
|
リクエストが行われていないにもかかわらず、呼出し側プロセスがリクエストの優先度を調べています。これは、アプリケーション・レベルのエラーです。
|
|
サービス名の通知を解除することができません。そのサービス名は、呼出し側プロセスによって現在通知されていません。
|
tpenqueue(3c)、 tpdequeue(3c)
|
関連付けられている TMQUEUE(5)サーバーが使用できないため、キュー・スペースにアクセスできません。詳細は、『ファイル形式、データ記述、MIBおよびシステム・プロセス・リファレンス』を参照してください。
|
|
Oracle Tuxedoシステムのイベント・ブローカにアクセスできません。詳細は、 8-1ページの「イベント・ベースのクライアントおよびサーバーのコーディング」を参照してください。
|
オペレーティング・システムのエラーは、オペレーティング・システム・コールが失敗したことを示します。
tperrno(5)に
TPEOSが返されます。UNIXシステムの場合、失敗したシステム・コールを識別する整数値がグローバル変数
Uunixerrに返されます。オペレーティング・システム・エラーを修正するには、システム管理者に問い合せてください。
呼出し側プロセスに、アプリケーションに参加するために必要なパーミッションが設定されていない場合、
tpinit()呼出しは失敗して、
tperrno(5)に
TPEPERMが返されます。パーミッションは、構成ファイルに設定されるもので、アプリケーションには設定されません。このエラーが発生した場合は、アプリケーション管理者に問い合せて、必要なパーミッションが構成ファイルに設定されていることを確認してください。
ATMI関数の呼出しが間違った順序で行われた場合、または間違ったプロセスを使用して行われた場合、プロトコル・エラーが発生します。たとえば、アプリケーションに参加する前に、クライアントがサーバーとの通信の開始を試みると、このエラーが発生します。また、イニシエータではなくトランザクションの参加リソースによって
tpcommit()が呼び出された場合も、このエラーが発生します。
ATMI呼出しを正しい順序で正しく使用すると、アプリケーション・レベルでプロトコル・エラーを修正できます。
プロトコル・エラーの原因を特定するには、次の事柄を確認してください。
•
|
正しいプロセスによって呼出しが行われているかどうか
|
詳細は、
『Oracle Tuxedo ATMI C言語関数リファレンス』のC言語アプリケーション・トランザクション・モニター・インタフェースの概要に関する項を参照してください。
特定のキューへの登録またはキューからの取出しに失敗した場合、
tpenqueue(3c)または
tpdequeue(3c)関数は、
tperrno(5)に
TPEDIAGNOSTICを返します。処理が失敗した原因は、
ctlを介して返される診断値によって判別できます。有効な
ctlフラグについては、
『Oracle Tuxedo ATMI C言語関数リファレンス』の
「tpenqueue(3c)」または
「tpdequeue(3c)」を参照してください。
アプリケーション・ドメインに参加するOracle Tuxedoシステムのリリース間で互換性に問題がある場合、Oracle Tuxedoシステムは
tperrno(5)に
TPERELEASEを返します。
たとえば、
tpnotify(3c)関数を呼び出す際に、呼出し側がターゲット・クライアントから承認メッセージを受け取るまでブロックすることを示す
TPACKフラグが設定されている場合、ターゲット・クライアントが
TPACK承認プロトコルがサポートされていない旧バージョンのOracle Tuxedoシステムを使用していると、
TPERELEASEエラーが返されます。
リソース・マネージャ・エラーは、
tpopen(3c)および
tpclose(3c)を呼び出したときに発生し、
tperrno(5)に
TPERMERRの値が返されます。リソース・マネージャを正しくオープンできなかった場合、
tpopen()でこのエラー・コードが返されます。同じように、リソース・マネージャを正しくクローズできなかった場合、
tpclose()でこのエラー・コードが返されます。Oracle Tuxedoシステムでは、移植性を保つために、この種類のエラーでは詳細な情報は返されません。リソース・マネージャ・エラーの正確な性質を判断するには、リソース・マネージャに問い合せる必要があります。
Oracle Tuxedoシステムでは、タイムアウト・エラーがサポートされており、アプリケーションがサービス・リクエストまたはトランザクションを待つ時間に制限があります。Oracle Tuxedoシステムでサポートされている設定可能なタイムアウト機構は、ブロッキング・タイムアウトとトランザクション・タイムアウトの2種類です。
ブロッキング・タイムアウトは、アプリケーションがサービス・リクエストに対する応答を待つ時間の上限値を指定します。アプリケーション管理者は、構成ファイルにシステムのブロッキング・タイムアウトを設定します。
トランザクション・タイムアウトは、トランザクション(その中で複数のサービス・リクエストが行われる場合もあります)の有効期間を定義します。アプリケーションのトランザクション・タイムアウトを定義するには、
tpbegin()に
timeout引数を渡します。
通信呼出しでは、ブロッキング・タイムアウトまたはトランザクション・タイムアウトのいずれかが返され、
tpcommit()ではトランザクション・タイムアウトだけが返されます。いずれの場合も、トランザクション・モードのプロセスで呼出しが失敗して
TPETIMEが返された場合は、トランザクション・タイムアウトが発生しています。
デフォルトでは、プロセスがトランザクション・モードではない場合、ブロッキング・タイムアウトが実行されます。通信呼出しの
flagsパラメータに
TPNOTIMEを設定すると、フラグの設定値はブロッキング・タイムアウトだけに適用されます。プロセスがトランザクション・モードの場合はブロッキング・タイムアウトは実行されず、
TPNOTIMEフラグが設定されていても関係ありません。
プロセスがトランザクション・モードではない場合に、非同期呼出しでブロッキング・タイムアウトが発生すると、ブロックされている通信呼出しは失敗します。ただし、呼出し記述子は有効なままであり、再度呼出しを行う場合に使用できます。ほかの通信には影響ありません。
トランザクション・タイムアウトが発生すると、非同期トランザクション応答の呼出し記述子(
TPNOTRANフラグが指定されていないもの)は無効になり、参照できなくなります。
呼出しがトランザクション・モードで行われていない場合、またはflagsパラメータにTPNOBLOCKが設定されていない場合、
TPETIMEは通信呼出しでブロッキング・タイムアウトが発生したことを示します。
注意:
|
TPNOBLOCKフラグが設定されている場合、ブロッキング状態が存在すると呼出しは直ちに戻るので、ブロッキング・タイムアウトは発生しません。
|
プロセスに対するリクエストまたは応答が不明なタイプのバッファで送信された場合、型付きバッファのエラーが返されます。リクエスト・データ・バッファの送信先のサービスでバッファ・タイプが認識されない場合、
tpcall()、
tpacall()および
tpconnect()関数は
TPEITYPEを返します。
プロセスで認識されるバッファ・タイプは、構成ファイルとプロセスにリンクされているOracle Tuxedoシステム・ライブラリの両方で識別されるものです。これらのライブラリは、プロセスで認識される型付きバッファを識別するデータ構造体を定義および初期化します。プロセスごとにライブラリを作成するか、またはバッファ・タイプが定義されたアプリケーション固有のファイルのコピーをアプリケーションで用意することができます。アプリケーションでは、バッファ・タイプ・スイッチと呼ばれるバッファ・タイプ・データ構造体をプロセスごとに設定できます。詳細は、
『ファイル形式、データ記述、MIBおよびシステム・プロセス・リファレンス』の
「tuxtypes(5)」および
「typesw(5)」を参照してください。
呼出し側で認識されないか、または使用できないバッファで応答メッセージが送信されると、
tpcall()、
tpgetrply()、
tpdequeue(3c)および
tprecv()関数は
TPEOTYPEを返します。呼出し側で使用できないバッファの場合、そのバッファ・タイプはタイプ・スイッチに含まれています。ただし、返されたタイプは応答の受信用に割り当てられたタイプと一致せず、また呼出し側は異なるバッファ・タイプを使用することはできません。呼出し側は、
flagsに
TPNOCHANGEを設定して、このプリファレンスを示します。その場合、厳密なタイプ・チェックが行われ、違反が見つかると
TPEOTYPEが返されます。デフォルトでは、緩やかなタイプ・チェックが行われます。その場合、呼出し側で認識される限り、最初に割り当てられたタイプ以外のバッファ・タイプが返されることもあります。応答の送信では、応答バッファは呼出し側で認識できるものでなければなりません。また、厳密なタイプ・チェックが指定されている場合は、それに従う必要があります。
アプリケーション内では、
tpreturn()の
rcode引数を使用して、呼出し側のプログラムにユーザー定義のエラーに関する情報を渡すことができます。また、システムは、
tpurcodeの値に
tpreturn()の
rcode引数の値を設定します。
tpreturn(3c)または
tpurcode(5)の詳細は、
『Oracle Tuxedo ATMI C言語関数リファレンス』と
『ファイル形式、データ記述、MIBおよびシステム・プロセス・リファレンス』をそれぞれ参照してください。
アプリケーションのロジックは、戻り値がある呼出しのエラー条件を調べ、エラー発生時に適切な処理を行うように設計します。特に、次を確認します。
•
|
-1または NULL値が返されていないかどうかを確認します。どちらの値が返されるかは、呼び出す関数によって異なります。
|
•
|
tperrno(5)の値を確認し、その値に応じて適切なアプリケーション・ロジックを実行するswitch文が記述されたコードを呼び出します。
|
ATMIでは、
tpstrerrordetail(3c)、
tpstrerror(3c)および
Fstrerror、Fstrerror32(3fml)の3種類の関数がサポートされており、Oracle TuxedoシステムとFMLのメッセージ・カタログからエラー・メッセージのテキストを取得します。これらの関数は、対応するエラー・メッセージを指すポインタを返します。このポインタを使用して、
userlog(3c)などに、ポインタが指すテキストを送ることができます。詳細は、
『Oracle Tuxedo ATMI C言語関数リファレンス』の
「tpstrerrordetail(3c)」および
「tpstrerror(3c)」を参照してください。また、
『Oracle Tuxedo ATMI FML関数リファレンス』の
「Fstrerror、Fstrerror32(3fml)」を参照してください。
リスト11-1は、エラーの一般的な処理方法を示しています。この例では、
atmicall()関数は、一般的なATMI呼出しを表しています。switch文(21行目)の後のコードには、アプリケーション定義の戻りコードの解釈に
tpurcodeを使用する方法が示されています。
001 #include <stdio.h>
002 #include "atmi.h"
003
004 main()
005
006 {
007 int rtnval;
008
009 if (tpinit((TPINIT *) NULL) == -1)
010
error message, exit program;
011 if (tpbegin(30, 0) == -1)
012
error message, tpterm, exit program;
013
014
allocate any buffers,
015
make atmi calls
016
check return value
017
018 rtnval =
atmicall();
019
020 if (rtnval == -1) {
021 switch(tperrno) {
022 case TPEINVAL:
023 fprintf(stderr, "Invalid arguments were given to
atmicall\n");
024 fprintf(stderr, "e.g., service name was null or flags wrong\n");
025 break;
026 case ...:
027 fprintf(stderr, ". . .");
028 break;
029
030
Include all error cases described in the atmicall(3) reference 031
page.
032
Other return codes are not possible, so there should be no 033
default within the switch statement.
034
035 if (tpabort(0) == -1) {
036 char *p;
037 fprintf(stderr, "abort was attempted but failed\n");
038 p = tpstrerror(tperrno);
039 userlog("%s", p);
040 }
041 }
042 else
043 if (tpcommit(0) == -1)
044 fprintf(stderr, "REPORT program failed at commit time\n");
045
046
The following code fragment shows how an application-specific
047
return code can be examined.
048 .
049 .
050 .
051 ret = tpcall("servicename", (char*)sendbuf, 0, (char **)&rcvbuf, &rcvlen, \
052 (long)0);
053 .
054 .
055 .
056 (void) fprintf(stdout, "Returned tpurcode is: %d\n", tpurcode);
057
058
059 free all buffers
060 tpterm();
061 exit(0);
062 }
tperrno(5)の値は、各問題の詳細を示し、どのレベルで問題の解決が可能かを示しています。アプリケーションで、ある処理に特定のエラー条件が定義されている場合、
tpurcodeの値にも同じことが言えます。
リスト11-2は、
tpstrerrordetail(3c)関数を使用して、エラーの発生時に詳細情報を取得する方法を示しています。
リスト11-2
tpstrerrordetail()によるエラー処理
001 #include <stdio.h>
002 #include <string.h>
003 #include <atmi.h> /* BEA Tuxedo Header File */
004 #define LOOP_ITER 100
005 #if defined(__STDC__) || defined(__cplusplus)
006 main(int argc, char *argv[])
007 #else
008 main(argc, argv)
009 int argc;
010 char *argv[];
011 #endif
012 {
013 char *sendbuf, *rcvbuf;
014 long sendlen, rcvlen;
015 int ret;
016 int i;
017 if(argc != 2) {
018 (void) fprintf(stderr, "Usage: simpcl string\n");
019 exit(1);
020 }
021 /* Attach to BEA Tuxedo System as a Client Process */
022 if (tpinit((TPINIT *) NULL) == -1) {
023 (void) fprintf(stderr, "Tpinit failed\n");
024 exit(1);
025 }
026 sendlen = strlen(argv[1]);
027
028 /* Allocate STRING buffers for the request and the reply */
029
030 if((sendbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {
031 (void) fprintf(stderr,"Error allocating send buffer\n");
032 tpterm();
033 exit(1);
034 }
035
036 if((rcvbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {
037 (void) fprintf(stderr,"Error allocating receive buffer\n");
038 tpfree(sendbuf);
039 tpterm();
040 exit(1);
041 }
042
043 for( i=0; i<LOOP_ITER; i++) {
044 (void) strcpy(sendbuf, argv[1]);
045
046 /* Request the service TOUPPER, waiting for a reply */
047 ret = tpcall("TOUPPER", (char *)sendbuf, 0, (char **)&rcvbuf, &rcvlen, (long)0);
048
049 if(ret == -1) {
050 (void) fprintf(stderr, "Can't send request to service
TOUPPER\n");
051 (void) fprintf(stderr, "Tperrno = %d, %s\n", tperrno, tpstrerror(tperrno));
052
053 ret = tperrordetail(0);
054 if(ret == -1) {
055 (void) fprintf(stderr, "tperrodetail() failed!\n");
056 (void) fprintf(stderr, "Tperrno = %d, %s\n", tperrno, tpstrerror(tperrno));
057 }
058 else if (ret != 0) {
059 (void) fprintf( stderr, "errordetail:%s\n",
060 tpstrerrordetail( ret, 0));
061 }
062 tpfree(sendbuf);
063 tpfree(rcvbuf);
064 tpterm();
065 exit(1);
066 }
067 (void) fprintf(stdout, "Returned string is: %s\n", rcvbuf);
068 }
069
070 /* Free Buffers & Detach from System/T */
071 tpfree(sendbuf);
072 tpfree(rcvbuf);
073 tpterm();
074 return(0);
以下の項では、各種のプログラミング機能がトランザクション・モードでどのように動作するかについて説明します。まず、トランザクション・モードのコーディングで従うべき基本的な通信規則について説明します。
トランザクション・モードで実行するコードを記述する場合は、以下の基本的な通信規則に従います。
•
|
同じトランザクションに参加するプロセスでは、すべてのリクエストで応答が必要です。応答を必要としないリクエストを行うには、 tpacall()の flagsパラメータに TPNOTRANまたは TPNOREPLYを設定します。
|
•
|
サービスは、 tpreturn()または tpforward()を呼び出す前に、すべての非同期トランザクション応答を取得する必要があります。この規則には、コードをトランザクション・モードで実行するかどうかに関係なく従います。
|
•
|
イニシエータは、 tpcommit()を呼び出す前に、すべての非同期トランザクション応答( TPNOTRANフラグが指定されていないもの)を取得する必要があります。
|
•
|
トランザクションの参加リソース以外からの応答を必要とする非同期呼出しには、応答を取得する必要があります。つまり、応答が抑制されたのではなくトランザクションが抑制された tpacall()で行ったリクエストに対する応答を取得する必要があります。
|
•
|
トランザクションがタイムアウトになっていなくても、「中断のみ」としてマークされている場合、以降の通信では TPNOTRANフラグを設定して、トランザクションがロールバックされた後でも通信の結果が保持されるようにします。
|
•
|
トランザクションがタイムアウトになると、以下のようになります。
|
•
|
タイムアウトになった呼出しの記述子は無効になり、以降この記述子を参照すると、 TPEBADDESCが返されます。
|
•
|
非同期呼出しで、 tpacall()の flagsパラメータに TPNOREPLY、 TPNOBLOCK、または TPNOTRANを設定できます。
|
•
|
タイムアウト以外の理由でトランザクションが一度「中断のみ」とマークされると、 tpgetrply()の呼出しでは、呼出しのローカル状態を表す値が戻され、ローカル条件を反映する成功コードまたはエラー・コードのいずれかが戻されます。
|
•
|
応答を取得するために tpgetrply()で一度記述子を使用した場合、またはエラー条件を通知するために tpsend()または tprecv()で一度記述子を使用した場合、その記述子は無効になり、以降この記述子を参照すると TPEBADDESCが返されます。この規則には、コードをトランザクション・モードで実行するかどうかに関係なく従います。
|
•
|
トランザクションが一度中断されると、未処理のトランザクションの呼出し記述子( TPNOTRANフラグが設定されていないもの)はすべて無効になり、以降この記述子を参照すると TPEBADDESCが返されます。
|
以下の項では、トランザクションに関連するエラーについて説明します。
トランザクション・エラーが発生すると、
tperrno(5)に
TPETRANが返されます。ただし、このようなエラーの意味は、そのエラーを返す関数によって異なります。
表11-3は、トランザクション・エラーを返す関数と、考えられるエラーの原因を示しています。
|
|
|
通常は、トランザクションの開始を試みたときに発生する一時的なシステム・エラーが原因で起こります。呼出しを繰り返し行うと、問題が解決します。
|
|
TPNOTRANフラグを設定しないでリクエストを行った後、トランザクション応答を取得するためにこの関数が呼び出されました。
|
|
呼出し側が、1つ以上のリソース・マネージャとグローバル・トランザクション外の作業に関与しているため、Oracle Tuxedoシステムがグローバル・トランザクションを再開できません。そのような作業はすべて、グローバル・トランザクションを再開する前に完了している必要があります。ローカル・トランザクションについての呼出し側の状態は、変更されません。
|
|
トランザクションがサポートされていないサービスに対して、トランザクション・モードで呼出しが行われました。サービスには、データベース管理システム(DBMS)にアクセスし、その結果トランザクションがサポートされるサーバー・グループに属するものがあります。そのようなグループに属さないサービスもあります。また、トランザクションがサポートされたサービスには、トランザクションがサポートされていないソフトウェアとの相互運用を必要とするものがあります。たとえば、フォームを出力するサービスの処理が、トランザクションがサポートされていないプリンタで行われる場合があります。トランザクションがサポートされていないサービスは、トランザクションの参加リソースとして動作できない場合があります。
サービスをサーバーやサーバー・グループにグループ分けする作業は、管理タスクの1つです。どのサービスでトランザクションがサポートされているかを確認するには、アプリケーション管理者に問い合せてください。
トランザクション・レベルのエラーをアプリケーション・レベルで修正するには、 TPNOTRANフラグを有効にするか、またはトランザクション外でエラーが返されたサービスにアクセスします。
|
致命的なトランザクション・エラーが発生した場合、アプリケーションでは、イニシエータで
tpabort()を呼び出してトランザクションを明示的に中断しなければなりません。そのため、トランザクションにとって致命的なエラーを認識することが大切です。次の3つの場合、トランザクションは失敗します。
•
|
トランザクションのイニシエータまたは参加リソースが、次のいずれかの理由により「中断のみ」にマークされました。
|
•
|
応答バッファの typeまたは subtypeが不明であるか、または呼出し側で使用できないので、成功したか失敗したかを判断できません。 tperrno(5)に TPEOTYPEが設定されます。
|
トランザクションにとって致命的なプロトコル・エラーが発生するのは、トランザクションの不正な参加リソースから
tpcommit()が呼び出された場合だけです。このエラーは、アプリケーション内で開発段階に修正できます。
イニシエータまたは参加リソースで障害が発生した後、またはトランザクションがタイムアウトになった後で、
tpcommit()が呼び出されると、暗黙的な中断エラーになります。その場合、コミットは失敗するので、トランザクションを中断する必要があります。
通信呼出しで
TPESVCERR、
TPESVCFAIL、
TPEOTYPE、または
TPETIMEが返された場合、
tpabort()を呼び出してトランザクションを明示的に中断しなければなりません。トランザクションを明示的に中断する前に、未処理の呼出し記述子を待つ必要はありません。ただし、これらの記述子は、呼出しが中断された後は無効とみなされるので、トランザクション終了後にこれらの記述子へのアクセスを試みると、
TPEBADDESCが返されます。
TPESVCERR、
TPESVCFAILおよび
TPEOTYPEの場合、トランザクションがタイムアウトにならないかぎり、引き続き通信呼出しを行うことができます。これらのエラーが戻された場合、トランザクションは「中断のみ」にマークされます。これ以降の処理の結果を保持するには、
flagsパラメータに
TPNOTRANを設定して通信用の関数を呼び出します。このフラグを設定すると、「中断のみ」にマークされたトランザクションで実行された処理は、トランザクションが中断してもロールバックされません。
トランザクション・タイムアウトが発生しても通信を続けることはできますが、次のような通信リクエストを行うことはできません。
そのため、非同期呼出しを行うには、
flagsパラメータに
TPNOREPLY、
TPNOBLOCK、または
TPNOTRANを設定する必要があります。
tpcommit()関数は、
TP_COMMIT_CONTROLの設定に応じて、
TPEHAZARDまたは
TPEHEURISTICを返します。
TP_COMMIT_CONTROLに
TP_CMT_LOGGEDを設定すると、2フェーズ・コミットの第2フェーズの実行前にアプリケーションに制御が移ります。その場合、第2フェーズ中に発生したヒューリスティックな判断がアプリケーションで認識されないことがあります。
TPEHAZARDまたは
TPEHEURISTICは1フェーズ・コミットで返すことができます。ただし、これが可能なのは、トランザクションに関与しているリソース・マネージャが1つだけで、1フェーズ・コミットでこのリソース・マネージャがヒューリスティックな判断を返すか、なんらかの障害の発生を示す場合です。
TP_COMMIT_CONTROLに
TP_CMT_COMPLETEを設定すると、リソース・マネージャがヒューリスティックな判断を通知する場合は
TPEHEURISTICが返され、リソース・マネージャがなんらかの障害を通知する場合は
TPEHAZARDが返されます。
TPEHAZARDは、コミットの第2フェーズ(または1フェーズ・コミット)で参加リソースになんらかの障害が発生し、トランザクションが正常終了したかどうかがわからない状況を示します。
tpcommit()を呼び出した後でタイムアウトが発生した場合、トランザクションはどのような状態になるでしょうか。トランザクションがタイムアウトになり、そのトランザクションが中断されたことがシステムで認識されると、システムは
tperrno(5)に
TPEABORTを設定して、そのような状況の発生を通知します。トランザクションのステータスが不明な場合は、エラー・コードに
TPETIMEを設定します。
トランザクションの状態が明確ではない場合、リソース・マネージャに問い合せる必要があります。まず、トランザクションによって行われた変更が適用されたかどうかを確認します。これにより、トランザクションがコミットされたか、または中断されたかを判断できます。
トランザクション・モードのプロセスで、
flags引数に
TPNOTRANを設定して通信呼出しを行うと、呼び出されたサービスは現在のトランザクションに参加できません。サービス・リクエストの成功や失敗は、トランザクションの結果に影響しません。トランザクションは、サービスがトランザクションに参加しているかどうかには関係なく、そのサービスから応答が返されるのを待つ間にタイムアウトになる場合もあります。
tpreturn()およびtpforward()関数
トランザクション・モードで実行中にプロセスを呼び出すと、
tpreturn()および
tpforward()は、トランザクションのサービス部分をそのトランザクションの完了時にコミットまたは中断できる状態にします。同じトランザクションでサービスを何度も呼び出すことができます。システムは、トランザクションのイニシエータによって
tpcommit()または
tpabort()が呼び出されないかぎり、トランザクションを完全にはコミットまたは中断しません。
サービス内で行われた通信呼出しのすべての未処理の記述子が取得されるまで、
tpreturn()または
tpforward()を呼び出すことはできません。
rvalに
TPSUCCESSを設定して、未処理の記述子で
tpreturn()を呼び出すと、プロトコル・エラーが発生し、
tpgetrply()を待機中のプロセスに
TPESVCERRが戻されます。そのプロセスがトランザクション・モードになっている場合、呼出し側は「中断のみ」にマークされます。トランザクションのイニシエータが
tpcommit()を呼び出した場合も、トランザクションが暗黙的に中断されます。
rvalに
TPFAILを設定して、未処理の記述子で
tpreturn()を呼び出すと、
tpgetrply()を待機中のプロセスに
TPESVCFAILが戻されます。トランザクションへの影響は同じです。
トランザクション・モードで実行中に
tpreturn()を呼び出すと、tpreturn()で発生したプロセス・エラー、またはアプリケーションによって
rvalに設定された値で示されるエラーにより、トランザクションの結果に影響することがあります。
tpforward()を使用すると、ある時点までは要求が正しく処理されていることを示すことができます。アプリケーション・エラーが検出されない場合、システムは
tpforward()を呼び出します。アプリケーション・エラーが検出された場合、システムは
TPFAILを設定して
tpreturn()を呼び出します。
tpforward()を正しく呼び出さないと、システムはその呼出しをプロセス・エラーと見なし、エラー・メッセージをリクエスタに返します。
tpterm()関数は、アプリケーションからクライアント・コンテキストを削除します。
クライアント・コンテキストがトランザクション・モードになっている場合、呼出しは失敗して、
tperrno(5)に
TPEPROTOが返されます。クライアント・コンテキストは、トランザクション・モードでアプリケーションの一部として残ります。
呼出しが成功すると、現在の実行スレッドはアプリケーション内に存在しなくなるため、クライアント・コンテキストは、トランザクションと通信したりトランザクションに参加できなくなります。
ATMI関数を使用してトランザクションを定義すると、Oracle Tuxedoシステムによって内部呼出しが実行され、トランザクションに参加している各リソース・マネージャにグローバル・トランザクション情報が渡されます。
tpcommit()または
tpabort()など呼び出すと、各リソース・マネージャに対して内部呼出しが行われ、呼出し側のグローバル・トランザクションのために行われていた作業がコミットまたは中断されます。
グローバル・トランザクションが開始された場合(明示的でも暗黙的でも)、アプリケーション・コードでリソース・マネージャのトランザクション関数を明示的に呼び出すことはできません。このトランザクション規則に従わないと、不安定な結果が生じます。
tpgetlev()関数を使用すると、リソース・マネージャのトランザクション関数を呼び出す前に、グローバル・トランザクション内にすでにプロセスがあるかどうかを確認できます。
リソース・マネージャによっては、トランザクションの整合性レベルなど、特定のパラメータをプログラマが設定できるものがあります。その場合、リソース・マネージャ間のインタフェースで使用可能なオプションを指定します。そのようなオプションは、次の2つの方法で使用できるようになります。
•
|
リソース・マネージャ固有の関数呼出し。分散アプリケーションのプログラマは、これらの関数を使用してオプションを設定することができます。
|
•
|
ハードコーディングされたオプション。リソース・マネージャのプロバイダで提供されるトランザクション・インタフェースに組み込まれています。
|
詳細は、リソース・マネージャのドキュメントを参照してください。
オプションの設定方法はリソース・マネージャによって異なります。たとえば、Oracle TuxedoシステムのSQLリソース・マネージャの場合、
set transaction文を使用して、Oracle Tuxedoシステムによってすでに開始されているトランザクションに対する特定のオプション(整合性レベルとアクセス・モード)が決まります。
以降の項では、次のトランザクションについて説明します。
トランザクション・モードになっている呼出し側が、現在のトランザクションに参加するために別のサービスを呼び出した場合、次のようになります。
•
|
呼び出されたプロセスの成功や失敗は、現在のトランザクションに影響します。参加リソースで致命的なトランザクション・エラーが発生すると、現在のトランザクションは「中断のみ」にマークされます。
|
•
|
正常終了した参加リソースによって行われた処理が適用されるかどうかは、トランザクションの結果に依存します。つまり、トランザクションが中断された場合は、すべての参加リソースの処理は適用されません。
|
•
|
現在のトランザクションに参加するために別のサービスを呼び出すときに、 TPNOREPLYフラグを使用することはできません。
|
AUTOTRANが設定された別のトランザクションでのサービス呼出し
TPNOTRANフラグを設定して通信呼出しを行い、呼び出されたときにトランザクションが自動的に開始するようにサービスが設定されている場合、呼出し側プロセスと呼び出されたプロセスはどちらもトランザクション・モードになります。ただし、この2つは別々のトランザクションを構成します。この状況では、次の処理が行われます。
•
|
tpreturn()はトランザクション・モードなので、トランザクションの参加リソースの障害やトランザクション・タイムアウトなどの影響を受けます。その場合、エラー・メッセージが返されます。
|
•
|
呼出し側のトランザクションの状態は、呼出し側に戻されるエラー・メッセージやアプリケーション障害の影響を受けません。
|
•
|
呼出し側のトランザクションは、呼出し側が応答を待っている間にタイムアウトになることがあります。
|
•
|
応答が必要ない場合、呼出し側のトランザクションは、通信呼出しによる影響を受けません。
|
新しい明示的なトランザクションを開始するサービスの呼出し
•
|
tpreturn()はトランザクションの役割は果たしません。つまり、サービス・ルーチンにトランザクションが明示的に定義されているかどうかにかかわらず、 tpreturn()の役割は常に同じです。
|
•
|
通常、システムはプロセス・エラー、バッファ・タイプ・エラー、またはアプリケーション障害を返し、 TPESVCFAIL、 TPEITYPE/ TPEOTYPE、および TPESVCERRの一般的な規則に従います。
|
•
|
呼出し側のトランザクションの状態は、呼出し側に戻されるエラー・メッセージやアプリケーション障害の影響を受けません。
|
•
|
呼出し側は、応答を待っている間にトランザクションがタイムアウトになることがあります。
|
•
|
応答が必要ない場合、呼出し側のトランザクションは、通信呼出しによる影響を受けません。
|
Oracle Tuxedoシステムで提供されるサブルーチン
Oracle Tuxedoシステムで提供されるサブルーチン
tpsvrinit()、
tpsvrdone()、
tpsvrthrinit(3c)および
tpsvrthrdone(3c)は、トランザクションで使用される場合は特定の規則に従う必要があります。
注意:
|
tpsvrthrinit(3c)と tpsvrthrdone(3c)は、マルチスレッド・アプリケーションだけで指定できます。 tpsvrinit()と tpsvrdone()は、スレッド・アプリケーションでも非スレッド・アプリケーションでも指定できます。
|
Oracle Tuxedoシステム・サーバーは、初期化時に
tpsvrinit()または
tpsvrthrinit(3c)を呼び出します。特に、
tpsvrinit()または
tpsvrthrinit(3c)は、呼出し側プロセスがサーバーになった後、サービス・リクエストの処理を開始する前に呼び出されます。
tpsvrinit()または
tpsvrthrinit(3c)で非同期通信を実行した場合、関数が戻る前にすべての応答が取得されなければなりません。この処理が行われなかった場合、システムは保留中の応答があっても無視して、サーバーを終了します。
tpsvrinit()または
tpsvrthrinit(3c)でトランザクションを定義した場合、関数が戻る前にすべての非同期応答を取得して、トランザクションを終了しなければなりません。この処理が行われなかった場合、システムは未処理の応答が残っていてもトランザクションを中断し、それらの応答をすべて無視します。その場合、サーバーは正常に終了します。
Oracle Tuxedoシステム・サーバーの抽象化では、サービス・リクエストの処理が完了した後、終了する前に
tpsvrdone()または
tpsvrthrdone(3c)を呼び出します。この時点で、サーバーのサービスの通知は取り消されますが、サーバー自体はアプリケーションから分離していません。
tpsvrdone()または
tpsvrthrdone(3c)で通信を開始した場合は、未処理の応答をすべて取得してから戻る必要がありますが、この処理が行われなかった場合、システムは保留中の応答があっても無視して、サーバーを終了します。
tpsvrdone()または
tpsvrthrdone(3c)内でトランザクションを開始した場合は、すべての応答を取得してから終了する必要がありますが、この処理が行われなかった場合、システムはトランザクションを中断し、応答を無視します。この場合もサーバーは終了します。
中央イベント・ログには、Oracle Tuxedoアプリケーションで発生する重要なイベントが記録されます。これらのイベントに関するメッセージは、アプリケーション・クライアントとサービスが
userlog(3c)関数を介してログに出力されます。
中央イベント・ログの分析は、アプリケーションで行う必要があります。
userlog(3c)に記録するイベントに関しては、厳密なガイドラインを定義しておきます。ほとんど問題にならないようなメッセージを記録しないようにすると、アプリケーションのデバッグが簡単になります。
Windows 2003プラットフォームの中央イベント・ログの設定の詳細は、
WindowsにおけるTuxedo ATMIの使用を参照してください。
アプリケーション管理者は、構成ファイルに、各マシン上の
userlog(3c)エラー・メッセージ・ファイル名の接頭辞として使用する絶対パス名を定義します。
userlog(3c)関数は、月、日、年を表す
mmddyyの形式で日付を生成し、この日付をパス名の接頭辞に付加して中央イベント・ログの完全なファイル名を構成します。毎日、新しいファイルが作成されます。そのため、中央イベント・ログに数日間にわたってメッセージが送信された場合、メッセージはそれぞれ異なるファイルに書き込まれます。
•
|
マシン名。たとえば、UNIXシステムでは、 uname(1)コマンドから返される名前が使用されます。
|
•
|
userlog(3c)を呼び出したスレッドのスレッドID (スレッドがサポートされていないプラットフォーム上では0)、プロセスID、および名前。
|
•
|
userlog(3c)を呼び出したスレッドのコンテキストID。
|
各メッセージの本文の前には、そのメッセージのカタログ名と番号が付きます。
たとえば、
mach1 (
unameコマンドから返される名前)というUNIXマシン上で、セキュリティ・プログラムが午後
4:22:14に次のような呼出しを行ったとします。
userlog("Unknown User ’%s’ \n", usrnm);
162214.mach1!security.23451: Unknown User ’abc’
この例では、securityのプロセスIDは
23451、変数
usrnmの値は
abcです。
前述のメッセージが、アプリケーションではなくOracle Tuxedoシステムによって生成された場合は、次のようになります。
162214.mach1!security.23451: LIBSEC_CAT: 999: Unknown User ’abc’
この例では、メッセージのカタログ名は
LIBSEC_CAT、メッセージ番号は
999です。
プロセスがトランザクション・モードのときにメッセージが中央イベント・ログに送られると、ユーザー・ログ・エントリのタグにはそのほかの要素が付加されます。これらの要素は、リテラル文字列の
gtridと、それに続く3桁のlong型の16進数で構成されます。これらの整数はグローバル・トランザクションをユニークに識別するもので、グローバル・トランザクション識別子、つまり
gtridと呼ばれます。この識別子は主に管理上の目的で使用されます。また、中央イベント・ログでメッセージの前に付加されるタグの中に挿入されます。システムがトランザクション・モードで中央イベント・ログにメッセージを書き込むと、ログ・エントリは次のようになります。
162214.mach1!security.23451: gtrid x2 x24e1b803 x239:
Unknown User ’abc’
イベント・ログにメッセージを書き込むには、次の手順に従います。
•
|
ログに書き込むエラー・メッセージを char *型の変数に割り当て、その変数名を呼出しの引数として使用します。
|
•
|
メッセージのリテラル文字列を二重引用符で囲み、次の例のように userlog(3c)呼出しの引数として指定します。
|
.
.
.
/* Open the database to be accessed by the transactions.*/
if(tpopen() == -1) {
userlog("tpsvrinit: Cannot open database %s, tpstrerror(tperrno)");
return(-1);
}
.
.
.
この例では、
tpopen(3c)が
-1を返した場合、メッセージが中央イベント・ログに送られます。
userlog(3c)のシグネチャは、UNIXシステムの
printf(3S)関数と同じです。どちらの関数の形式でも、リテラル文字列や変換仕様を指定して、可変個引数を使用できます。
userlog(3c)文を使用して、アプリケーション・ソフトウェアをデバッグできます。しかし、問題が複雑な場合は、デバッガ・コマンドを使用することもあります。
以下の項では、UNIXおよびWindows 2003プラットフォーム上でアプリケーションをデバッグする方法について説明します。
UNIXプラットフォーム上でのアプリケーション・プロセスのデバッグ
UNIXシステムの標準デバッグ・コマンドは、
dbx(1)です。このツールの詳細は、UNIXシステムのリファレンス・マニュアルで
dbx(1)を参照してください。
-gオプションを使用してクライアント・プロセスをコンパイルすると、
dbx(1)のリファレンス・ページで説明されている手順に従ってこれらのプロセスをデバッグできます。
dbxコマンドを実行するには、次のように入力します。
クライアント・プロセスを実行するには、次の手順に従います。
3.
|
dbxのプロンプト( *)で、 runサブコマンド( r)と、クライアント・プログラムの main()に渡すオプションを入力します。
|
サーバー・プログラムのデバッグは、これよりも複雑な作業です。通常、サーバーは
tmbootコマンドを使用して起動します。このコマンドは、サーバーを正しいマシン上で正しいオプションを使って起動します。
dbxを使用する場合は、
tmbootコマンドからではなく、サーバーを直接実行する必要があります。サーバーを直接実行するには、
dbxコマンドによって表示されるプロンプトの後に、
r (
runの省略形)を入力します。
Oracle Tuxedoの
tmboot(1)コマンドは、サーバーであらかじめ定義されている
main()に、非公開のコマンド行オプションを渡します。サーバーを直接実行するには、これらのオプションを
rサブコマンドに手動で渡す必要があります。指定する必要のあるオプションを確認するには、
-nと
-d 1オプションを指定して
tmbootを実行します。
-nオプションは、
tmbootが起動処理を行わないことを指定します。
-d 1は、レベル1のデバッグ文を表示することを指定します。デフォルトでは、
-d 1オプションは、すべてのプロセスに関する情報を返します。1つのプロセスに関する情報だけが必要な場合は、必要に応じてオプションを追加してリクエストを指定できます。詳細については、『Oracle Tuxedoコマンド・リファレンス』
を参照してください。
tmboot -n -d 1を実行すると、次の例に示すように、
tmbootからサーバーの
main()に渡されるコマンド行オプションのリストが出力されます。
exec server -g 1 -i 1 -u sfmax -U /tuxdir/appdir/ULOG -m 0 -A
必要なコマンド行オプションを確認したら、
dbx(1)の
rサブコマンドでサーバー・プログラムを直接実行できます。次は、コマンド行の例です。
*r -g 1 -i 1 -u sfmax -U /tuxdir/appdir/ULOG -m 0 -A
構成の一部としてすでに動作中のサーバーを実行する場合は、
dbx(1)は使用しません。使用した場合、サーバーは正常に終了して、サーバーが複製されたことを示すメッセージが中央イベント・ログに書き込まれます。
Windows 2003プラットフォーム上でのアプリケーション・プロセスのデバッグ
Windows 2003プラットフォームには、Microsoft Visual C++環境の一部としてグラフィカル・デバッガが提供されています。このツールの詳細は、Microsoft Visual C++のリファレンス・マニュアルを参照してください。
Microsoft Visual C++のデバッガを起動するには、次のように
startコマンドを入力します。
start msdev -p
process_ID
注意:
|
Microsoft Visual C++ 5.0以前のデバッガを使用する場合は、次のように startコマンドを入力します。
|
start msdev -p process_id
デバッガを起動して自動的にプロセスに入るには、次のようにプロセス名と引数を
startコマンド行に指定します。
start msdev
filename argument
たとえば、デバッガを起動し、引数に
ConvertThisStringを指定して
simpcl.exeプロセスに入るには、次のコマンドを入力します。
start msdev simpcl.exe ConvertThisString
ユーザー・モード例外が発生すると、メッセージが表示されて、デフォルトのシステム・デバッガを起動して、プログラム障害の発生場所、レジストリやスタックの状態を調べるように求められます。Windows 2003環境では、ユーザー・モード例外の障害発生時にはデフォルトのデバッガとして
「ワトソン博士」が使用され、Win32 SDK環境ではカーネル・デバッガが使用されます。
ユーザー・モード例外の障害発生時に使用されるWindows 2003システムのデフォルト・デバッガを変更するには、次の手順に従います。
1.
|
regeditまたは regedt32を実行します。
|
2.
|
HKEY_LOCAL_MACHINEサブツリー内で、 \SOFTWARE\Microsoft\Windows\CurrentVersion\AeDebugに移動します。
|
3.
|
Debuggerキーをダブルクリックして、「文字列の編集」ダイアログ・ボックスを表示します。
|
4.
|
現在表示されている文字列を変更して、使用するデバッガを指定します。
|
たとえば、Microsoft Visual C++環境で提供されるデバッガを指定する場合は、次のコマンドを入力します。
注意:
|
Microsoft Visual C++ 5.0以前のデバッガを使用する場合は、次のようにコマンドを入力します。
|
トランザクションの整合性、メッセージの通信、およびリソースへのアクセスは、オンライン・トランザクション処理(OLTP)アプリケーションの主要な要件です。
ここでは、リソース・マネージャにアクセスするSQL文と共に動作する通信ルーチン、バッファ管理、ATMIトランザクションを示すサンプル・コードを示します。ここで示す例は、Oracle Tuxedo銀行業務アプリケーション(
bankapp)の
ACCTサーバーから抜粋した
CLOSE_ACCTサービスです。
この例は、最初のSQL文でデータベースにアクセスする前に、
set transaction文(49行目)を使用して、トランザクションの整合性レベルとアクセス・モードを設定する方法を示しています。(読取り/書込みの権限が指定されている場合、整合性レベルはデフォルトで高い整合性に設定されます。)
ACCOUNT_IDの値に基づいて口座を解約するために、SQL問合せで引出し額を決定します(50 - 58行目)。
tpalloc()は、
WITHDRAWALサービスへのリクエスト・メッセージ用のバッファを割り当て、
ACCOUNT_IDと引出し額がバッファに格納されます(62 - 74行目)。次に、
tpcall()呼出しを介して
WITHDRAWALサービスにリクエストが送信されます(79行目)。その後、SQLの
delete文で、該当する口座を削除してデータベースを更新します(86行目)。
すべての処理が成功すると、サービス内で割り当てられたバッファが解放され(98行目)、サービスに送信された
TPSVCINFOデータ・バッファが更新されて、トランザクションが正常に終了したことが示されます(99行目)。サービスがイニシエータであった場合、ここでトランザクションが自動的にコミットされます。
tpreturn()は、口座の解約を要求したクライアント・プロセスに、
TPSUCCESSと更新後のバッファを返します。最後に、要求されたサービスが正常に終了したことが、フォームのステータス行に示されます。
各関数呼出しの後、成功したか失敗したかが確認されます。エラーが発生した場合、サービスで割り当てられたバッファが解放され、サービスで開始されたトランザクションが中断され、
TPSVCINFOバッファが更新されてエラーの原因が示されます(80 - 83行目)。最後に、
tpreturn()が
TPFAILを返し、更新されたバッファ内のメッセージがフォームのステータス行に表示されます。
注意:
|
サービス・ルーチンでグローバル・トランザクションの整合性レベルを指定する場合、同じトランザクションに参加するすべてのサービス・ルーチンで、同じようにレベルを定義する必要があります。
|
001 #include <stdio.h> /* UNIX */
002 #include <string.h> /* UNIX */
003 #include <fml.h> /* BEA Tuxedo System */
004 #include <atmi.h> /* BEA Tuxedo System */
005 #include <Usysflds.h> /* BEA Tuxedo System */
006 #include <sqlcode.h> /* BEA Tuxedo System */
007 #include <userlog.h> /* BEA Tuxedo System */
008 #include "bank.h" /* BANKING #defines */
009 #include "bank.flds.h" /* bankdb fields */
010 #include "event.flds.h" /* event fields */
011
012
013 EXEC SQL begin declare section;
014 static long account_id; /* account id */
015 static long branch_id; /* branch id */
016 static float bal, tlr_bal; /* BALANCE */
017 static char acct_type; /* account type*/
018 static char last_name[20], first_name[20]; /* last name, first name */
019 static char mid_init; /* middle initial */
020 static char address[60]; /* address */
021 static char phone[14]; /* telephone */
022 static long last_acct; /* last account branch gave */
023 EXEC SQL end declare section;
024 static FBFR *reqfb; /* fielded buffer for request message */
025 static long reqlen; /* length of request buffer */
026 static char amts[BALSTR]; /* string representation of float */
027 code for OPEN_ACCT service
028 /*
029 * Service to close an account
030 */
031 void
032 #ifdef __STDC__
033 LOSE_ACCT(TPSVCINFO *transb)
034 #else
035 CLOSE_ACCT(transb)
036 TPSVCINFO *transb;
037 #endif
038 {
039 FBFR *transf; /* fielded buffer of decoded message */
040 /* set pointer to TPSVCINFO data buffer */
041 transf = (FBFR *)transb->data;
042 /* must have valid account number */
043 if (((account_id = Fvall(transf, ACCOUNT_ID, 0)) < MINACCT) ||
044 (account_id > MAXACCT)) {
045 (void)Fchg(transf, STATLIN, 0, "Invalid account number", (FLDLEN)0);
046 tpreturn(TPFAIL, 0, transb->data, 0L, 0);
047 }
048 /* Set transaction level */
049 EXEC SQL set transaction read write;
050 /* Retrieve AMOUNT to be deleted */
051 EXEC SQL declare ccur cursor for
052 select BALANCE from ACCOUNT where ACCOUNT_ID = :account_id;
053 EXEC SQL open ccur;
054 EXEC SQL fetch ccur into :bal;
055 if (SQLCODE != SQL_OK) { /* nothing found */
056 (void)Fchg(transf, STATLIN, 0, getstr("account",SQLCODE), (FLDLEN)0);
057 EXEC SQL close ccur;
058 tpreturn(TPFAIL, 0, transb->data, 0L, 0);
059 }
060 /* Do final withdrawal */
061 /* make withdraw request buffer */
062 if ((reqfb = (FBFR *)tpalloc("FML",NULL,transb->len)) == (FBFR *)NULL) {
063 (void)userlog("tpalloc failed in close_acct\n");
064 (void)Fchg(transf, STATLIN, 0,
065 "Unable to allocate request buffer", (FLDLEN)0);
066 tpreturn(TPFAIL, 0, transb->data, 0L, 0);
067 }
068 reqlen = Fsizeof(reqfb);
069 (void)Finit(reqfb,reqlen);
070 /* put ID in request buffer */
071 (void)Fchg(reqfb,ACCOUNT_ID,0,(char *)&account_id, (FLDLEN)0);
072 /* put amount into request buffer */
073 (void)sprintf(amts,"%.2f",bal);
074 (void)Fchg(reqfb,SAMOUNT,0,amts, (FLDLEN)0);
075 /* increase the priority of this withdraw */
076 if (tpsprio(PRIORITY, 0L) == -1)
077 (void)userlog("Unable to increase priority of withdraw");
078 /* tpcall to withdraw service to remove remaining balance */
079 if (tpcall("WITHDRAWAL", (char *)reqfb, 0L, (char **)&reqfb,
080 (long *)&reqlen,TPSIGRSTRT) == -1) {
081 (void)Fchg(transf, STATLIN, 0,"Cannot make withdrawal", (FLDLEN)0);
082 tpfree((char *)reqfb);
083 tpreturn(TPFAIL, 0,transb->data, 0L, 0);
084 }
085 /* Delete account record */
086 EXEC SQL delete from ACCOUNT where current of ccur;
087 if (SQLCODE != SQL_OK) { /* Failure to delete */
088 (void)Fchg(transf, STATLIN, 0,"Cannot close account", (FLDLEN)0);
089 EXEC SQL close ccur;
090 tpfree((char *)reqfb);
091 tpreturn(TPFAIL, 0, transb->data, 0L, 0);
092 }
093 EXEC SQL close ccur;
094 /* prepare buffer for successful return */
095 (void)Fchg(transf, SBALANCE, 0, Fvals(reqfb,SAMOUNT,0), (FLDLEN)0);
096 (void)Fchg(transf, FORMNAM, 0, "CCLOSE", (FLDLEN)0);
097 (void)Fchg(transf, STATLIN, 0, " ", (FLDLEN)0);
098 tpfree((char *)reqfb);
099 tpreturn(TPSUCCESS, 0, transb->data, 0L, 0);
100 }