コールアウト・ライブラリ関数の呼び出し
コールアウト・ライブラリは、$ZF コールアウト・インタフェースへのフックを含む共有ライブラリ (DLL または SO ファイル) であり、多様な $ZF 関数が実行時にロードして、その関数を呼び出すことができるようにします。$ZF コールアウト・インタフェースは、実行時にコールアウト・ライブラリをロードし、そのライブラリから関数を呼び出すために使用できる 4 つの異なるインタフェースを提供します。各インタフェースは、主に、ライブラリの識別方法とメモリへのロード方法が異なります。
-
"$ZF() を使用した iriszf コールアウト・ライブラリへのアクセス" では、iriszf という特別な共有ライブラリの使用方法について説明します。このライブラリが利用可能な場合、事前にライブラリをロードしたり、ライブラリ名を指定したりしなくても、$ZF("funcname",args) という形式の呼び出しによってその関数にアクセスできます。
-
"$ZF(-3) を使用した単純なライブラリ関数呼び出し" では、ライブラリをロードし、ライブラリ・ファイル・パスと関数名を指定することによって関数を呼び出す方法について説明します。使用は簡単ですが、仮想メモリ内で使用できるのは一度に 1 つのライブラリのみです。その他のインタフェースとは異なり、ライブラリ関数を呼び出す前に初期化を行う必要がありません。
-
"$ZF(-5) を使用したシステム ID によるライブラリへのアクセス" では、一度に複数のライブラリを効率的に維持し、アクセスするために使用できるインタフェースについて説明します。同時に複数のライブラリをロードでき、それぞれに必要な処理オーバーヘッドは、$ZF(-3) よりはるかに小さくて済みます。メモリ内のライブラリは、ライブラリのロード時に生成されるシステム定義 ID によって識別されます。
-
"ユーザ・インデックスによるライブラリへのアクセスでの $ZF(-6) の使用" では、コールアウト・ライブラリの大規模なセットを処理するための最も効率的なインタフェースについて説明します。このインタフェースは、グローバルに定義されたインデックス・テーブルを介してライブラリへのアクセスを可能にします。インデックスは、InterSystems IRIS のインスタンス内のすべてのプロセスで利用でき、同時に複数のライブラリをメモリに配置できます。インデックス付きの各ライブラリには一意のユーザ定義インデックス番号が指定され、インデックス・テーブルは実行時に定義および変更できます。指定されたライブラリ ID と関連付けられているファイル名は、ライブラリ・ファイルの名前が変更されるとき、または再配置されるときに変更できます。この変更は、インデックス番号でライブラリをロードするアプリケーションに対して透過的です。
$ZF() を使用した iriszf コールアウト・ライブラリへのアクセス
iriszf という名前のコールアウト・ライブラリがインスタンスの <install_dir>/bin ディレクトリにある場合、関数名と引数のみを指定した $ZF 呼び出しによってその関数を呼び出すことができます (例 : $ZF("functionName",arg1, arg2))。iriszf 関数は、事前にライブラリをロードしなくても呼び出すことができます。また、インスタンス内のすべてのプロセスで利用できます。
カスタムの iriszf ライブラリを定義するには、標準のコールアウト・ライブラリを作成して、それをインスタンスの <install_dir>/bin ディレクトリに移動し、名前を iriszf に変更します (具体的にはプラットフォームに応じて iriszf.dll または iriszf.so)。
以下に、simplecallout.c の例 (“InterSystems コールアウト・ライブラリの作成” を参照) をコンパイルし、それを iriszf ライブラリとして設定する手順を示します。これらの例では、インスタンスが Linux で実行されていて、/intersystems/iris という名前のディレクトリにインストールされていることを想定していますが、手順は基本的にすべてのプラットフォームで同じです。
-
simplecallout.c を作成して保存します。
#define ZF_DLL #include "iris-cdzf.h" int AddTwoIntegers(int a, int b, int *outsum) { *outsum = a+b; /* set value to be returned by $ZF function call */ return IRIS_SUCCESS; /* set the exit status code */ } ZFBEGIN ZFENTRY("AddInt","iiP",AddTwoIntegers) ZFEND
-
コールアウト・ライブラリ・ファイル (simplecallout.so) を生成します。
gcc -c -fPIC simplecallout.c -I /intersystems/iris/dev/iris-callin/include/ -o simplecallout.o gcc simplecallout.o -shared -o simplecallout.so
-
InterSystems IRIS ターミナル・セッションから $ZF(-3) を使用してライブラリをテストします。
USER>write $ZF(-3,"/mytest/simplecallout.so","AddInt",1,4) 5
-
次に、$ZF() で使用するライブラリをインストールします。simplecallout.so を <install_dir>/bin にコピーし、名前を iriszf.so に変更します。
cp simplecallout.so /intersystems/iris/bin/iriszf.so
-
InterSystems IRIS セッションから $ZF() を使用してコードを呼び出せることを確認します。
USER>write $zf("AddInt",1,4) 5
iriszf ライブラリは最初の使用時に 1 回ロードされ、アンロードされることはありません。この処理は、この章で前述した他の $ZF のロードおよびアンロード操作とはまったく無関係です。
以前のバージョンの $ZF コールアウト・インタフェースでは、コードをインターシステムズのカーネルに静的にリンクし、$ZF() を使用して呼び出すことができました。静的リンクはサポートされなくなりましたが、iriszf ライブラリで同じ機能が提供されており、カーネルに再リンクする必要はありません。
単純なライブラリ関数呼び出しでの $ZF(-3) の使用
$ZF(-3) 関数は、コールアウト・ライブラリをロードして、そのライブラリから指定した関数を実行するために使用されます。$ZF(-3) は、1 つのライブラリのみを使用している場合、またはライブラリのロードのオーバーヘッドを懸念して十分な呼び出しを行っていない場合に、もっとも役立ちます。これにより、ライブラリ名、関数名、および関数引数のコンマ区切りのリストを指定することによって、任意の利用可能なライブラリ関数を呼び出すことができます。
result = $ZF(-3, library_name[, function_name[, arguments]])
指定されたライブラリは、$ZF(-3) への前の呼び出しによってロードされていない場合にロードされます。一度にロードできるのは 1 つのライブラリのみです。後続の $ZF(-3) 呼び出しが、別のライブラリを指定すると、古いライブラリはアンロードされ、新しいライブラリが置き換わります。このライブラリは、後続の $ZF(-3) 呼び出しが同じライブラリを指定する限りロードされたままになります。ライブラリがロードされた後に、後続の呼び出しで、ライブラリ名を NULL 文字列 ("") として指定できます。
関数を呼び出すことなくライブラリをロードまたはアンロードすることができます。新しいライブラリをロードするには、ライブラリ名のみを指定します。新しいライブラリをロードせずに現在のライブラリをアンロードするには、NULL 文字列のみを指定します。いずれのケースでも、$ZF(-3) は、ロードまたはアンロードが成功したかどうかを示すステータス・コードを返します。
以下の ObjectScript コードは、2 つの異なるライブラリそれぞれから 2 つの異なる関数を呼び出し、現在のライブラリをアンロードします。
// define Callout library paths
set libOne = "c:\intersystems\iris\bin\myfirstlibrary.dll"
set libTwo = "c:\intersystems\iris\bin\anotherlibrary.dll"
//load and call
SET result1=$ZF(-3,libOne,"FuncA",123) // loads libOne and calls FuncA
SET result2=$ZF(-3,"","FuncB","xyz") // calls FuncB from same library
//load, then call with null name
SET status=$ZF(-3,libTwo) // unloads libOne, loads libTwo
SET result1=$ZF(-3,"","FunctionOne","arg1")
SET result2=$ZF(-3,"","FunctionTwo","argA", "argB")
//unload
SET status=$ZF(-3,"") // unloads libTwo
-
簡便性のため、ライブラリ名は文字列 libOne および libTwo に割り当てられます。
-
$ZF(-3) への最初の呼び出しは、コールアウト・ライブラリ libOne をロードし、そのライブラリから関数 FuncA を呼び出します。
-
2 番目の呼び出しは、ライブラリ名に NULL 文字列を指定して、現在ロードされている libOne を再び使用することを示し、そのライブラリから関数 FuncB を呼び出します。
-
$ZF(-3) への 3 番目の呼び出しは、ライブラリ名 libTwo のみを指定します。これにより、libOne がアンロードされ、libTwo がロードされますが、ライブラリ関数は呼び出されません。この呼び出しは libTwo が正常にロードされたかどうかを示すステータス・コードを返します。
-
4 番目と 5 番目の呼び出しは、ライブラリ関数 FunctionOne および FunctionTwo を現在ロードされている libTwo から呼び出します。
-
最後の $ZF(-3) 呼び出しは、ライブラリ関数を呼び出さず、ライブラリ名に NULL 文字列を指定します。これにより、libTwo がアンロードされ、新しいライブラリはロードされません。この呼び出しは libTwo が正常にアンロードされたかどうかを示すステータス・コードを返します。
この章の以下のセクションでは、一度に複数のライブラリをロードできる $ZF 関数について説明します。これらの関数は $ZF(-3) と競合しません。$ZF(-3) は、いつでもそれ自体のライブラリのプライベート・コピーをロードおよびアンロードしているかのように使用することができます。
システム ID によるライブラリへのアクセスでの $ZF(-5) の使用
$ZF(-5) 関数は、ライブラリ関数の呼び出しにシステム定義のライブラリおよび関数の識別子を使用します。多くのライブラリ関数呼び出しを行うアプリケーションでは、これにより処理のオーバーヘッドが大幅に削減できます。複数のライブラリを同時に開くことができます。各ライブラリは、一度のみロードが必要であり、各ライブラリまたは関数識別子は一度のみ生成する必要があります。ユーティリティ関数 $ZF(-4,1)、$ZF(-4,2)、および $ZF(-4,3) は、必要な識別子を取得し、ライブラリをロードまたはアンロードするために使用されます。
-
$ZF(-5) — システム定義のライブラリおよび関数の識別子によって参照される関数を呼び出します。
-
$ZF(-4,1) — ライブラリをロードします。ライブラリ・ファイル名を取得し、ロードされたライブラリのシステム定義ライブラリ ID 値を返します。
-
$ZF(-4,2) — ライブラリ ID によって指定されるコールアウト・ライブラリをアンロードします。
-
$ZF(-4,3) — 指定されたライブラリ ID および関数名の関数 ID 値を返します。
$ZF(-4,1) および $ZF(-4,3) 関数は、コールアウト・ライブラリのロードとライブラリおよび関数識別子の取得に使用されます。$ZF(-4,1) の構文は以下のとおりです。
lib_id = $ZF(-4,1,lib_name) // get library ID
ここで lib_name は、共有ライブラリ・ファイルのフルネームとパスであり、lib_id は、返されるライブラリ ID です。$ZF(-4,3) の構文は以下のとおりです。
func_id=$ZF(-4,3,lib_id, func_name) // get function ID
ここで lib_id は、ライブラリ ID、func_name は、ライブラリ関数名、func_id は、返される関数 ID 値です。
以下の ObjectScript コードはコールアウト・ライブラリ mylibrary.dll をロードしてライブラリ ID を取得し、"MyFunction" の関数 ID を取得して $ZF(-5) を使用して呼び出します。
set libID = $ZF(-4,1,"C:\calloutlibs\mylibrary.dll")
set funcID = $ZF(-4,3,libID, "MyFunction")
set x = $ZF(-5,libID, funcID, "arg1")
識別子が定義されると、ライブラリは $ZF(-4,2) によってアンロードされるまでロードされたままになり、その識別子は $ZF(-4,1) または $ZF(-4,3) へのさらなる呼び出しを行うことなく使用することができます。これにより、複数のライブラリからの関数が何度も呼び出される際の処理オーバーヘッドが大幅に削減されます。
以下の ObjectScript コードは 2 つの異なるライブラリをロードし、ロング・ループで両方のライブラリから関数を呼び出します。inputlibrary.dll 内の関数はデータを取得し、outputlibrary.dll 内の関数はデータをプロットおよび保存します。
Method GraphSomeData(loopsize As %Integer=100000) As %Status
{
// load libraries and get system-defined ID values
set InputLibID = $ZF(-4,1,"c:\intersystems\iris\bin\inputlibrary.dll")
set OutputLibID = $ZF(-4,1,"c:\intersystems\iris\bin\outputlibrary.dll")
set fnGetData = $ZF(-4,3,InputLibID,"GetData")
set fnAnalyzeData = $ZF(-4,3,OutputLibID,"AnalyzeData")
set fnPlotPoint = $ZF(-4,3,OutputLibID,"PlotPoint")
set fnWriteData = $ZF(-4,3,OutputLibID,"WriteData")
// call functions from each library until we have 100000 good data items
set count = 0
do {
set datapoint = $ZF(-5,InputLibID,fnGetData)
set normalized = $ZF(-5,OutputLibID,fnAnalyzeData,datapoint)
if (normalized'="") { set flatdata($INCREMENT(count)) = normalized }
} while (count<loopsize)
set status = $ZF(-4,2,InputLibID) //unload "inputlibrary.dll"
// plot results of the previous loop and write to output
for point=1:1:count {
set list = $ZF(-5,OutputLibID,fnPlotPoint,flatdata(point))
set x = $PIECE(list,",",1)
set y = $PIECE(list,",",2)
set sc = $ZF(-5,OutputLibID,fnWriteData,flatdata(point),x,y,"outputfile.dat")
}
set status = $ZF(-4,2,OutputLibID) //unload "outputlibrary.dll"
quit 0
}
-
$ZF(-4,1) への呼び出しでは、コールアウト・ライブラリ inputlibrary.dll および outputlibrary.dll を仮想メモリ内にロードし、それらのシステム定義のライブラリ ID を返します。
-
$ZF(-4,3) への呼び出しでは、ライブラリ ID および関数名を使用してライブラリ関数の ID を取得します。返された関数 ID は実際は ZFEntry テーブル・シーケンス番号 (前の章の “ZFEntry テーブルの作成” を参照) です。
-
最初のループでは、$ZF(-5) を使用して各ライブラリから関数を呼び出します。
-
inputlibrary.dll からの GetData() 関数は、未指定のソースから生のデータを読み取ります。
-
outputlibrary.dll からの AnalyzeData() 関数は、生のデータを正規化するかまたは拒否して、空の文字列を返します。
-
正規化された各 datapoint は、flatdata(count) (ここで ObjectScript 関数 $INCREMENT への最初の呼び出しが count を作成し、1 に初期化する) に保存されます。
既定では、ループは 100000 の項目をフェッチします。両方のライブラリがロードされメモリ内に残っているため、2 つの異なるライブラリ間を切り替えるための処理オーバーヘッドはありません。
-
-
最初のループが終了した後に、ライブラリ inputlibrary.dll は必要なくなるため、$ZF(-4,2) が呼び出されてアンロードされます。ライブラリ outputlibrary.dll は、メモリ内に残ります。
-
2 番目のループは、配列 flatdata からの各項目を処理し、未指定の場所にあるファイルに書き込みます。
-
2 番目のループが終了した後に、$ZF(-4,2) が再び呼び出されてライブラリ outputlibrary.dll がアンロードされます。
以下のセクションでは、$ZF(-6) インタフェースについて説明します。これは、$ZF(-5) インタフェースと同じ仮想メモリ領域内にライブラリをロードします。
ユーザ・インデックスによるライブラリへのアクセスでの $ZF(-6) の使用
$ZF(-6) 関数は、グローバルに定義されたインデックスを介してコールアウト・ライブラリへのアクセスを可能にする、共有ライブラリ・ファイルの場所を認識していないアプリケーションでも使用可能な効率的なインタフェースを提供します。ユーザ定義のインデックス・テーブルは、ライブラリ ID 番号と対応するライブラリ・ファイル名で構成されるキーと値のペアを格納します。指定されたライブラリ ID と関連付けられているファイル名は、ライブラリ・ファイルの名前が変更されたときまたは再配置されたときに変更できます。この変更は、インデックス番号でライブラリをロードするアプリケーションに対して透過的です。その他の $ZF 関数は、インデックス・テーブルを作成して維持するため、および $ZF(-6) によってロードされたライブラリをアンロードするために提供されています。
このセクションでは、以下の $ZF 関数について説明しています。
-
$ZF(-6) — ユーザ指定のインデックス番号によって参照されるコールアウト・ライブラリから関数を呼び出します。ライブラリがまだロードされていない場合には、自動的にロードします。
-
$ZF(-4,4) — インデックス番号によって指定されるコールアウト・ライブラリをアンロードします。
-
$ZF(-4,5) および $ZF(-4,6) — システム・インデックス・テーブル内でエントリを作成または削除します。システム・インデックスは、InterSystems IRIS のインスタンス内のすべてのプロセスでグローバルに利用可能になります。
-
$ZF(-4,7) および $ZF(-4,8) — プロセス・インデックス・テーブル内でエントリを作成または削除します。プロセス・テーブルは、システム・テーブルの前に検索されるため、プロセス内でシステム全体の定義をオーバーライドするために使用します。
$ZF(-6) インタフェースは、$ZF(-5) (“システム ID によるライブラリへのアクセスでの $ZF(-5) の使用” を参照) によって使用されるものと類似していますが、以下の点が異なります。
-
$ZF(-6) を使用するには、先にライブラリ・インデックス・テーブルを作成する必要があります。ライブラリ・インデックス値は、ユーザ定義であり、実行時に変更またはオーバーライドできます。
-
ライブラリ名は、インデックス内に格納され、ライブラリをロードするアプリケーションによって定義される必要はありません。ライブラリ・ファイルの名前と場所は、インデックス値によって、ライブラリをロードする依存アプリケーションに影響を与えることなくインデックス内で変更することができます。
-
ライブラリをロードする別の $ZF 関数はありません。代わりに、ライブラリはその関数の一つを呼び出す最初の $ZF(-6) 呼び出しによって自動的にロードされます。
-
開発者は既にライブラリ関数 ID (ZFEntry テーブル内の順序によって決定される) を知っていると見なされるため、指定された名前およびライブラリ・インデックス値に対して関数 ID を返す $ZF 関数はありません。
以下の例は、$ZF(-6) インタフェースの使用方法を示しています。最初の例は、システム・インデックス・テーブル内にライブラリ ID を定義し、2 番目の例 (別のアプリケーションから呼び出される場合がある) は、ライブラリ ID を使用してライブラリ関数を呼び出します。
この例では、システム・インデックス・テーブル内で 100 を mylibrary.dll のライブラリ ID として設定します。その番号に既に定義が存在している場合は、削除されて置き換えられます。
set LibID = 100
set status=$ZF(-4,4,LibID) // unload any existing library with this ID value
set status = $ZF(-4,5,LibID,"C:\calloutlibs\mylibrary.dll") // set system ID
-
LibID は、開発者によって選択されたインデックス番号です。この番号は、予約済みのシステム値 1024 ~ 2047 を除くゼロよりも大きい任意の整数です。
-
ライブラリに既にインデックス番号 100 がロードされている場合、エントリを置き換える前にアンロードする必要があります。
-
$ZF(-4,5) への呼び出しは、インデックス番号 100 をライブラリ・ファイル mylibrary.dll に関連付けます。
ライブラリ ID がシステム・インデックス・テーブルに定義されると、InterSystems IRIS の現在のインスタンス内のすべてのプロセスでグローバルに利用可能になります。
この例では、前の例で作成されたシステム・インデックス・テーブルを使用します。$ZF(-6) を使用してライブラリをロードし、ライブラリ関数を呼び出して、ライブラリをアンロードします。このコードは、システム・インデックス内でライブラリ ID を定義したのと同じアプリケーションから呼び出す必要はありません。
set LibID = 100 // library ID in system index table
set FuncID = 2 // second function in library ZFEntry table
set x = $ZF(-6,LibID, FuncID, "arg1") // call function 2
set status = $ZF(-4,4,LibID) // unload the library
-
LibID は、システム・インデックス内に定義されているライブラリ ID です。このアプリケーションは、ライブラリ関数を使用するためにライブラリ名またはパスを知っている必要はありません。
-
FuncID は、ライブラリ LibID の ZFEntry テーブルにリストされている 2 番目の関数の関数 ID です。開発者はライブラリ・コードへのアクセス権を持っていると見なされます — $ZF(-6) インタフェースは、ライブラリ関数名を指定することによって、この番号を取得するための関数を持っていません。
-
$ZF(-6) への呼び出しは、100 をライブラリ ID として指定し、2 を関数 ID として指定し、"arg1" を関数に渡す引数として指定します。この呼び出しは、コールアウト・ライブラリ mylibrary.dll がロードされていない場合にはロードし、ZFEntry テーブルにリストされている 2 番目の関数を呼び出します。
-
$ZF(-4,4) への呼び出しは、ライブラリをアンロードします。$ZF(-6) によってロードされる各ライブラリは、プロセスが終了するまでまたは $ZF(-4,4) によってアンロードされるまで常駐したままになります。
ライブラリ関数のカプセル化での $ZF(-6) インタフェースの使用
$ZF(-5) インタフェースの例のように動作する (この章で前述した “システム ID によるライブラリへのアクセスでの $ZF(-5) の使用” を参照) $ZF(-6) インタフェースの例を記述するのは簡単ですが、これは $ZF(-6) を使用した利点を示しません。代わりに、このセクションでは、エンド・ユーザがコールアウト・ライブラリの内容または場所について知らずにまったく同じタスクを実行できるようにする ObjectScript クラスを提供します。
$ZF(-5) の例は、コールアウト・ライブラリ inputlibrary.dll および outputlibrary.dll から関数を呼び出して、いくつかの実験データを処理してグラフの描画に使用できる 2 次元の配列を生成しました。このセクションの例は、同じタスクを以下の ObjectScript コードを使用して実行します。
-
クラス User.SystemIndex — システム・インデックス・テーブル内でエントリを定義するために使用されるファイル名およびインデックス番号をカプセル化します。
-
クラス User.GraphData — 両方のライブラリから関数をカプセル化するメソッドを提供します。
-
メソッド GetGraph() — User.GraphData メソッドを呼び出すエンド・ユーザ・プログラムの一部です。このメソッドのコードは、$ZF(-5) の例とまったく同じタスクを実行しますが、$ZF 関数を直接呼び出しません。
User.SystemIndex クラスを使用すると、コールアウト・ライブラリを使用するアプリケーションがインデックス番号またはファイルの場所をハードコード化することなく、システム・インデックス・エントリを作成してアクセスすることができます。
Class User.SystemIndex Extends %Persistent
{
/// Defines system index table entries for the User.GraphData libraries
ClassMethod InitGraphData() As %Status
{
// For each library, delete any existing system index entry and add a new one
set sc = $ZF(-4,4,..#InputLibraryID)
set sc = $ZF(-4,5,..#InputLibraryID,"c:\intersystems\iris\bin\inputlibrary.dll")
set sc = $ZF(-4,4,..#OutputLibraryID)
set sc = $ZF(-4,5,..#OutputLibraryID,"c:\intersystems\iris\bin\outputlibrary.dll")
quit 0
}
Parameter InputLibraryID = 100;
Parameter OutputLibraryID = 200;
}
-
InitGraphData() メソッドは、User.GraphData のライブラリをシステム・インデックス・テーブルに追加します。これは、InterSystems IRIS のインスタンスが開始されたときに自動的に呼び出され、ライブラリがインスタンス内のすべてのプロセスで利用可能になります。
-
InputLibraryID および OutputLibraryID クラス・パラメータが利用可能になり、依存アプリケーションが (以下の例の User.GraphData の Init() メソッドによって示されているように) インデックス値をハードコード化する必要がなくなります。
User.GraphData クラスを使用すると、エンド・ユーザが実際のコールアウト・ライブラリについて何も知らなくてもライブラリ関数を呼び出すことができます。
Class User.GraphData Extends %Persistent
{
/// Gets library IDs and updates the system index table for both libraries.
Method Init() As %Status
{
set InLibID = ##class(User.GraphDataIndex).%GetParameter("InputLibraryID")
set OutLibID = ##class(User.GraphDataIndex).%GetParameter("OutputLibraryID")
quit ##class(User.SystemIndex).InitGraphData()
}
Property InLibID As %Integer [Private];
Property OutLibID As %Integer [Private];
/// Calls function "FormatData" in library "inputlibrary.dll"
Method FormatData(rawdata As %Double) As %String
{
quit $ZF(-6,..InLibID,1,rawdata)
}
/// Calls function "RefineData" in library "outputlibrary.dll"
Method RefineData(midvalue As %String) As %String
{
quit $ZF(-6,..OutLibID,1,midvalue)
}
/// Calls function "PlotGraph" in library "outputlibrary.dll"
Method PlotGraph(datapoint As %String, xvalue As %Integer) As %String
{
quit $ZF(-6,..OutLibID,2,datapoint,xvalue)
}
/// Unloads both libraries
Method Unload() As %String
{
set sc = $ZF(-4,4,..InLibID) // unload "inputlibrary.dll"
set sc = $ZF(-4,4,..OutLibID) // unload "outputlibrary.dll"
quit 0
}
}
-
Init() メソッドは、inputlibrary.dll および outputlibrary.dll のシステム・インデックス・エントリを設定または更新する User.SystemIndex からクラス・メソッドを呼び出します。また、ライブラリ ID の現在の値も取得します。このクラスの開発者は引き続き、コールアウト・ライブラリ・コードについて知っている必要がありますが、システム・インデックスへの将来の変更は透過的になります。
-
メソッド FormatData()、RefineData()、および PlotGraph() はそれぞれ、1 つのライブラリ関数への呼び出しをカプセル化します。これらは無条件 $ZF 関数呼び出しのみを含むため、元の $ZF 呼び出しと同じ速さで実行するように最適化することができます。
-
Unload() メソッドは、ライブラリのいずれか、または両方をアンロードします。
以下の例は、エンド・ユーザが User.GraphData 内でメソッドを使用する方法を示しています。GetGraph() メソッドは、コールアウト・ライブラリを使用して $ZF(-5) インタフェース例内の GraphSomeData() メソッドとまったく同じタスクを実行しますが (この章で前述している “システム ID によるライブラリへのアクセスでの $ZF(-5) の使用” を参照)、$ZF 関数を直接呼び出しません。
Method GetGraph(loopsize As %Integer = 100000) As %Status
{
// Get an instance of class GraphData and initialize the system index
set graphlib = ##class(User.GraphData).%New()
set sc = graphlib.Init()
// call functions from both libraries repeatedly
// each library is loaded automatically on first call
for count=1:1:loopsize {
set midvalue = graphlib.FormatData(^rawdata(count))
set flatdata(count) = graphlib.RefineData(midvalue)
}
// plot results of the previous loop
for count=1:1:loopsize {
set x = graphlib.PlotGraph(flatdata(count),0)
set y = graphlib.PlotGraph(flatdata(count),x)
set ^graph(x,y) = flatdata(count)
}
//return after unloading all libraries loaded by $ZF(-6)
set status = graphlib.Unload()
quit 0
}
-
User.GraphData クラスは graphlib としてインスタンス化され、Init() メソッドがシステム・インデックスを初期化するために呼び出されます。システム・インデックスは InterSystems IRIS のインスタンス内のすべてのプロセスに対して初期化する必要があるのは一度のみのため、このメソッドをここで呼び出す必要はありません。
-
最初のループは、間接的に $ZF(-6) を使用して、各ライブラリから関数を呼び出し、$ZF(-6) は、各ライブラリを最初に必要な際に自動的にロードします。ライブラリ inputlibrary.dll は、FormatData() への最初の呼び出しでロードされ、outputlibrary.dll は、RefineData() への最初の呼び出しでロードされます。
-
2 番目のループは、PlotGraph() を既にロードされているライブラリ outputlibrary.dll から呼び出します。
-
Unload() への呼び出しは、両方のライブラリで間接的に $ZF(-4,4) を呼び出します。
テストでのプロセス・インデックスの使用
前に述べたように、プロセス・インデックス・テーブルは、システム・インデックス・テーブルの前に検索されるため、プロセス内でシステム全体の定義をオーバーライドするために使用できます。以下の例では、前のセクションで使用されたライブラリのうちの 1 つの新しいバージョンをテストするために使用されるプロセス・インデックスを作成します。
// Initialize the system index and generate output from standard library
set testlib = ##class(User.GraphData).%New()
set sc = testlib.Init()
set sc = graphgen.GetGraph() // get 100000 data items by default
merge testgraph1 = ^graph
kill ^graph
// create process index and test new library with same instance of testproc
set sc = $ZF(-4,4,100) // unload current copy of inputlib
set sc = $ZF(-4,8) // delete existing process index, if any
set sc = $ZF(-4,7,100, "c:\testfiles\newinputlibrary.dll") // override system index
set sc = graphgen.GetGraph()
merge testgraph2 = ^graph
// Now compare testdata1 and testdata2
-
前の例のように、最初の 3 行で、このテスト・コードはシステム・インデックスを初期化してグラフを生成します。グラフは、inputlibrary.dll の標準バージョン (ID 値 100 を持つシステム・インデックス・エントリによって識別される) を使用してプロットされ、testgraph1 に保存されています。
-
$ZF(-4,4) への呼び出しにより inputlibrary.dll がアンロードされます。これはシステム・インデックス・テーブル内でライブラリ ID 100 で識別されます。
-
$ZF(-4,8) は、ライブラリ ID を指定せずに呼び出され、現在のプロセス・インデックス・テーブル内のすべてのエントリが削除されることを示します。
-
$ZF(-4,7) への呼び出しは、テスト・ライブラリ newinputlibrary.dll に 100 をライブラリ ID として設定するプロセス・インデックス・テーブルにエントリを追加します。これにより、システム・インデックス内のその ID のエントリがオーバーライドされます。ライブラリ ID 100 は、inputlibrary.dll ではなく newinputlibrary.dll をポイントするようになります。
-
GetGraph() が User.GraphData の同じインスタンスを使用して再び呼び出されます。標準バージョンの inputlibrary.dll がアンロードされる以外は何も変更されないため、GetGraph() は新しいバージョンのライブラリをロードして使用します。その後、テストではグラフ testgraph1 と testgraph2 が比較され、両方のバージョンで同じ結果を生成することが確認されます。