トリガ呼出と実行のセマンティクス

GT.Mは、そのグローバル変数のデータベース・ファイル内の各グローバル変数のトリガを格納します。グローバル・ディレクトリは、グローバル変数をデータベース・ファイルにマップするときに、そのグローバル変数のトリガも同じデータベース・ファイルにマップします。拡張参照で別のグローバル・ディレクトリを使用してグローバル変数をデータベース・ファイルにマップすると、そのグローバル・ディレクトリのトリガも同じデータベース・ファイルにマップされます。

SETコマンドとKILL / ZKILLコマンドのトリガは一緒に指定できますが、トリガを呼び出すコマンドは常に一意です。ISV $ZTRIGGEROP は、トリガ・コマンドと一致するトリガ・コードを提供します。

コマンドがグローバル変数を更新するたびに、GT.Mランタイム・システムは最初にそのグローバル変数のトリガがあるかどうかを判断します。トリガがある場合、シグネチャをスキャンして添字とノード値を検索し、一致するトリガを識別します。複数のトリガが一致すると、GT.Mはそれらを任意の順序で呼び出します。潜在的なマルチスレッドのGT.Mの将来のバージョンでは、複数のトリガを並列に実行することを選択する可能性があるため、ノードに複数のトリガがある場合は、正しいアプリケーションの動作をそれらは実行します。

プロセスがKILL、ZKILLまたはSETコマンドを実行するとき、ターゲットは変更のためにコマンド引数で指定されたグローバル変数ノードです。 SETとZKILLの場合、ターゲットは単一のノードです。KILLの場合、ターゲットは、ノードのサブツリー全体を表すことができます。GT.Mは、ターゲット・ノードに対するトリガとのみ一致し、各KILLコマンドに対してトリガを1回だけ起動します。GT.Mは、サブツリー内のノードに一致するトリガがあるかどうかをチェックしません。

Kill / ZKill

KILLまたはZKILLがトリガ定義に一致するグローバル・ノードを更新する場合、GT.Mはデータベース状態の変更が計算された後、プロセス空間またはデータベースに適用される 前に、トリガ・コードを実行します。これは、KILLされるノードと子孫(存在する場合)がトリガ・コードで見える状態にあることを意味します。KILLトリガは$ZTVALUEを無視することに注意してください。

Set

SETがトリガ定義に一致するグローバル・ノードを更新すると、GT.Mはノードがプロセスのアドレス空間で更新された 後に、データベースに適用される前にトリガコードを実行します。トリガの実行が完了すると、トリガ・ロジックは、$ZTVALUEが設定されていない場合にのみ、ノードの値をプロセス・アドレス空間からコミットします。トリガーの実行中に$ZTVALUEが設定されている場合、トリガー・ロジックはノードの値を$ZTVALUEの値からコミットします。

次の例を考えてみます:

GTM>set c=$ztrigger("S")
;trigger name: A#1#  cycle: 1
+^A -commands=S -xecute="set ^B=200"
;trigger name: B#1#  cycle: 1
+^B -commands=S -xecute="set $ztval=$ztval+1 " 
GTM>set ^A=100,^B=100 
GTM>write ^A
100
GTM>write ^B
201 

SET ^A=100 は、トリガ A#1 を呼び出す。トリガの実行が開始されると、GT.Mはプロセス・アドレス空間に ^A を100に設定しますが、データベースには適用しません。したがって、トリガ・ロジックは ^A が100に設定されているとみなします。ただし、データベースにアクセスする他のプロセスは、^A の以前の値を参照してください。トリガの実行が完了すると、トリガ・ロジックは、$ZTVALUEが設定されていない場合にのみ、ノードの値をプロセス・アドレス空間からコミットします。トリガ・ロジックは、トリガの実行中に$ZTVALUEが設定されている場合のみ、ノードの値を$ZTVALUEからコミットします。$ZTVALUEは、A#1 に設定されていないため、GT.Mはプロセス・アドレス空間から ^A の値をデータベースにコミットします。したがって、GT.Mは、^A=100 をデータベースにコミットします。 SET ^B=200 はトリガー B#2 を呼び出します。$ZTVALUE はトリガの実行中に設定されるため、GT.Mはトリガの実行終了時に $ZTVALUE の値を ^B にコミットします。

[注意] 注意

トリガ・コード内で、^B 上の任意のSET操作は、再帰的にトリガ B#1 を呼び出します。したがって、$ZTVALUEを設定すると、トリガの実行中に値ノードが変更されます。GT.Mは、オリジナルのコマンドがトランザクション内にあるかどうかにかかわらず、同じトランザクション内のトリガ更新と関連するすべてのトリガを実行します。つまり、トリガ・ロジックはノードの更新された値を認識しますが、最も外側のトランザクションがデータベースにコミットするまで他のプロセスには表示されません。他のプロセスが競合する更新がある場合、GT.Mは明示的または暗黙のトランザクションをRESTARTして競合を解決します。

トリガは、SETがトリガを開始したノードを更新する必要があります。これが発生する可能性のある状況は次のとおりです:

  • ログまたはジャーナル・エントリは、更新と同じノードの別の部分に格納する必要がある場合があります、または、

  • 更新されているノードは、そのデータを標準形式で格納する必要があります(実際にどのように入力されたかにかかわらず、全部大文字や標準化された句読点など)、または、 ある範囲の限定されたその値を持ちます。

そのような場合、トリガ・ロジックはグローバル・ノードの代わりに ISV $ZTVALUEに変更を加える必要があります。トリガ呼び出しの最後に、GT.Mは$ZTVALUEの値をノードに適用します。最初の照合トリガーが実行される前に、GT.Mは$ ZTVALUEを設定します。あるトリガのロジック内のコマンドは別のネストされたトリガを呼び出すことができるので、既にトリガ内にある場合、GT.Mはネストされたトリガの開始のために変更する前に、以前のアップデートに対して $ZTVALUEの値をスタックします。

GT.Mは、MERGEコマンドをデータ・ソースの照合順序で実行される一連のSETコマンドとして扱います。GT.Mは、一致するトリガのためにMERGEによって更新された各グローバル・ノードをチェックします。GT.Mが1つ以上の一致を検出した場合、次のコマンドの前に一致するすべてのトリガを呼び出すか、同じSETコマンドの次のセット引数を呼び出します。

GT.Mは $INCREMENT() 関数をSETコマンドとして扱います。$INCREMENT() 操作の結果は数値でなければならないため、トリガ・コードが$ZTVALUEを変更すると、トリガの最後に、GT.Mは +$ZTVALUEの値(つまり、$ZTVALUEが強制的に数値に変換されます)をターゲットノードに適用します。

トリガの実行環境

上記のように、一致する複数のトリガがある場合、GT.Mプロセスは一致するトリガのリストを作成し、予測可能性を保証せずに任意の順序でそれらを実行します。

一致するトリガーごとに:

  1. GT.Mプロセスは、ネイキッド参照、$REFERENCE、$TEST、$ZTOLDVAL、$ZTDATA、$ZTRIGGEROP、$ZTUPDATE、NEW されるすべてのローカル変数を暗黙的にスタックします。トリガ・コードの実行開始時に、$REFERENCE、$TEST、ネイキッド・インジケータは、最初に積み重ねる前の値を保持します(KILL / ZKILLの場合、KILL / ZKILLコマンドの参照にノードが削除される前にトリガーが実行されます)。更新が複数の(チェインした)トリガを直接開始する場合は、すべてがネイキッド参照、$REFERENCE、$TEST、$ZTDATA、$ZTLEVEL、$ZTOLDVAL、$ZTRIGGEROPと同じ値で始まります。これにより、トリガが実行される順序とは独立したトリガが容易になります。トリガ内のアプリケーション・ロジックは、$REFERENCE、読み込み専用の固有の特殊変数 $ZTDATA、$ZTLEVEL、$ZTOLDVAL、$ZTRIGGEROP、$ZTUPDATE、および読み書き可能な固有の特殊変数 $ZTVALUE、$ZTWORMHOLE を使用できます。

  2. GT.Mはトリガ・コードを実行します。このGT.Mトリガの実行中に、同じトリガが同じターゲットまたは別のターゲットに対して再度一致すると、GT.Mはトリガを再帰的に再呼び出しします。つまり、同じコマンドに対して同じトリガを複数回呼び出すことができます。このような再帰呼び出しはおそらく最終的にSTACKCRITエラーを引き起こす異常な状態であることに注意してください。トリガは最大127レベルまでネストすることができます。その後、ネストを試行するとMAXTRGRNESTエラーが発生します。

  3. コードが完了すると、GT.Mはローカル変数をクリアし、$ZTVALUEを除くスタックされたものをトリガの開始時の値に復元し、オリジナルの更新と一致するトリガが残っている場合は、$ZTUPDATEを調整し、その次のアクションを実行します($ZTVALUEの変更に関するコメントについては、ISVの定義を参照してください)。$ZTVALUEは、アプリケーションの更新が最初にトリガを呼び出したノードの現在のターゲット値を常に保持します。同じノードの複数のトリガは任意の順序で実行されるため、複数のトリガを変更すると、$ZTVALUEを注意深く設計して実装する必要があります。

すべてのトリガを実行した後、GT.Mは、トリガを開始する操作とトリガの更新をコミットし、次のコマンドで実行を続行します (または、複数のノードが同じコマンドによって更新されている場合は、次のノードで更新されます)。トリガを開始する操作自体がトランザクション内にある場合、他のプロセスは、最も外側のトランザクションのTCOMMITまでデータベース状態の変化を認識しません。

トリガ・アクションがAtomicであることを保証するために、GT.Mはトランザクション内でトリガ・ロジックとトリガ・アップデートを常に実行します。トリガ・アップデートがアプリケーション・トランザクション内にない場合、GT.Mは再起動可能な「Batch」トランザクションを暗黙的に開始し、オリジナルのアップデートとアップデートによって生成されたトリガをラップします。In other words, when 0=$TLEVEL GT.M behaves as if implicit TStart *:Transactionid="BATCH" and TCommit commands bracket the upddate and its triggers. 言い換えれば、0=$TLEVELならは、GT.Mは暗黙的な TStart *:Transactionid="BATCH" のように振る舞いまい、そして、TCommitコマンドは更新とそのトリガを囲みます。したがって、トリガコードおよび/またはそのエラー・トラップは常にトランザクション内で動作し、メイン・アプリケーション・コードがTSTARTを使用しない場合でもTRESTARTコマンドを使用できます。トリガで使用する$ETRAPコードには、TROLLBACKロジックが含まれている場合があります。

廃止予定のZTSTART / ZTCOMMITトランザクションは、トリガと互換性がありません。トリガが定義されているグローバルへの更新が発生したときにZTSTARTトランザクションがすでにアクティブである場合、GT.Mは実行時エラーを発行します。同様に、GT.Mは、トリガ・コンテキスト内でエラーとしてZTSTARTを発行しようとするすべてを扱います。

トリガ実行中のエラー処理

GT.Mは$ETRAPメカニズムを使用して、トリガの実行中にエラーを処理します。トリガ中にエラーが発生した場合、GT.Mは$ETRAPでMコードを実行します。$ETRAPが$ECODEをクリアしない場合、GT.Mはトリガ内でデータベース更新をコミットせず、制御をトリガ更新の環境に渡します。$ETRAPアクションまたはそれが起動するロジックが$ECODEをクリアすると、GT.Mは引き続きトリガ・ロジックの処理を続行できます。

以下の簡単な例を考えてみましょう:

^Acct(id=:,disc=:) -commands=Set -xecute="Set msg=""Trigger Failed"",$ETrap=""If $Increment(^count) Write msg,!"" Set $ZTVAlue=x/disc" 

トリガ実行中に、disc (トリガ更新の2番目の添字)が 0 と評価され、DIVZERO( 0で除算しようとする)エラーが発生すると、GT.Mは "Trigger Failed"というメッセージを表示します。$ETRAPは$ECODEをクリアしないので、メッセージを出力した後、GT.Mはトリガコンテキストを終了し、トリガの外にエラー・ハンドラを呼び出します。DIVZEROの場合、プロセスは ^Acct(id,disc) に新しい値を割り当てたり、増分した ^count の値をデータベースにコミットしたりしません。

アプリケーション・プロセスは、トリガ内の実行時エラーを処理するために、広範囲の訂正アクションを使用できます。ただし、これらの修正アクションは、MUPIPレプリケーション中に使用できない場合があります。「トリガー環境」セクションで説明したように、GT.Mは、トリガ定義だけを複製しますが、トリガされた更新は複製しません。トリガ更新は、複製インスタンスが複製を再生するときにトリガによって実行されます。トリガが複製インスタンスで呼び出された場合、トリガがオリジナルのインスタンスで正常に呼び出されたことを意味します。通常のアプリケーション要件では、正しく構成された複製インスタンスで同じ結果が生成されることを確認する必要があります。したがって、MUPIP上の$ETRAPコードは、次の場合に対処する必要があります:

  1. 実行時の$ETRAPコードは、トリガ・ロジックを変更して、望ましい結果を達成しました

  2. 複製構成は、開始構成とは異なります

  3. 開始インスタンスと複製インスタンス間のフィルタによってエラーが発生します

後の2つのケースでは、ミスマッチ環境には基本的に2つの可能性があります:

  1. 意図されたものと$ETRAPメカニズムは、違いを管理するための不可欠な部分です

  2. 意図せず、$ETRAPメカニズムは、相違を修正してレプリケーションを再開するように運営チームに通知するのに役立ちます

トリガ機能には、gtm_trigger_etrap という環境変数が含まれています。これは、トリガ・コンテキストで$ETRAPの初期値を提供し、mumpsとMUPIPプロセスの両方でトリガ操作のエラー・トラップを設定するために使用できます。もちろん、コードはトリガ・コンテキスト内でSET $ETRAPでもかまいません。実行時トリガ操作中に gtm_trigger_etrapの値を指定せずにトリガが失敗した場合、GT.Mは現在のトラップ・ハンドラを使用します。MUMPSプロセスでは、トリガの更新時にトラップハンドラが $ZTRAP で、gtm_trigger_etrap が定義されていない場合、エラー・トラップは暗黙的に $ETRAP="" に置き換えられ、$ZTRAPがアンスタックして有効になる前に、トリガ・ロジックとトリガ・アクションの両方から抜け出します。MUPIPプロセスで、gtm_trigger_etrapの値を指定せずにトリガが失敗した場合、GT.Mは暗黙的に SET $ETRAP="If $ZJOBEXAM()" を実行し、MUPIPプロセスを終了します。$ZOBEXAM() は、障害の分析の基礎となるファイルに診断情報(ZSHOW "*"に相当)を記録します。

[重要] 重要

$ZJOBEXAM() は、関数の実行時にプロセスのコンテキストをダンプします。出力には、識別番号、クレジットカード番号などの機密情報が含まれている可能性があります。MUPIPエラーハンドラによって生成されるファイルの場所を確保するか、MUPIPを操作するための適切なセキュリティ特性を設定する必要があります。あるいは、MUPIPが$ZJOBEXAM()ファイルを作成しないようにするには、gtm_trigger_etrap環境変数を明示的に "Write !,$ZSTATUS,!,$ZPOSITION,! Halt" のようなハンドラに設定します。

トリガ実行中のエラー処理のその他の重要な側面は次のとおりです:

  1. トリガに$ZTRAPエラー処理メカニズムを使用しようとすると、NOZTRAPINTRIGRエラーが発生します。

  2. トリガを起動する任意のトランザクション($TLEVEL=0)の外で発生した場合、GT.Mはトランザクションを暗黙的に開始して開始更新とトリガ更新をラップします。その結果、トリガ/コンテキスト内のTROLLBACKまたはTCOMMITが、トリガが開始されたときとは別の$TLEVELで起動中の更新を完了するようにコードを戻した場合(暗黙のTSTARTを含む)、GT.MはTRIGTCOMMITエラーを発行し、オリジナルの更新をコミットしません。

  3. トリガの開始時に$TLEVELを下回ったTCOMMITは、TRIGTLVLCHNGエラーを引き起こします。この動作は、チェイン、ネスト、単数のいずれのトリガにも適用されます。

  4. GT.MはXECUTEの引数としてトリガ・コードを実行するように見えるかもしれません。しかし、パフォーマンス上の理由から、GT.Mは内部的にトリガ・コードを疑似ルーチンに変換し、それがルーチンであるかのように実行します。これはほとんど不可能ですが、トリガ名はエラー・メッセージや $STACK() の戻り値などの場所に現れることがあります。

  5. トリガは領域に関連付けられており、プロセスは1つ以上のグローバル・ディレクトリーを使用して複数の領域にアクセスすることができるため、トリガに名前の競合が発生する可能性があります。GT.Mは、潜在的にある他のリソースとの名前の競合を避けるために、ユーザーが指定したトリガ名または自動的に生成されたトリガ名に "#" 文字で区切られた2文字のサフィックスを追加しようとします。一意の名前するこの試みに失敗すると、GT.MはTRIGNAMEUNIQエラーを発行します。

  6. 任意の複雑さのMコードを保持する gtm_trigger_etrapを定義すると、Mコードとシェル・スクリプトの引用規則の不一致が明らかになります。FISでは、値全体を一重引用符で囲み、一重引用符( ')、感嘆符(!)、およびバックスラッシュ(\)文字のみをエスケープするアプローチを提案しています。包括的な(しかし、うまくいえば現実的ではない)例については:

    $ export gtm_trigger_etrap='write:1\'=2 $zstatus,\!,"5\\2=",5\\2,\! halt'
    $ echo $gtm_trigger_etrap
    write:1'=2 $zstatus,!,"5\2=",5\2,! halt 
    GTM>set $etrap=$ztrnlnm("gtm_trigger_etrap")
    GTM>xecute "write 1/0"
    150373210,+1^GTM$DMOD,%GTM-E-DIVZERO, Attempt to divide by zero
    5\2=2
    $

ZGoto

トリガのトランザクションの整合性を維持し、不適切なディストネーションへの分岐制御を回避するため、ZGOTOは次のように動作します:

  1. GT.Mは、MUPIPコンテキストの置き換えを試みるため、MUPIPの ZGOTO 1:<entryref> 引数をサポートしていません。

  2. ZGOTOの引数がトリガを開始した更新のレベル以下の入口参照(entryref)を指定すると、GT.Mはトリガ更新を実行せずに制御の流れを入口参照(entryref)にリダイレクトします。あるいは、GT.Mが非nullの$ECODEを検出し、トリガを完了するために処理されなかったエラーを示す場合、オリジナルのトリガ更新をコミットするのではなく、現在のエラーハンドラに制御を渡します。

  3. ZGOTO 0 はプロセスを終了し、ZGOTO 1 は トリガ呼び出しの外になければならない基本スタックフレームに戻ります。

  4. 実行時トリガ・コンテキスト内のZGOTOは、トリガを起動したコマンドを含む行の次のMコマンドに直接は到達することはできません、なぜなら、更新が始まるが入口参照(entryref)がないレベルを指定する引数を持つZGOTOが(それがQUITと同じように)更新自体に戻るので、$ECODEがnullの場合、GT.Mは行を再開する前に、追加のトリガとトリガ更新を処理し続けます。

トリガを実行するソースコードへのアクセス

ZPRINT / $TEXT() / ZBREAKは、ハッシュ記号(#)で区切られたランタイムの曖昧さ解消と、スラッシュ(/)で区切られた領域の曖昧さ解消の両方を認識します。ZPRINTとZBREAKはトリガが見つからない(trigger-not-found)場合をTRIGNAMENFエラーとして扱い、$TEXT() は空の文字列を返します。それらの引数に領域の曖昧さ解消が含まれている場合、これらの機能はnullのランタイムと曖昧さ解消を無視します。それらの引数に領域の曖昧さ解消が含まれていない場合、これらの機能は空の値を持っていてもランタイムの曖昧さ解消が指定されているかのように動作します。引数がランタイムの曖昧さ解消と領域の曖昧さ解消の両方を指定し、ランタイムの曖昧さ解消が指定された領域と異なる領域からロードされたトリガを指定した場合、または、領域の曖昧さ解消が $ZGBLDIRによってマップされていないトリガを保持する領域を識別する場合、これらの機能はトリガを見つけられないものとして扱います。

GT.CM

GT.CM サーバはトリガを起動しません。つまり、クライアント・プロセスは、トリガを必要としない更新に自分自身を制限しなければならず、そうでなければトリガが実行するアクションを明示的に呼び出さなければなりません。GT.CMは、トリガをバイパスするため、トリガ・ロジックのバグによって不整合な状態に置かれたデータを修復するためのデバッグや複雑な修正のためにトリガをバイパスするメカニズムを提供する可能性があります。

その他のユーティリティ

MUPIP INTEG、REORG、BACKUP(-BYTESTREAMを含む)中に、GT.Mは、ちょうど通常のグローバル・ノードを扱うように、トリガ定義を扱います。

Because they are designed as state capture and [re]establishment facilities, MUPIP EXTRACT does not extract trigger definitions and MUPIP LOAD MUPIP EXTRACTは状態キャプチャおよび再構築機能として設計されているため、MUPIP EXTRACTはトリガー定義を 抽出しません 、そしてMUPIP LOADはトリガ定義を復元したり、トリガを起動したりしません。トリガをバイパスするMUPIP LOADの入力を構築することはできますが、GT.CM 構成を使用する場合を除いて、Mコード自体が既存のトリガをバイパスする方法はありません。$ZTRIGGER() 関数は、Mコードが、トリガを削除することを含めてトリガを調整することを許可しますが、これらのアクションはすべてのトリガに関連するノードを更新するすべてのプロセスに影響します。MUPIP EXTRACTとLOADのように、^%GIと^%GO Mユーティリティー・プログラムはGT.Mトリガ定義を抽出してロードしません。MUPIP LOADとは異なり、^%GIは他のMコードと同様にトリガを起動します。これにより、期待されたものや意図されたもの以外の結果が得られる可能性があります。

inserted by FC2 system