クリアフィルター
記事
Toshihiko Minamoto · 2021年10月12日
[前の記事](https://jp.community.intersystems.com/node/492151)では、マクロの潜在的なユースケースををレビューしました。そこで、マクロの使用方法についてより包括的な例を見てみることにしましょう。 この記事では、ロギングシステムを設計して構築します。
### ロギングシステム
ロギングシステムは、アプリケーションの作業を監視するための便利なツールで、デバッグや監視にかける時間を大幅に節約してくれます。 これから構築するシステムは2つの部分で構成されます。
* ストレージクラス(レコードをログ記録するためのクラス)
* 新しいレコードをログに自動的に追加する一連のマクロ
### ストレージクラス
保存する必要のあるもののテーブルを作成し、コンパイル中やランタイム時に、このデータを取得できるタイミングを指定しましょう。 これは、システムの2つ目の部分であるマクロで作業するときに必要となります。そこでは、コンパイル中にできるだけ多くの記録可能な詳細を取得することを目指します。
情報
取得タイミング
イベントタイプ
コンパイル
クラス名
コンパイル
メソッド名
コンパイル
メソッドに渡される引数
コンパイル
clsソースコードの行番号
ランタイム
生成されたintコードの行番号
ランタイム
ユーザー名
ランタイム
日付/時刻
ランタイム
メッセージ
ランタイム
IPアドレス
ランタイム
上記のテーブルのプロパティを含むApp.Logクラスを作成しましょう。 App.Logオブジェクトが作成されると、ユーザー名、日付/時刻、およびIPアドレスプロパティは、自動的に入力されます。
App.Logクラス:
Class App.Log Extends %Persistent
{
/// イベントのタイプ
Property EventType As %String(MAXLEN = 10, VALUELIST = ",NONE,FATAL,ERROR,WARN,INFO,STAT,DEBUG,RAW") [ InitialExpression = "INFO" ];
/// クラスの名前、イベントが起きた場所
Property ClassName As %Dictionary.Classname(MAXLEN = 256);
/// メソッドの名前、イベントが起きた場所
Property MethodName As %String(MAXLEN = 128);
/// intコードの行
Property Source As %String(MAXLEN = 2000);
/// clsコードの行
Property SourceCLS As %String(MAXLEN = 2000);
/// Cacheユーザー
Property UserName As %String(MAXLEN = 128) [ InitialExpression = {$username} ];
/// メソッドに渡された引数の値
Property Arguments As %String(MAXLEN = 32000, TRUNCATE = 1);
/// 日付と時刻
Property TimeStamp As %TimeStamp [ InitialExpression = {$zdt($h, 3, 1)} ];
/// ユーザーメッセージ
Property Message As %String(MAXLEN = 32000, TRUNCATE = 1);
/// ユーザーのIPアドレス
Property ClientIPAddress As %String(MAXLEN = 32) [ InitialExpression = {..GetClientAddress()} ];
/// ユーザーIPアドレスの特定
ClassMethod GetClientAddress()
{
// %CSP.Session source is preferable
#dim %request As %CSP.Request
If ($d(%request)) {
Return %request.CgiEnvs("REMOTE_ADDR")
}
Return $system.Process.ClientIPAddress()
}
}
###
### ロギングマクロ
通常、マクロは、その定義を含む個別の *.incファイルに保存されます。 必要なファイルは、Include MacroFileNameコマンドを使って、クラスに含めることができます。この場合、Include App.LogMacroとなります。
初めに、ユーザーがアプリケーションコードに追加するメインのマクロを定義しましょう。
#define LogEvent(%type, %message) Do ##class(App.Log).AddRecord($$$CurrentClass, $$$CurrentMethod, $$$StackPlace, %type, $$$MethodArguments, %message)
このマクロは、イベントタイプとメッセージの2つの入力引数を受け入れます。 メッセージ引数はユーザーが定義しますが、イベントタイプパラメーターには、イベントタイプを自動的に識別する、別の名前による追加のマクロが必要となります。
#define LogNone(%message) $$$LogEvent("NONE", %message)
#define LogError(%message) $$$LogEvent("ERROR", %message)
#define LogFatal(%message) $$$LogEvent("FATAL", %message)
#define LogWarn(%message) $$$LogEvent("WARN", %message)
#define LogInfo(%message) $$$LogEvent("INFO", %message)
#define LogStat(%message) $$$LogEvent("STAT", %message)
#define LogDebug(%message) $$$LogEvent("DEBUG", %message)
#define LogRaw(%message) $$$LogEvent("RAW", %message)
したがって、ロギングを実行するには、ユーザーはアプリケーションコードに$$$LogError("Additional message")のみを配置するだけで済みます。
後は、$$$CurrentClass、$$$CurrentMethod、$$$StackPlace、$$$MethodArgumentsマクロを定義するのみです。 では、最初の3つから始めましょう。
#define CurrentClass ##Expression($$$quote(%classname))
#define CurrentMethod ##Expression($$$quote(%methodname))
#define StackPlace $st($st(-1),"PLACE")
%classnameと%methodname変数は、[ドキュメント](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCOS_macros)に記載されています。 [$stack](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fstack)関数はINTコードの行番号を返します。 これをCLS行番号に変換するには、このコードを使用できます。
%Dictionaryパッケージを使用して、メソッド引数とその値のリストを取得しましょう。 これにはメソッドの説明を含む。クラスに関するすべての情報が含まれています。 特に関心があるのは%Dictionary.CompiledMethodクラスとFormalSpecParsedプロパティで、これはリストです。
$lb($lb("Name","Classs","Type(Output/ByRef)","Default value "),...)
これはメソッドのシグネチャに対応しています。 たとえば次のコードがあるとします。
ClassMethod Test(a As %Integer = 1, ByRef b = 2, Output c)
このコードには、次のFormalSpecParsed値があります。
$lb(
$lb("a","%Library.Integer","","1"),
$lb("b","%Library.String","&","2"),
$lb("c","%Library.String","*",""))
$$$MethodArgumentsマクロを次のコードに展開する必要があります(Testメソッド)。
"a="_$g(a,"Null")_"; b="_$g(b,"Null")_"; c="_$g(c,"Null")_";"
これを行うには、コンパイル中に次のことを行う必要があります。
クラス名とメソッド名を取得する
%Dictionary.CompiledMethodクラスの対応するインスタンスを開いて、そのFormalSpecプロパティを取得する
それをソースコード行に変換する
対応するメソッドをApp.Logクラスに追加しましょう。
ClassMethod GetMethodArguments(ClassName As %String, MethodName As %String) As %String
{
Set list = ..GetMethodArgumentsList(ClassName,MethodName)
Set string = ..ArgumentsListToString(list)
Return string
}
ClassMethod GetMethodArgumentsList(ClassName As %String, MethodName As %String) As %List
{
Set result = ""
Set def = ##class(%Dictionary.CompiledMethod).%OpenId(ClassName _ "||" _ MethodName)
If ($IsObject(def)) {
Set result = def.FormalSpecParsed
}
Return result
}
ClassMethod ArgumentsListToString(List As %List) As %String
{
Set result = ""
For i=1:1:$ll(List) {
Set result = result _ $$$quote($s(i>1=0:"",1:"; ") _ $lg($lg(List,i))_"=")
_ "_$g(" _ $lg($lg(List,i)) _ ","_$$$quote(..#Null)_")_"
_$s(i=$ll(List)=0:"",1:$$$quote(";"))
}
Return result
}
次に$$$MethodArgumentsマクロを以下のように定義しましょう。
#define MethodArguments ##Expression(##class(App.Log).GetMethodArguments(%classname,%methodname))
ユースケース
それでは、ロギングシステムの機能を示すために、Testメソッドを使ってApp.Useクラスを作成しましょう。
Include App.LogMacro
Class App.Use [ CompileAfter = App.Log ]
{
/// Do ##class(App.Use).Test()
ClassMethod Test(a As %Integer = 1, ByRef b = 2)
{
$$$LogWarn("Text")
}
}
上記の結果、intコードの$$LogWarn("Text")マクロは次の行に変換されます。
Do ##class(App.Log).AddRecord("App.Use","Test",$st($st(-1),"PLACE"),"WARN","a="_$g(a,"Null")_"; b="_$g(b,"Null")_";", "Text")
このコードを実行すると、新しいApp.Logレコードが作成されます。
改善点
ロギングシステムを作成したところで、次のような改善のアイデアがあります。
まず、オブジェクト型引数を処理するようにすることができます。現在の実装では、オブジェクトorefしか記録しないためです。
次に、呼び出しで、保存された引数値からメソッドのコンテキストを復元するようにできます。
オブジェクト型引数の処理
引数の値をログに入れる行は、ArgumentsListToStringメソッドに生成され、次のようになります。
"_$g(" _ $lg($lg(List,i)) _ ","_$$$quote(..#Null)_")_"
リファクタリングを行って、それを、変数名とクラス(FormalSpecParsedから知ることができます)を受け入れる別のGetArgumentValueメソッドに移動し、変数を行に変換するコードを出力してみましょう。 データ型には既存のコードを使用し、オブジェクトは、SerializeObject(ユーザーコードから呼び出すため)とWriteJSONFromObject(オブジェクトをJSONに変換するため)メソッドを使ってJSONに変換されます。
ClassMethod GetArgumentValue(Name As %String, ClassName As %Dictionary.CacheClassname) As %String
{
If $ClassMethod(ClassName, "%Extends", "%RegisteredObject") {
// オブジェクトです
Return "_##class(App.Log).SerializeObject("_Name _ ")_"
} Else {
// データ型です
Return "_$g(" _ Name _ ","_$$$quote(..#Null)_")_"
}
}
ClassMethod SerializeObject(Object) As %String
{
Return:'$IsObject(Object) Object
Return ..WriteJSONFromObject(Object)
}
ClassMethod WriteJSONFromObject(Object) As %String [ ProcedureBlock = 0 ]
{
Set OldIORedirected = ##class(%Device).ReDirectIO()
Set OldMnemonic = ##class(%Device).GetMnemonicRoutine()
Set OldIO = $io
Try {
Set Str=""
//IOを現在のルーチンにリダイレクト。以下に定義するラベルを利用。
Use $io::("^"_$ZNAME)
//リダイレクトを有効にします
Do ##class(%Device).ReDirectIO(1)
Do ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(Object)
} Catch Ex {
Set Str = ""
}
//元のリダイレクト/ニューモニックルーチンの設定に戻ります
If (OldMnemonic '= "") {
Use OldIO::("^"_OldMnemonic)
} Else {
Use OldIO
}
Do ##class(%Device).ReDirectIO(OldIORedirected)
Quit Str
// IOリダイレクトが可能なラベル
// 文字の読み取り。読み取りは重要ではありません
rchr(c) Quit
// 文字列の読み取り。読み取りは重要ではありません
rstr(sz,to) Quit
// 文字の書き込み。出力ラベルを呼び出します
wchr(s) Do output($char(s)) Quit
// フォームフィードの書き込み。出力ラベルを呼び出します
wff() Do output($char(12)) Quit
// 改行の書き込み。出力ラベルを呼び出します
wnl() Do output($char(13,10)) Quit
// 文字列の書き込み。出力ラベルを呼び出します
wstr(s) Do output(s) Quit
// タブの書き込み。出力ラベルを呼び出します
wtab(s) Do output($char(9)) Quit
// 出力ラベル。ここで、実際に行いたいことを処理します。
// ここではStrに書き込みます
output(s) Set Str = Str_s Quit
}
オブジェクト型引数のログエントリは次のようになります。

### コンテキストの復元
このメソッドの主旨は、すべての引数を現在のコンテキストで(主にデバッグ用のターミナルで)使用できるようにすることです。 これを行うために、ProcedureBlockメソッドパラメーターを使用することができます。 0に設定すると、そのようなメソッドに宣言されたすべての変数はメソッドを終了してもそのまま使用することができます。 ここでのメソッドは、App.Logクラスのオブジェクトを開いて、Argumentsプロパティを逆シリアル化します。
ClassMethod LoadContext(Id) As %Status [ ProcedureBlock = 0 ]
{
Return:'..%ExistsId(Id) $$$OK
Set Obj = ..%OpenId(Id)
Set Arguments = Obj.Arguments
Set List = ..GetMethodArgumentsList(Obj.ClassName,Obj.MethodName)
For i=1:1:$Length(Arguments,";")-1 {
Set Argument = $Piece(Arguments,";",i)
Set @$lg($lg(List,i)) = ..DeserializeObject($Piece(Argument,"=",2),$lg($lg(List,i),2))
}
Kill Obj,Arguments,Argument,i,Id,List
}
ClassMethod DeserializeObject(String, ClassName) As %String
{
If $ClassMethod(ClassName, "%Extends", "%RegisteredObject") {
// オブジェクトです
Set st = ##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(String,,.obj)
Return:$$$ISOK(st) obj
}
Return String
}
ターミナルでは次のように表示されます。
> zw
> do ##class(App.Log).LoadContext(2)
> zw
a=1 b=<OBJECT REFERENCE> [2@%ZEN.proxyObject]
> zw b
b=<OBJECT REFERENCE> [2@%ZEN.proxyObject]
+----------------- general information ---------------
| oref value: 2
| class name: %ZEN.proxyObject
| reference count: 2
+----------------- attribute values ------------------
| %changed = 1
| %data("prop1") = 123
| %data("prop2") = "abc"
| %index = ""
### この続きは?
鍵となる潜在的な改善点は、メソッド内に作成された任意の変数リストを使用して、ログクラスに別の引数を追加することです。
### まとめ
マクロはアプリケーション開発に非常に役立ちます。
### 質問
コンパイル中に行番号を取得する方法はありますか?
### リンク
* [パート1. マクロ](https://jp.community.intersystems.com/node/492151)
* [GitHubリポジトリ](https://github.com/intersystems-ru/Log)
記事
Toshihiko Minamoto · 2021年12月24日
皆さん、こんにちは。私の最新のプロジェクトの1つをご紹介します。 [Grafana用データソースプラグイン](https://openexchange.intersystems.com/package/Grafana-Plugin-for-InterSystems)です。これは、InterSystems IRISに直接接続して(将来的に)あらゆるデータを収集できるプラグインです。
.png)
### 機能
* 定期的に更新される履歴付きのSAM メトリクスで、Grafanaが直接収集したメトリクスを、表示中にリクエストされた場合にのみ表示できます。
* messages.logとalerts.logを表示します。
* ^ERRORSグローバルのアプリケーションエラー
#### 後日追加予定の機能
* DateTimeフィールドの有無に関わらずテーブルをクエリするすべてのSQL SELECT
* グローバルからデータを直接表示
* IRIS側でカスタムSQLクエリを呼び出す
* MDXクエリ
つまり、アプリケーション内でログを記録するためのカスタムロジックが存在する場合、Grafanaをそれらのログに接続して、そこで表示することが可能ということです。
### テスト
自分でテストしてみるには、リポジトリをクローンして、docker-composeで環境を開始します。 docker-compose環境はポート3000、3081、3082を使用して構成されるようになっているため、システム上でこれらのポートがすでに使用されている場合は、docker-compose.ymlファイルでポートを変更してください。
git clone https://github.com/caretdev/grafana-intersystems-datasource.git
cd grafana-intersystems-datasource
docker-compose up -d
イメージをプルしたら、2つのコンテナでGrafanaとIRISが開始します。
Grafanaはhttp://localhost:3000/で開きます。
[DataSources]に移動すると、InterSystems IRIS接続が自動プロビジョニングによって追加されています。
.png)
中を覗くと、基本設定付きの単純なフォームと接続を確認するための[Test]ボタンがあります。 IRISが起動すると、緑色の「OK」が表示されます。
.png)
ダッシュボードとパネルを作成しましょう

[Query Type]で「Metrics」を選択します。

例としてiris\_db\_latencyを選択しましょう

デフォルトの更新間隔は選択した時間間隔に応じますが、クエリオプションの[Min Interval]フィールドで変更することができます。
.png)
ログファイルとアプリケーションエラーは、ログの視覚化とともにテーブルとして表示することができます。

[プロジェクトに投票](https://openexchange.intersystems.com/contest/current)してください
プラグインにほかの機能の追加を希望する場合は、私にご連絡ください。
お知らせ
Mihoko Iijima · 2024年2月16日
開発者の皆さん、こんにちは!
InterSystems 技術文書ライティングコンテストの開催が決定しました!《USコミュニティのコンテストです》
✍️ 技術文書ライティングコンテスト: InterSystems IRIS チュートリアル ✍️
2月19日~3月24日の期間で、InterSystems IRIS のプログラマを対象に、初心者/中級者/上級者のレベルを問わないチュートリアルとなるような記事を投稿してください!
🎁 参加賞(全員): コンテストに参加いただいた皆様全員に参加賞があります!(参加賞とは別に特別賞もあります!)
賞品
1. 技術文書ライティングコンテストに投稿された全員! - コンテストの期間中に記事を投稿いただいた方全員に参加賞をご用意しています。
🎁 Terra Thread Fairtrade Waist Pack
2. エキスパートアワード – InterSystemsのエキスパートにより審査されます。
🥇 1位 - iPad10th generation
🥈 2位 - Beats Fit Pro True Wireless Earbuds
🥉 3位 - Amazon Kindle Paperwhite Signature Edition (32 GB)
※優勝者は1位の受賞賞品の代わりに、2位、3位の賞品を選択することもできます。
3. 開発者コミュニティアワード – 「いいね!」が最も多かった記事に贈られます。
🎁 Amazon Kindle Paperwhite Signature Edition (32 GB)
メモ:
著者は 1ノミネートに対して1つの賞品を獲得できます(一人の著者は、エキスパートノミネートで1賞品、コミュニティノミネートで1賞品 の合計 2 つの賞品を獲得することができます)。
同点の場合は、同点の記事に対するエキスパートの投票数を同点判定基準とします。
参加資格
どなたでもご参加いただけます!(InterSystems 開発者コミュニティのアカウントを作成するだけでご応募いただけます)
コンテストスケジュール
📝 2024年2月19日~3月24日:この期間にコミュニティへの記事の投稿と投票が行われます。
開発者コミュニティメンバーは、公開された記事に「いいね!」をつけることで「開発者コミュニティアワード」の投票を行ったことになります。
《注意》記事の公開が早ければ早いほど、「いいね!」を集める期間が長くなります。
応募条件
❗️ コンテスト期間中に書かれた記事で、以下の条件を満たすものは、自動的(*)にコンテストに参加することができます。
InterSystems IRISのチュートリアル(**)を投稿してください。チュートリアルのレベルは初級、中級、上級のいずれでもかまいません。
英語での投稿をお願いします。(スクリーンショット、コードなども含めて英語での表記でお願いします。
USの開発者コミュニティに投稿してください。(日本のコミュニティに投稿してからの英語翻訳記事としてUSコミュニティに投稿した場合、コンテスト対象記事として認識されませんのでご注意ください。)
記事は、新しい記事で投稿してください(既存の記事の続編でも構いません)。
他のコミュニティで投稿された記事の翻訳記事では応募できません。
記事には、インターシステムズの技術に関する正確で信頼できる情報のみを掲載してください。
記事を投稿する際 Tutorial tag をつけて投稿してください
記事は400単語以上としてください(リンクとコードは文字制限にカウントしません)
同じトピックであっても異なる著者による異なる内容の記事であれば許可されます。
* コミュニティのエキスパートが記事を審査します。コンテストに参加できるのは有効はコンテンツのみです。
** チュートリアルは開発者が特定のタスクや一連のタスクを完了できるように、手順を示してください。
🎯 EXTRA BONUSES
今回は、当選に有利なボーナスを追加することにしました!ぜひチェックしてください!
Bonus
Nominal
Details
Topic bonus
5
提案されたトピックのリスト(下記)にあるトピックに関する記事であれば、ボーナスとしてエキスパート5票(エキスパートが選ぶ1位が3票です)を獲得できます。
Video bonus
3
記事の記載だけでなく説明用ビデオを作成した場合獲得できます。
Discussion bonus
1
インターシステムズのエキスパートが決定した、最も有益な議論を行った記事に対して獲得できます。このボーナスを獲得できるのは1記事のみです。
Translation bonus
2
翻訳記事を他リージョンのコミュニティに投稿するとボーナスポイントを獲得できます。 翻訳方法はこちらの記事をご参照ください。メモ:1記事つき1票のみ獲得できます
New participant bonus
3
コンテストに参加経験のない方は、3エキスパート票を獲得できます。
トピック候補
ボーナス特典をゲットできるトピック案です。
✔️ AI/ML/GenAI の使用✔️ Cloud SQLの使用✔️ VSCodeの使用✔️ Kubernetesの使用✔️ FHIR SQL Builderの使用
注)同じテーマでも、著者が異なる記事はOKで
➡️ InterSystems Discord に参加してルールやトピック、ボーナスについてチャットしましょう!
皆さんの✨素敵✨な記事をお待ちしています!
重要事項:賞品の配送は国によって異なり、一部の国では不可能な場合があります。制限のある国のリストは、@Liubka Zelenskaia までお問い合わせください
記事
Hiroshi Sato · 2021年11月11日
これは InterSystems FAQ サイトの記事です。
設定内容によって、方法が異なります。
システム構成について管理ポータルの [システム管理] > [構成]
以下の設定については(※1)、パラメータファイル(InterSystems IRISは iris.cpf、Caché/Ensemble/HealthShareは cache.cpf) に格納されます。
このファイルはテキストファイルとなっていますのでこのファイルの一部を他のシステムにコピーして反映させることが可能です。 ただし、ディレクトリ名など各システム固有の情報が多く含まれるため、そのままファイル全体をコピーしても設定内容を反映させることはできません。 (※1) 【Caché/Ensemble2010.2以前】 [システム管理ポータル] > [構成] (システム構成) メニュー以下の設定が対象です。 パラメータ・ファイルの各項目については、以下ドキュメントをご参照ください。 InterSystems パラメータ・ファイル・リファレンスについて【IRIS】 Caché パラメータ・ファイル・リファレンスについて
セキュリティについて^SECURITY ユーティリティを使用してエクスポート/インポートすることが可能です。 ターミナルを起動し、%SYSネームスペースで以下のコマンドを実行してください。
%SYS>Do ^SECURITY
1) User setup2) Role setup3) Service setup4) Resource setup5) Application setup6) Auditing setup8) SSL configuration setup9) Mobile phone service provider setup10) OpenAM Identity Services setup11) Encryption key setup12) System parameter setup13) X509 User setup14) KMIP server setup15) ExitOption? 121) Edit system options2) Edit authentication options3) Edit LDAP options4) Display system options5) Export All Security settings <-- エクスポート6) Import All Security settings <-- インポート7) ExitOption? 5 または 6
注意) Caché/Ensemble 2011.1.0より前のバージョンでは、上記ツールで SQL TABLE のセキュリティ設定をエクスポート/インポートすることができません。 その場合は、%System.SQLクラスのクラスメソッドExport()を使用して行うことが可能です。 詳細は以下ドキュメントをご参照ください。 %SYSTEM.SQLのクラスリファレンスについて
開発機のサーバ接続リスト (優先接続サーバ)について こちらは、InterSystems製品でエクスポート/インポートする方法はご提供していません。
サーバの定義はWindowsシステムのレジストリに格納しています(全製品共通)。
32bitHKEY_LOCAL_MACHINE\SOFTWARE\InterSystems\Cache\Servers
64bit
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\InterSystems\Cache\Servers
お知らせ
Toshihiko Minamoto · 2021年4月24日
みなさん、こんにちは。今回はInterSystems Container Registryを発表できることをうれしく思います。 これはコンテナベースのリリースやプレビューにアクセスする新たな配布チャンネルです。すべてのコミュニティエディションのイメージはログイン不要の公開リポジトリにあります。すべてのリリースイメージ(IRIS, IRIS for Health, Health Connect, System Alerting and Monitoring, InterSystems Cloud Manager) やユーティリティイメージ(アービター、 Web Gateway、PasswordHash等) にはWRCアカウントの認証情報から生成されるログイントークンが必要です。
WRC配布サイトは当面の間、引き続きTar形式などのリリースイメージを提供します。しかしながら、CI/CDパイプラインを「docker pull」でInterSystems Container Registryから直接イメージを取得するよう設定できるようになりました。
レジストリにはhttps://containers.intersystems.comでアクセスできます。以下の内容やドキュメント (Using the InterSystems Container Registry) の使用方法をご参照ください。実行時の問題や共有したいフィードバックがありましたら、以下にコメント頂くか、jpnsup@intersystems.comまでご連絡ください。
--------------------------------------------------------------
InterSystems Container Registryの使い方
ここでは、https://containers.intersystems.comにあるInterSystems Container Registry (ICR)の使用手順を記載します。
ICRのイメージは以下の例のように docker pull コマンドでダウンロードできます。
docker pull containers.intersystems.com/intersystems/iris-community:2020.4.0.547.0
ダウンロードできるイメージの一覧は InterSystemsの利用可能なコンテナイメージ をご参照ください。
このドキュメントには以下の章に分かれています。
ICRへの認証
ICRの収録イメージ一覧
ICRへの認証
ICRには以下の手順でログインできます。
ブラウザより https://containers.intersystems.com/ にアクセスし、インターシステムズWRC認証情報でログインします。
Dockerログイントークンかログインコマンドを取得します。
取得した認証情報を使い、Dockerインターフェース(PowerShellウインドウやLinuxコマンドラインなど)でICRへの認証を行います。以下の例のように、表示されるDocker ログインコマンドをコピー、ペーストすることで認証できます。
docker login -u="bbinstoc" -p="provided_password" containers.intersystems.com
セキュリティの観点から、コマンド docker login containers.intersystems.com を入力しますと、Username プロンプトにユーザ名、Password プロンプトにパスワードを入力できます。
注意: 別のDockerレジストリにログインした場合、Dockerログインコマンドでエラーが発生することがあります。別のDockerレジストリをログアウトしてから、containers.intersystems.comにログインしてください。
以下の例のようにICRからイメージをpullすることができます。
docker pull containers.intersystems.com/intersystems/iris:2020.4.0.547.0
ICRでの収録一覧
Dockerレジストリにてイメージやタグで一覧を取得するAPIが利用できます。レジストリの内容を一覧するものとして利用できるオープンソースなサードパーティーユーティリティの一例としてdocker-ls があります。 https://github.com/mayflower/docker-ls より取得できます。
このユーティリティを入手する方法としては
様々なプラットホームに対応した コンパイルされた docker-ls バイナリ をダウンロードします。
プラットホーム上で直接ユーティリティをインストールします。例としてLinuxシステムでは以下のコマンドを使用します。
sudo snap install docker-ls
ユーティリティをインストールするLinuxプラットホームでイメージ carinadigital/docker-ls:latest をPull、実行します。
docker run --rm carinadigital/docker-ls:latest
docker-ls がインストールされると、ICRのリポジトリをリストする以下のコマンドが使用できます。
docker-ls repositories --registry https://containers.intersystems.com --user username --password password
注意: コマンドライン上にパスワードを含めるのではなく、パスワードの入力を促す --interactive-password オプションをご利用ください。
パブリックに利用できるイメージのみを一覧するには --user や --password オプションの引数として空文字("")を指定してください。以下はパブリックなInterSystems IRIS for Healthイメージを一覧する例です。
docker-ls tags --registry https://containers.intersystems.com --user "" --password "" intersystems/irishealth-community
パブリックでないイメージの一覧を見るには、containers.intersystems.comにログインしているかどうかにかかわらず、このユーティリティにユーザ名とパスワードを指定する必要があります。
その他の例は https://github.com/mayflower/docker-ls をご参照ください。
お知らせ
Toshihiko Minamoto · 2020年10月11日
InterSystems は、InterSystemsIRIS を新しいリリース方法を採用しようとしています(訳注:2020年現在、このリリース方法が採用されています)。このブログでは、新しいリリースモデルとお客様が予測しておくべきことを説明しています。 この内容は InterSystems IRIS ロードマップセッションの最後に行われた Global Summit で説明し、お客様から多くの肯定的なフィードバックを受け取ったものです。
この新しいモデルでは、次の 2 つのリリースストリームを提供しています。
1)EM と呼ばれる従来と同じ毎年恒例のリリース(拡張メンテナンス)
2)CD(継続的デリバリーを意味する)のタグが付けられ、コンテナ形式でのみ入手可能になる四半期ごとのリリース。
変更の理由はスピードと予測性の向上
この業界では変化のペースが加速していますが、このモデルを採用すれば最新機能を非常に迅速に公開し、市場での応答性と競争力を高めることができます。 当社は多くのお客様から次の 2 つを求められています。
新機能をリクエストしてからそれを使用できるようになるまでの時間の短縮
アップデート計画を立てるための予測可能なスケジュール
この継続的デリバリーの原則に基づいた新しいリリースの流れは、多くの主要ソフトウェア会社やエンタープライズ対応のオープンソースプロジェクトの大部分で使用されている 2 ストリームモデルとほぼ同等のものです。 この方法の採用に成功した人々は、リリースの品質が向上し、リスクが低下し、応答時間が短縮されたことを明確に報告しています。
従来のリリース方針は変更なし
従来と同じリリース(「EM」リリース)はこれまでと同じように行われます。 このリリースは継続的なメンテナンスリリースの対象となり、必要に応じてその場その場で提供され、すべてのプラットフォームでサポートされます。 従来通り、全製品のインストールキットは WRC Software Distribution ポータルを通じて入手できます。 フィールドテストはこれまでと同様にメジャーリリースで利用できます。 メンテナンスリリースは従来と同じ基本ルールが適用され、EMリリースで利用できます。
以前と異なるのは、これらのリリースが毎年予測可能なタイミングで提供されるようになることです。 次の図に示すように、InterSystems IRIS のバージョン 2019.1 は 2019 年 3 月に、バージョン 2020.1 は 2020 年 3 月に予定されています。
新しい四半期リリースではコンテナのみが提供
3 カ月ごとに新しい四半期リリースストリームを介して「CD」表記の新機能が提供されるようになります。 例えば次の図に示すように、InterSystems IRIS バージョン 2018.2 CD は 2018 年 11 月に、バージョン 2019.1 CD は 2019 年 2 月に、バージョン 2019.2 CD は 2019 年 5 月に予定されています。
CD リリースには次の制限があります。
Open Container Initiative(OCI)フォーマットを使用するコンテナイメージとしてのみ入手できます。 このフォーマットは、Docker / Amazon / Microsoft / Google / IBM などの多くの企業で広く使用され、サポートされています。
OCI 互換のインフラストラクチャのみで動作します。 Docker は最も一般的な OCI ランタイムであるため、InterSystems は Ubuntu Linux カーネルで構築された Docker コンテナの提供とサポートを行っています。 このコンテナは、すべての主要クラウドプラットフォーム(Amazon AWS / Microsoft Azure / Google GCP/ IBM Cloud)と事実上すべての種類の Linux、Windows Server 2016 / 2019 などのさまざまなプラットフォームで実行されます。 InterSystems は Docker-for-windows と Docker-for-mac をそれぞれ使用する開発専用の Windows 10 と Mac OS へのコンテナのデプロイをサポートしています。 (現時点で OCI コンテナをサポートしていない代表的なプラットフォームは AIX です。)
これらはコンテナであるため、インストールやイメージのアップグレードは不要です。 InterSystems が提供するコンテナイメージを使用し、それともとに独自のイメージを作成できます。 デプロイする場合は、単純にコンテナを入れ替えるだけです。データのアップグレードが必要な場合、InterSystems はリリースと共にアップグレードを提供します。
CD リリースに関して、InterSystems はメンテナンスリリース、セキュリティ修正、またはAdhoc(パッチ修正)を提供しません。変更を取得したい場合は、単純に次のリリースを取得してください。 最新の変更が加えられた新しいリリースが 3 カ月ごとに提供されるため、重要な修正を待つ必要はありません。
InterSystems は開発、テスト、および本番環境を対象に CD リリースを完全にサポートしています。 InterSystems は各 CD リリースに加えてプレビュープログラムも用意し、最終リリースの前にプレビューイメージを提供します。 プレビューイメージは、開発およびテストを目的とする場合はサポートされますが、本番環境ではサポートされていません。
コンテナは比較的新しいものですが、現在は広く使用されており、多くのメリットがあります。 お客様は CD リリースを使用したり、コンテナを採用したりする必要はありません。ただし、コンテナ内で InterSystems IRIS を使用するのに役立つ多くの InterSystems のリソース(複数のオンライン動画を含む)が存在するほか、業界全体には大規模なコンテナ周辺のエコシステムがあります。
CD リリースは新機能を迅速に提供するほか、従来の(EM)リリースの予測可能性と安定性の向上に役立ちます。今年最初の CD リリースには対応する EM リリースがあります(プラットフォーム固有の機能を除いては同じものです)。また、これらには以前の CD リリースのすべての機能に加えてさらに多くの機能が追加されています。開発者は CD リリースで作業でき、コードが従来のリリースでも機能することを確信できます。CD リリースを試さなかった場合でも、四半期ごとに InterSystems IRIS でリリースされた機能を追跡し、自信を持って計画を立てることができます。
記事
Toshihiko Minamoto · 2021年1月28日
独自の組織データアーキテクチャを書き、InterSystems IRIS にマッピングする必要がある場合は、以下にご紹介するデータアーキテクチャダイアグラムおよび InterSystems IRIS ドキュメンテーションのリファレンスに記載されている内容を考慮してください。
.png)
## **アーキテクチャマッピング**
SQL データベース: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GSQL
管理されるファイル: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=AFL_mft および https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=SETEDIGuides
IoT ブローカー、イベント、センサー: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=EMQTT
メッセージ: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=EMQS
NoSQL: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GDOCDB
API と Web サービス: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GREST, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GSOAP, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=AFL_iam および https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=PAGE_interoperability
ETL: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=SETAdapters, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=EDTL, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=EBPL および
EAI コネクタ: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=SETAdapters
XEP イベント: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=BJAVXEP, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=BNETXEP,
ビッグデータの取り込み: https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=BSPK
AI: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=PAGE_text_analytics, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=APMML, https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=PAGE_python_native, https://www.intersystems.com/br/resources/detail/machine-learning-made-easy-intersystems-integratedml/
プロセス: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=EBPL
コーポレートサービス: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=EESB および https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=AFL_iam
メモリ内: https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=GSCALE_ecp
コンテンツ: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GDOCDB
文字列: https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_textanalytics
保護: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=SETSecurity, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=TSQS_Applications, https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI および https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=GCAS
インベントリ: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GSA_using_portal および https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=GOBJ_xdata
プライバシー: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GCAS_encrypt
IT ライフサイクル、バックアップ、復元: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GSA_using_portal, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=GCDI_backup
アクセス管理:
https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=TSQS_Authentication, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=TSQS_Authorization, https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=TSQS_Applications
レプリケーションおよび HA (高可用性): https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=PAGE_high_availability
モニタリング: https://docs.intersystems.com/sam/csp/docbook/DocBook.UI.Page.cls?KEY=ASAM および https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=PAGE_monitoring
IT オペレーション: https://docs.intersystems.com/irislatestj/csp/docbook/Doc.View.cls?KEY=PAGE_platform_mgmt
* ## 視覚化: https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=PAGE_bi
記事
Toshihiko Minamoto · 2020年9月30日
InterSystems IRIS のクラスクエリ
InterSystems IRIS(および Cache、Ensemble、HealthShare)のクラスクエリは、SQL クエリを Object Script のコードから分離する便利なツールです。 このクエリの基本的な機能は、同じ SQL クエリを複数の場所で異なる引数で使用する場合にクエリの本文をクラスクエリとして宣言し、このクエリを名前で呼び出すことでコードの重複を回避できるというものです。 このアプローチは、次のレコードを取得するタスクを開発者が定義するカスタムクエリにも便利です。 興味が湧きましたか? それではこのまま読み進めてください!
## 基本クラスクエリ
簡単に言うと、基本クラスクエリは SQL の SELECT クエリを表現できるようにするものです。 基本クラスクエリは SQL オプティマイザとコンパイラによって通常の SQL クエリと同様に処理されますが、Caché Object Script のコンテキストから実行する際はより便利になります。 また、次のようにクラス定義(メソッドまたはプロパティと同様)でクエリ項目として宣言されます。
* タイプ: %SQLQuery
* SQL クエリのすべての引数を引数リストに含める必要があります。
* クエリタイプ: SELECT
* コロンを使用して各引数にアクセスします(静的SQLと同様)。
* 出力結果の名前とデータタイプに関する情報を含む ROWSPEC パラメーターをフィールドの順序と共に定義します。
* (任意)フィールドに ID が含まれている場合、 CONTAINID パラメーターにその列番号を定義します。 ID を返す必要がない場合は、CONTAINID に0を割り当てます。
* (任意)静的 SQL の同様のパラメーターに対応し、SQL 式をコンパイルするタイミングを指定する COMPILEMODE パラメーターを定義します。 このパラメーターが IMMEDIATE(デフォルト)に設定されている場合、クエリはクラスと同時にコンパイルされます。 このパラメーターを DYNAMIC に設定すると、クエリは初回実行の前にコンパイルされます(動的 SQL と同様)。
* (任意)クエリ結果の形式を指定する SELECTMODE パラメーターを定義します。
* このクエリを SQL プロシージャとして呼び出す場合は、SqlProc プロパティを追加します。
* クエリの名前を変更する場合は、SqlName プロパティを設定します。 SQL コンテキストでのクエリのデフォルト名は PackageName.ClassName_QueryName です。
* Caché Studio には、クラスクエリを作成するためのウィザードが搭載されています。
指定した文字で始まるすべてのユーザー名を返す ByName クエリを使った Sample.Person クラスのサンプル定義
Class Sample.Person Extends %Persistent
{
Property Name As %String;
Property DOB As %Date;
Property SSN As %String;
Query ByName(name As %String = "") As %SQLQuery
(ROWSPEC="ID:%Integer,Name:%String,DOB:%Date,SSN:%String",
CONTAINID = 1, SELECTMODE = "RUNTIME",
COMPILEMODE = "IMMEDIATE") [ SqlName = SP_Sample_By_Name, SqlProc ]
{
SELECT ID, Name, DOB, SSN
FROM Sample.Person
WHERE (Name %STARTSWITH :name)
ORDER BY Name
}
}
このクエリを次のように Caché Object Script から呼び出すことができます。
Set statement=##class(%SQL.Statement).%New()
Set status=statement.%PrepareClassQuery("Sample.Person","ByName")
If $$$ISERR(status) {
Do $system.OBJ.DisplayError(status)
}
Set resultset=statement.%Execute("A")
While resultset.%Next() {
Write !, resultset.%Get("Name")
}
または、自動生成されたメソッドである「クエリ名Func」を使用して結果セットを取得することもできます。
Set resultset = ##class(Sample.Person).ByNameFunc("A")
While resultset.%Next() {
Write !, resultset.%Get("Name")
}
このクエリは、SQL コンテキストから次の 2 つの方法で呼び出すこともできます。
Call Sample.SP_Sample_By_Name('A')
Select * from Sample.SP_Sample_By_Name('A')
このクラスは、SAMPLES のデフォルト Caché ネームスペースにあります。単純なクエリに関する説明は以上となります。 今度はカスタムクエリを説明します。
## カスタムクラスクエリ
基本クラスクエリはほとんどの場合に正常に動作しますが、次のような場合にはアプリケーションでクエリの動作を完全に制御しなければならないことがあります。
* 選択条件が複雑な場合。 カスタムクエリでは次のレコードを返す Caché Object Script メソッドが独自に実装されているため、選択条件が要件に応じて複雑化している可能性があります。
* 使用したくない形式の API経由でしかデータにアクセスできない場合。
* データが(クラスなしで)グローバルに保存されている場合。
* データにアクセスするために権利を昇格する必要がある場合。
* データにアクセスするために外部 API を呼び出す必要がある場合。
* データにアクセスするためにファイルシステムにアクセスする必要がある場合。
* クエリを実行する前に、追加の操作を実行する必要があります(接続の確立、アクセス許可の確認など)。
では、どのようにカスタムクラスクエリを作成しますか? まず、クエリのワークフロー全体(初期化から破棄まで)を実装する 4 つのメソッドを定義する必要があります。
* queryName — クエリに関する情報を提供します(基本クラスクエリと同様)
* queryName**Execute** — クエリを作成します
* queryName**Fetch** — クエリの次のレコードの結果を取得します
* queryName**Close** — クエリを破棄します
次に、これらのメソッドをさらに詳しく分析します。
**queryName メソッド**
queryName メソッドはクエリに関する情報を提供します。
* タイプ: %Query
* 本文を空白のままにします。
* 出力結果の名前とデータタイプに関する情報を含む ROWSPEC パラメーターをフィールドの順序と共に定義します。
* (任意)フィールドに ID が含まれている場合、番号順に対応する CONTAINID パラメーターを定義します。 ID を返さない場合は、CONTAINID に値を割り当てないでください。
例えば、新しい永続クラス Utils.CustomQuery のすべてのインスタンスを 1 つずつ出力する AllRecords クエリ(queryName = AllRecords、メソッドは単に AllRecords と呼ばれる)を作成してみましょう。 まず、新しい永続クラス Utils.CustomQuery を作成します。
Class Utils.CustomQuery Extends (%Persistent, %Populate){
Property Prop1 As %String;
Property Prop2 As %Integer;
}
次に、AllRecords クエリを書きます。
Query AllRecords() As %Query(CONTAINID = 1, ROWSPEC = "Id:%String,Prop1:%String,Prop2:%Integer") [ SqlName = AllRecords, SqlProc ]
{
}
**queryNameExecute メソッド**
queryNameExecute メソッドはクエリを完全に初期化します。 このメソッドのシグネチャは次のとおりです。
ClassMethod queryNameExecute(ByRef qHandle As %Binary, args) As %Status
説明:
* qHandle はクエリ実装の他のメソッドとの通信に使用されます。
* このメソッドは、qHandle を後で queryNameFetch メソッドに渡す状態に設定する必要があります。
* qHandle は OREF、変数、または多次元変数に設定できます。
* args はクエリに渡される追加のパラメーターです。 必要な数の引数を追加できます(または引数をまったく使用しないでください)。
* このメソッドはクエリの初期化ステータスを返します。
では、再び例に戻りましょう。 複数の方法で範囲内を自由に反復処理できます(以下でカスタムクエリの基本的な処理方法を説明します)。ただし、この例では関数 $Order を使用してグローバルを反復処理します。 この場合、qHandle は現在の ID を格納します。追加の引数は必要ないため、arg 引数は必要ありません。 結果は次のようになります。
ClassMethod AllRecordsExecute(ByRef qHandle As %Binary) As %Status {
Set qHandle = "" Quit $$$OK
}
**queryNameFetch メソッド**
queryNameFetch メソッドは、単一の結果を $List 形式で返します。 このメソッドのシグネチャは次のとおりです。
ClassMethod queryNameFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = queryNameExecute ]
説明:
* qHandle はクエリ実装の他のメソッドとの通信に使用されます。
* クエリが実行されると、qHandleには queryNameExecute または queryNameFetch の以前の呼び出しによって指定された値が割り当てられます。
* すべてのデータが処理されると、レコードが値 %List または空の文字列に設定されます。
* データの終端に達したら、AtEnd が 1 に設定されます。
* PlaceAfter キーワードは、int コードでのメソッドの位置を識別します。 "Fetch" メソッドは "Execute" メソッドの後に配置する必要がありますが、これは 静的 SQL(つまり、クエリ内の カーソル)にのみ重要です。
一般に、このメソッド内では次の処理が実行されます。
1. データの終端に達したかどうかを確認します。
2. まだデータが残っている場合は新しい %List を作成し、Row 変数に値を割り当てます。
3. それ以外の場合は、AtEnd を 1 に設定します。
4. 次の結果を取得するために qHandle を準備します。
5. ステータスを返します。
この例では次のようになります。
ClassMethod AllRecordsFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status {
#; ^Utils.CustomQueryD を反復する
#; qHandle に次の id を書き込み、新しい id を持つグローバルの値を val に書き込む
Set qHandle = $Order(^Utils.CustomQueryD(qHandle),1,val)
#; 残っているデータがあるかどうかを確認する
If qHandle = "" {
Set AtEnd = 1
Set Row = ""
Quit $$$OK
}
#; 残っていなければ %List を作成する
#; val = $Lb("", Prop1, Prop2) Storage の定義を参照
#; Row =$lb(Id,Prop1, Prop2) AllRecords リクエストについては ROWSPEC を参照
Set Row = $Lb(qHandle, $Lg(val,2), $Lg(val,3))
Quit $$$OK
}
**queryNameClose メソッド**
queryNameClose メソッドはすべてのデータが取得された時点でクエリを終了します。 このメソッドのシグネチャは次のとおりです。
ClassMethod queryNameClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = queryNameFetch ]
説明:
* Caché は queryNameFetch メソッドの最後の呼び出しの後にこのメソッドを実行します。
* つまり、クエリのデストラクタとも言い換えることができます。
* したがって、その実装ではすべての SQL カーソル、クエリ、ローカル変数を破棄する必要があります。
* このメソッドは現在のステータスを返します。
この例では、ローカル変数 qHandle を削除する必要があります。
ClassMethod AllRecordsClose(ByRef qHandle As %Binary) As %Status {
Kill qHandle
Quit $$$OK
}
以上です! クラスをコンパイルすると、基本クラスクエリと同様に %SQL.Statement から AllRecords クエリを使用できるようになります。
## カスタムクエリの反復ロジック手法
では、カスタムクエリにはどのような手法を使用できるのでしょうか? 一般的には、次の 3 つの基本的な手法があります。
* グローバルによる反復
* 静的 SQL
* 動的 SQL
**グローバルによる反復**
この手法は、グローバルによる反復に $Order などの関数を使用することを基本にしています。 この手法は次の場合に使用できます。
* データが(クラスなしで)グローバルに保存されている場合。
* コード内の glorefs の数を減らしたい場合。
* 結果をグローバルの添え字で並べ替える必要がある/並べ替え可能な場合。
**静的 SQL**
この手法は、カーソルと静的 SQL を基本にしています。 この手法は次の目的で使用されます。
* int コードの可読性を高める。
* カーソルの処理を簡単にする。
* コンパイルプロセスの高速化(静的 SQL はクラスクエリに含まれるため、コンパイルは 1 回だけ実行されます)。
注意事項:
* %SQLQuery タイプのクエリから生成されたカーソルには、Q14 などのように自動的に名前が付けられます。
* クラス内で使用されるすべてのカーソルは、異なる名前を持つ必要があります。
* エラーメッセージは、名前の末尾に追加の文字があるカーソルの内部名が関係しています。 例えば、カーソル Q140 のエラーは実際にはカーソル Q14 によって引き起こされたものです。
* PlaceAfter を使用し、カーソルが宣言箇所と同じ int ルーチンで使用されるようにしてください。
* INTO は FETCH と組み合わせて使用する必要がありますが、DECLARE とは組み合わせないでください。
Utils.CustomQuery の 静的 SQL の例:
Query AllStatic() As %Query(CONTAINID = 1, ROWSPEC = "Id:%String,Prop1:%String,Prop2:%Integer") [ SqlName = AllStatic, SqlProc ]
{
}
ClassMethod AllStaticExecute(ByRef qHandle As %Binary) As %Status
{
&sql(DECLARE C CURSOR FOR
SELECT Id, Prop1, Prop2
FROM Utils.CustomQuery
)
&sql(OPEN C)
Quit $$$OK
}
ClassMethod AllStaticFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = AllStaticExecute ]
{
#; INTO は FETCH と共に使用する必要あり
&sql(FETCH C INTO :Id, :Prop1, :Prop2)
#; データの終端に達したかどうかを確認する
If (SQLCODE'=0) {
Set AtEnd = 1
Set Row = ""
Quit $$$OK
}
Set Row = $Lb(Id, Prop1, Prop2)
Quit $$$OK
}
ClassMethod AllStaticClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = AllStaticFetch ]
{
&sql(CLOSE C)
Quit $$$OK
}
**動的 SQL**
この手法は、他のクラスクエリと動的 SQL を基本にしています。 この手法は、複数のネームスペースで SQL クエリを実行する、クエリを実行する前に権限を昇格するなどの SQL クエリ自体以外の追加処理を実行する必要がある場合に適切です。
Utils.CustomQuery の動的 SQL の例:
Query AllDynamic() As %Query(CONTAINID = 1, ROWSPEC = "Id:%String,Prop1:%String,Prop2:%Integer") [ SqlName = AllDynamic, SqlProc ]
{
}
ClassMethod AllDynamicExecute(ByRef qHandle As %Binary) As %Status
{
Set qHandle = ##class(%SQL.Statement).%ExecDirect(,"SELECT * FROM Utils.CustomQuery")
Quit $$$OK
}
ClassMethod AllDynamicFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status
{
If qHandle.%Next()=0 {
Set AtEnd = 1
Set Row = ""
Quit $$$OK
}
Set Row = $Lb(qHandle.%Get("Id"), qHandle.%Get("Prop1"), qHandle.%Get("Prop2"))
Quit $$$OK
}
ClassMethod AllDynamicClose(ByRef qHandle As %Binary) As %Status
{
Kill qHandle
Quit $$$OK
}
## 代替手法:%SQL.CustomResultSet
%SQL.CustomResultSet クラスからサブクラス化してクエリを作成することもできます。 この手法のメリットは次のとおりです。
* 若干の速度改善
* すべてのメタデータがクラス定義から取得されるため、ROWSPEC が不要であること
* オブジェクト指向の設計原則に準拠できること
%SQL.CustomResultSet クラスのサブクラスからクエリを作成するには、次の手順を実行してください。
1. 結果のフィールドに対応するプロパティを定義します。
2. クエリコンテキストが格納される private プロパティを定義します。
3. コンテキストを開始する %OpenCursor メソッド(queryNameExecute と同様)をオーバーライドします。 エラーが発生時に %SQLCODE と %Message も設定します。
4. 次の結果を取得する %Next メソッド(queryNameFetch と同様)をオーバーライドします。 プロパティを入力します。 このメソッドはすべてのデータが処理された場合に 0 を返し、一部のデータがまだ残っている場合に 1 を返します。
5. 必要に応じて %CloseCursor メソッド(queryNameClose と同様)をオーバーライドします。
Utils.CustomQuery の %SQL.CustomResultSet の例:
Class Utils.CustomQueryRS Extends %SQL.CustomResultSet
{
Property Id As %String;
Property Prop1 As %String;
Property Prop2 As %Integer;
Method %OpenCursor() As %Library.Status
{
Set ..Id = ""
Quit $$$OK
}
Method %Next(ByRef sc As %Library.Status) As %Library.Integer [ PlaceAfter = %Execute ]
{
Set sc = $$$OK
Set ..Id = $Order(^Utils.CustomQueryD(..Id),1,val)
Quit:..Id="" 0
Set ..Prop1 = $Lg(val,2)
Set ..Prop2 = $Lg(val,3)
Quit $$$OK
}
}
これは、次のように Caché Object Script コードから呼び出すことができます。
Set resultset= ##class(Utils.CustomQueryRS).%New()
While resultset.%Next() {
Write resultset.Id,!
}
また、SAMPLES ネームスペースでは、Samples.Person のクエリを実装する Sample.CustomResultSet クラスという別の例を使用することもできます。
## 最後に
カスタムクエリは、Caché Object Script コードから SQL 式を分離し、純粋な SQL では難しすぎる可能性がある高度な動作を実装するのに役立ちます。
## 参考情報
クラスクエリ
グローバルによる反復
静的 SQL
動的 SQL
%SQL.CustomResultSet
Utils.CustomQuery クラス
Utils.CustomQueryRS クラス
この記事の執筆にご協力いただいた [Alexander Koblov](https://community.intersystems.com/user/alexander-koblov) 氏に感謝します。
記事
Toshihiko Minamoto · 2020年9月14日
*
この記事は、Caché 以前の歴史に関するかなり個人的な見方を書いたものです。
過去の記事で紹介された [Mike Kadow](https://community.intersystems.com/user/mike-kadow-0) 氏の素晴らしい著書に対抗するつもりはありません。
私たちの歴史的背景は異なるため、この記事は過去に対する別の視点を生み出すことを意図しています。
全体的な話は、1966 年に **MGH**(マサチューセッツ総合病院)で 8K のメモリ(18 ビットワード)[_現在 = 18K バイト_] を搭載した **PDP-7**(シリアル番号#103)
が予備のシステムとして使用されたことから始まります。
「シリアル番号 103 は、現在 [2014] は MGH のコックスがんセンターの敷地になっている取り壊されたセイヤービルの地下にありました。」「Octo Barnett の指導の下、Neil Papparlardo と Curt Marble がこのマシンで最初のソフトウェアを開発し、リリースしました。」 彼らはこのソフトウェアを MUMPS と名付けました。 (引用元)
PDP-7
言語自体は古い形式の Basic にかなり近いものでした。
しかし、他のプログラミング言語に比べて大幅に改善されている点がありました。
* その**画期的なアイデア**は、ファイルシステムを処理する必要なしに永続的なデータを格納および取得することでした。
これは、利用可能なメモリの 30 %以上を容易に消費し、ソートやインデックス付けに対応していない
他のシステムと比較すると、当時はものすごく先進的なものでした。
* (ALGOL、FORTRAN のように)強力なデータ型や名前によって強制されるデータ型がない。
これら(データ型の制約)によって形式上のエラーと変換の原因が無限に存在することになります。
* 構造が固定されていない動的(疎な)配列とメモリ内に事前に割り当てられた半分空の空間がある。
* 可変長の構造化インデックス(添え字)で永続的なデータにインデックスを付けることで
ソート、グループ化、サブグループ化などを簡単にしている。
これを COBOL、FORTRAN、PL/1 の古いコードと比較すると、この革命の規模がいかに大きいかわかるでしょう。
この新しいソフトウェアは PDP-11に至るまでの急速なハードウェアの発展と共に進化し、
最終的には MUMPS 4b として知られるようになりました。
1978 年は注目に値する年でした。- InterSystems が Terry Ragon によって設立されました。- DEC が初の VAX-11 クラスタを導入しました(確かカーネギーメロン大学で)。- DEC が DSM-11(Digital Standard Mumps)を完成させました。さらに、当時の最新標準規格に従いつつストレージのパフォーマンスを劇的に改善する新しい Global モジュールがありました。これは、データベースの名を冠した他のどの製品よりも圧倒的に性能が優れていました。この Global モジュールの作成者は、国際的な経験を持つ優秀なエンジニアである Terry Ragon でした。- 私自身も 1978 年に DSM-11 のセールス兼サポートエンジニアとして DEC に入社し、メイナードでの最初のサポート向けトレーニングで Terry に会いました。
当時の DEC は新しい VAX-11 と VAX-Cluster に完全に舞い上がっていました。
新しい高性能 DB は無視され、その能力は完全に誤解されていました。
新しいハードウェアを有効活用するために DSM を VAX でネイティブに使いたいというソフトウェア開発者の要望はすべて無視されていました。
このように顧客の要望がいつまでも無視され続けていたことが、私が自身の顧客から誘われるきっかけになりました。
「対応してもらえないのなら、私たちと一緒にやりましょう!」[このような OS をゼロから作成するオファーはどのくらいありますか?]
私は誘いを断り切れず、ベアボーンの VAX-750 でゼロから顧客と一緒に OS を書き上げました。
この OS は VISOS と名付けられ、サポートされている VAX のモデルが存在する間は生き残っていました。
しばらくして、DEC は DSM を VMS の上にレイヤードプロダクトとして発表しました。
当初、性能は基盤となる RMS によって決まっており、ハードウェアの処理能力の向上は反映されていませんでした。
私は関心を失い、それ以降のことはもう気にしませんでした。
数年後、DEC が愛されていなかった製品である DSM を InterSystems に売却したことは最高の出来事だと思っています。
ほどなくして DEC は自身を売却することになりました。
私は 20 年後に InterSystems に入社したとき、Caché の中で再び自分が実装していた部分をたくさん見つけました。
そのため、私は故郷にいるようなとても温かい気持ちを味わうことができたのです。
現在の Caché はその前身からは大きく変わっていますが、ソースには互換性があります。
Globals の力はまだ残っているのです。 性能面で競合する DB を凌駕できない事例はほとんど
存在しないかもしれません。 数多くの中から私が気に入っている例をご紹介します。
欧州宇宙機関(ESA)が実行している GAIA プロジェクト
この投稿は、技術的な歴史と個人的な物語の一部を間違いなくかなり個人的な視点で執筆したものです。
ご質問がある方や、私の誤りを正す必要があると感じた方は遠慮無くご連絡ください。
私はウィーン(オーストリア)にいるため、遠く離れた天の川の境界から
ケンブリッジ、メイナード、ボストンでの決定を見ているような感覚を常に抱いていました。
記事
Toshihiko Minamoto · 2021年3月15日
InterSystems IRIS では、情報を格納する「グローバル」というユニークなデータ構造をサポートしています。 基本的に、グローバルとは、マルチレベルのインデックスを持つ永続配列であり、トランザクションの実行やツリー構造のスピーディなトラバーサルといった機能が備えられているほか、ObjectScript として知られるプログラミング言語にも対応しています。
ここから先、少なくともコードサンプルについては、グローバルの基礎を理解されているという想定のもとに話しを進めていきます。
[グローバルはデータを保存するための魔法の剣です パート1 ](https://jp.community.intersystems.com/node/476486)
[グローバルはデータを保存するための魔法の剣ですパート2 - ツリー](https://jp.community.intersystems.com/node/477521)
[グローバルはデータを保存するための魔法の剣です パート3 - 疎な配列](https://jp.community.intersystems.com/node/477586)
グローバルは、普通のテーブルとは全く異なる構造でデータを格納し、OSI モデルの下位層で動作します。 それでは、グローバルを使ったトランザクションとはいかなるもので、どのような特性が見られるのでしょうか。
リレーショナルデータベースの理論では、ACID テスト ([Wikipedia で ACID を参照する](https://ja.wikipedia.org/wiki/ACID_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E7%A7%91%E5%AD%A6))) に合格するトランザクションこそが、適切に実装されたトランザクションとされています。
* _不可分性_: トランザクションで発生する変更内容がすべて記録されるか、そのいずれも記録されない。 [Wikipedia で不可分性 (データベースシステム) を見る](https://ja.wikipedia.org/wiki/ACID_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E7%A7%91%E5%AD%A6)#%E4%B8%8D%E5%8F%AF%E5%88%86%E6%80%A7(Atomicity))。
* _一貫性_: トランザクションが完了した後、データベース内部の論理状態が一貫している。 いろいろな意味で、この要件はプログラマーに適用されるものですが、SQL データベースの場合では、外部キーにも適用されます。
* _分離性_: 並列に実行されるトランザクションの結果はお互いを影響しない。
* _永続性 (あるいは持続性)_: トランザクションが完了した後に、OSI モデルの物理層の問題 (電源障害など) が発生しても、トランザクションで変更されたデータには影響しない。
グローバルは、非リレーショナルなデータ構造です。 メモリーフットプリントを最小限に抑えながらハードウェアの超高速作業をサポートできるようにデザインされています。 それでは、IRIS/docker-image を使って、トランザクションがグローバルに実装される仕組みを見てみましょう。
## 1. 不可分性
3 の値を一緒にデータベースに保存する必要があるが、そうならない場合はそのいずれも保存されないという状況について考えます。
不可分性を一番手っ取り早く確認するには、ターミナルで次のコードを入力します。
Kill ^a
TSTART
Set ^a(1) = 1
Set ^a(2) = 2
Set ^a(3) = 3
TCOMMIT
最後に次を入力します。
ZWRITE ^a
結果は以下のようになるはずです。
^a(1)=1
^a(2)=2
^a(3)=3
予想とおり、不可分性を確認できました。 では、わざとエラーを導入してタスクを少し複雑にします。トランザクションが部分的に保存されるのか、全く保存されないのかを見てみましょう。 まずは、先ほどと同じように不可分性を確認します。
Kill ^a
TSTART
Set ^a(1) = 1
Set ^a(2) = 2
Set ^a(3) = 3
今回は、ここで docker kill my-iris というコマンドを使い、コンテナを強制的に終了します。これにより SIGKILL (即座にプロセスを停止する) シグナルが送られるため、電源を強制的にオフにしているようなものです。 コンテナを再起動してから、グローバルの中身をチェックして、結果を確認します。 トランザクションは部分的に保存されているでしょうか?
ZWRITE ^a
何も表示されませんでした
いいえ、何も保存されませんでした。 これにより、アクシデントでサーバーが停止する場合、IRIS データベースでは不可分性が保証されることが分かりました。
では、変更内容を意図的にキャンセルするとしたらどうでしょう? 次のように rollback コマンドを使って試してみます。
Kill ^a
TSTART
Set ^a(1) = 1
Set ^a(2) = 2
Set ^a(3) = 3
TROLLBACK 1
ZWRITE ^a
Nothing got out
またしても、何も保存されませんでした。
## 2. 永続性
グローバルは、リレーショナルテーブルよりも低い層でデータを格納する構造であることを覚えていますか?また、グローバルデータベースでは、インデックスもグローバルとして格納されます。 従い、永続性の要件を満たすには、グローバルノードの値が変更される同じトランザクションにインデックの変更も含める必要があります。
例えば、^person というグローバルがあり、それに個人情報を格納するとします。キーにはソーシャルセキュリティ番号 (SSN) を使用します。
^person(1234567, 'firstname') = 'Sergey'
^person(1234567, ‘lastname’) = ‘Kamenev’
^person(1234567, ‘phone’) = ‘+74995555555
...
以下のように、^index というキーを作成し、ラストネームだけ、もしくはファーストネームとラストネームの組み合わせを使って、素早く検索できるようにしました。
^index(‘Kamenev’, ‘Sergey’, 1234567) = 1
データベースの永続性を維持するには、person を以下のように追加する必要があります。
TSTART
^person(1234567, ‘firstname’) = ‘Sergey’
^person(1234567, ‘lastname’) = ‘Kamenev’
^person(1234567, ‘phone’) = ‘+74995555555
^index(‘Kamenev’, ‘Sergey’, 1234567) = 1
TCOMMIT
従い、person を削除する場合は、以下のトランザクションを使う必要があります。
TSTART
Kill ^person(1234567)
Kill ^index(‘Kamenev’, ‘Sergey’, 1234567)
TCOMMIT
つまり、グローバルのような下位層の格納形式を使う場合、どのようなロジックを使ってアプリケーションの永続性の要件を満たすかは、プログラマー次第ということです。
幸い、IRIS にはトランザクションを整理して、アプリケーションの永続性を保証するためのコマンドが備えられています。 SQL が使用される場合、IRIS は内部でこれらのコマンドを実行して、INSERT、UPDATE、DELETE 式が実行されるときに、基となるグローバルのデータ構造を持続します。 もちろん、トランザクションを開始および停止する SQL コマンドは、IRIS SQL にも備えられているので、(SQL) アプリケーションロジックに活用することができます。
## 3. 分離性
ここからが本番です。 多くのユーザーが同時に同じデータベースにアクセスして、同じデータを変更するとしましょう。 多くのデベロッパーが同じコードリポジトリにアクセスし、多くのファイルの変更内容を同時にコミットしようと試みる状況に似ています。
データベースはすべてをリアルタイムに処理しなくてはいけません。 大手企業なら通常はバージョンコントロール (ブランチのマージや競合解決の管理など) の担当者がいて、かつ データベースはこれをリアルタイムに処理する必要があることを考えると、その問題の複雑さや、データベースとその機能を支えるコードを適切に設計することが大切なのは言うまでもありません。
データベースは、ユーザーの操作が意味することを理解できなければ、ユーザーが同じデータを操作する際に起こる競合を回避することもできません。 他のトランザクションと矛盾するトランザクションを 1 つキャンセルするか、それらを順番に実行することしかできません。
また、トランザクションの実行中 (コミットの前) は、データベースの状態の一貫性が失われている能性もあります。 一貫性を失ったデータベースの状態に他のトランザクションがアクセスできるのはよくありません。 しかし、リレーショナルデータベースでは、スナップショットを作成したり、複数バージョンの行を使用したりするなど、アクセスできてしまう方法がたくさんあります。
複数のトランザクションが並列に実行される場合は、お互いを干渉しないことが大切です。 それを確保するのが分離性です。
SQL では、分離性は分離する程度の順に 4 つのレベルで定義されます。 以下がその 4 つのレベルです。
* READ UNCOMMITTED
* READ COMMITTED
* REPEATABLE READ
* SERIALIZABLE
では、それぞれのレベルを一つずつ見ていきましょう。 各レベルの実装コストは、スタックを上がるにつれてほぼ指数関数的に増加していきますので、ご注意ください。
**READ UNCOMMITTED** は、分離の一番低いレベルですが、一番速いレベルでもあります。 トランザクションは、別のトランザクションによりコミットされた変更内容を読み取ることができます。
**READ COMMITTED** は、次の分離レベルで、譲歩することを意味します。 トランザクションは、コミットの前にお互いの変更を読み取ることはできませんが、コミットの後ならどの変更でも読み取ることができます。
長時間に渡って実行されるトランザクション (T1) があり、その間に T1 と同じデータを操作するトランザクション T2、T3 ... Tn がそれぞれでコミットしたとします。 このような場合は、T1 のデータをリクエストする度に異なる結果が得られる可能性があります。 これは Non-Repeatable Read (非再現リード) と呼ばれています。
次の分離レベルは、**REPEATABLE READ** です。データの読み取りをリクエストすると、その都度結果のスナップショットがとられるため、ここではもはや非再現リードは起りません。 同じトランザクションの実行中に同じデータがもう一度リクエストされることがあれば、スナップショットが使用されます。 但し、この分離レベルでは、ファンタムデータ (並列に実行されていた別のトランザクションによってコミットされた新しい文字列) が読み取られる可能性があります。
一番高い分離レベルは、**SERIALIZABLE** です。 トランザクションで使用 (読み取りまたは変更) されたデータに他のトランザクションがアクセスできるのは、最初のトランザクションが終了した後に限定されるという特徴があります。
まずは、トランザクションのあるスレッドとないスレッドとの間で操作が分離されているかどうかを確認してみましょう。 ターミナルを 2 つ開いて、以下を入力します。
Kill ^t Write ^t(1) 2
TSTART Set ^t(1)=2
分離はされていません。 片方のスレッドはトランザクションを開くと、もう片方のスレッドの動作を見ることができます。
それでは、異なるスレッドで実行中のトランザクションがお互いの中の状況を見れるかどうかを確認しましょう。 ターミナルウィンドウを 2 つ開き、2 つのトランザクションを並列に実行します。
Kill ^t TSTART Write ^t(1) 2
TSTART Set ^t(1)=2
画面に A 3 が表示されます。 ここでは、一番シンプルで一番速い分離レベル READ UNCOMMTTED が設定されています。
原則として、グローバルのような常にスピードを優先する下位層のデータ表現手段では、このレベルが主流となっています。 IRIS SQL では、トランザクションの異なる分離レベルを選択できますが、直接グローバルを操作する時にもっと高い分離レベルが必要になったらどうすればよいでしょう?
ここで、分離レベルの目的とそれぞれの仕組みについて考える必要があります。 例えば、低い分離レベルは、データベースを高速化するための譲歩を目的にしています。
最高の分離レベルを提供する SERIALIZABLE では、並列に実行されたトランザクションの結果がそれらを順に実行した場合の結果と同じになることが保証されます。 これにより、衝突を完全に防ぐことができます。 これは、ObjectScript で適切にロックを使用しても実現できる上に、適用方法も多数あります。 つまり、LOCK コマンドを使えば、普通のロックやインクリメンタルロックを作成したり、ロックを複数個作成することもできます。
それでは、ロックを使って異なる分離レベルを作る方法を見てみましょう。 ObjectScript では、[LOCK オペレーター](https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_clock)を使います。 このオペレーターは、データを変更するのに必要な排他ロックに限らず、共有ロックと呼ばれるロックも許可します。 共有ロックは、複数のスレッドがデータを読み取る目的で同時にアクセスできるロックであり、そのデータが読み取りプロセス中に他のプロセスによって変更されることはありません。
ロック方式に関する詳細については、[「ロックと並行処理の制御」](https://docs.intersystems.com/irislatestj/csp/docbook/DocBook.UI.Page.cls?KEY=ALOCK)と題した記事をお読みください。 ツーフェーズロック方式の詳細については、Wikipedia で[「ツーフェーズロック」](https://ja.wikipedia.org/wiki/%E3%83%84%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA%E3%83%AD%E3%83%83%E3%82%AF)と題された記事をお読みください。
難しいのは、トランザクションの実行中に、データの状態の一貫性が失われ、そのデータが他のプロセスに表示されてしまうという点です。 これはどうすれば回避できるのか? この例では、ロックを使って、データベースの状態が一貫して持続される可視性ウィンドウを作成します。 可視性ウィンドウには、ロックを使ってアクセスします。
同じデータに使われているロックは、再利用できるほか、複数のプロセスによる取得が可能です。 これらのロックを使うことで、データが他のプロセスにより変更されるのを防ぎます。 つまり、データベースの状態を一貫させるためのウィンドウを形成するのに使用されるというわけです。
一方の排他ロックは、データを変更するときに使用されるもので、一度に 1 つのプロセスしか取得できません。
排他ロック方式を使用できるシナリオは、2 つあります。 1 つ目は、対象となるデータに対し他のプロセスがロックを取得していないため、どのプロセスでもアクセスできるという場合。 2 つ目は、対象となるデータに対し共有ロックを取得し、かつ排他ロックを最初にリクエストしたプロセスだけがそのデータにアクセスできるという場合。

可視性ウィンドウが狭ければ狭いほど、他のプロセスが待機する時間が長くなる一方で、その中にあるデータベースの状態の一貫性は高まります。
**READ COMMITTED** では、他のスレッドがコミットしたデータしか見えないようになります。 他のトランザクションのデータがまだコミットされていない場合は、古いバージョンが表示されます。 このおかげで、ロックがリリースされるのを待たずに、作業を並列化することができます。
IRIS では、データの古いバージョンを見るには、特殊な裏技が必要になるので、ロックで何とか対処するしかありません。 共有ロックを使って、一貫性が維持されているポイントでのみデータの読み取りを許可する必要があります。
例えば、複数のユーザー「^person」で構成されるデータベースがあり、ユーザー間で資金の送金が行われるとします。 以下のコードは、person 123 から person 242 に資金が送金されるポイントを示しています。
LOCK +^person(123), +^person(242)
TSTART
Set ^person(123, amount) = ^person(123, amount) - amount
Set ^person(242, amount) = ^person(242, amount) + amount
TCOMMIT
LOCK -^person(123), -^person(242)
金額が差し引かれる前の段階で、person 123 に送金のリクエストが出るポイントでは、(デフォルトで) 排他ロックが取得されている必要があります。
LOCK +^person(123)
Write ^person(123)
ですが、ユーザーの個人アカウントのアカウント状況を表示する必要がある場合は、共有ロックを使うか、ロックを一切使わないという選択肢があります。
LOCK +^person(123)#”S”
Write ^person(123)
LOCK -^person(123)#”S”
但し、データベースの操作がほぼ瞬間的に実行されることを許可するのであれば (グローバルはリレーショナルテーブルよりもずっと下位のレベルの構造であることをお忘れなく)、より高い分離レベルが優先されるのでこのレベルはさほど必要ではなくなります。
以下は、READ COMMITTED の完全な例です。
LOCK +^person(123)#”S”, +^person(242)#”S”
Read data (сoncurrent committed transactions can change the data)
LOCK +^person(123), +^person(242)
TSTART
Set ^person(123, amount) = ^person(123, amount) - amount
Set ^person(242, amount) = ^person(242, amount) + amount
TCOMMIT
LOCK -^person(123), -^person(242)
Read data (сoncurrent committed transactions can change the data)
LOCK -^person(123)#”S”, -^person(242)#”S”
**REPEATABLE READ** は、2 番目に高い分離レベルです。 このレベルでは、1 つのトランザクションでデータが複数回読み取られ、その都度同じ結果が出ること、かつ並列に実行されているトランザクションがそのデータを変更できることを許可します。
分離レベルを確実に REPEATABLE READ にするには、データに対し排他ロックを取得します。それにより、分離レベルは自動的に SERIALIZABLE に引き上げられます。
LOCK +^person(123, amount)
read ^person(123, amount)
その他の操作 (並列ストリームは ^person(123, amount) を変更しようと試みますができません)
change ^person(123, amount)
read ^person(123, amount)
LOCK -^person(123, amount)
ロックがコンマで区切られている場合は、連続的に取得されていることを意味します。 ですが、以下のようにリストアップされている場合は、一斉にアトミックに取得されます。
LOCK +(^person(123),^person(242))
SERIALIZABLE は、最も高い分離レベルであり、コストも一番高くなります。 上の例で行ったように、従来のロックを操作する場合は、同じデータを持つすべてのトランザクションが連続的に実行されるようにロックを設定する必要があります。 このアプローチでは、ほぼすべてのロックが排他ロックである必要があり、パフォーマンスを確保するためにグローバルの最も小さいフィールドに対し取得される必要もあります。
^person グローバルから金額を差し引くという場合、SERIALIZABLE 以外のレベルは使えません。 資金の消費は、あくまで連続的なアクションである必要があり、そうでなければ同じ金額が複数回も消費されることになります。
## 4. 永続性
docker kill my-iris コマンドを使い、コンテナの hard cut-off をテストしたところ、 データベースはこれらのテストに対して良い結果を出し、 問題は一切見られませんでした。
## グローバルとロックを管理するためのツール
IRIS Management ポータルでご紹介している以下のツールがお役に立つかもしれません:
[ロックを管理](http://localhost:52773/csp/sys/op/%25CSP.UI.Portal.Locks.zen)。
[グローバル](http://localhost:52773/csp/sys/exp/%25CSP.UI.Portal.GlobalList.zen?%24NAMESPACE=USER)。
## 結論
InterSystems IRIS は、グローバルを使ったアトミックかつ永続的なトランザクションをサポートしています。 データベースとグローバルの一貫性を確保するには、ある程度のプログラミングやトランザクションが必要です。それは、外部キーなどの複雑な構造が組み込まれていないためです。
ロックを取得せずにグローバルを使うのは、READ UNCOMMITTED の分離レベルを使うのと同じことですが、ロックを使えばそのレベルを SERIALIZABLE に引き上げることができます。 グローバルを使って実現可能な正確性およびトランザクションの処理速度は、プログラマーのスキルと意図によって大きく左右します。 データを読み取るときに、共有ロックが使用される幅が広ければ広いほど、それだけ分離レベルは高くなります。 また、排他ロックが使用される幅が狭ければ狭いほど、それだけトランザクションの処理速度も速くなります。
お知らせ
Seisuke Nakahashi · 2023年11月13日
2023年5月に発表し、Global Summit 2023 における多くのプレゼンテーションや活発な議論をへて、インターシステムズは Intersytems Studio の非推奨に関する計画を引き続き進めています。(非推奨とは、インターシステムズが積極的に開発しなくなった、より優れたオプションが存在する機能またはテクノロジを示します)
InterSystems Studio は 2023.2 で非推奨となりましたが、引き続き 2023.3 および 2024.1 で提供されます。2024.1 は Windows キットの一部として Studio が含まれる最後のリリースとなり、それ以降の InterSystems IRIS バージョンに接続できる唯一の Studio バージョンとなります。2024.1 に含まれる Studio は、単独のキットとして WRC コンポーネント・ダウンロードページ から引き続き入手いただける予定にしています。
これまで同様、 InterSystems ObjectScript エクステンション を利用した VS Code は、あらゆる InterSystems 製品開発におすすめのツールです。まずは Studio 移行ガイド をご参照ください。最近 VS Code を使っていなかった方は、新機能 XML インポート/エクスポート によって VS Code への移行がより簡単になっているので、ぜひご確認ください。
6月以降さまざまなフィードバックをお寄せいただき、本当にありがとうございます。みなさまからの経験談やチャレンジをお聞きするのがいつも嬉しいです。みなさまが、私たちの新しいフラッグシップ IDE をより良くする仲間になってくださるのを楽しみにしています。
お知らせ
Mihoko Iijima · 2022年1月28日
開発者の皆さん、こんにちは!
次の InterSystems プログラミングコンテストのお題が発表されました!次は、Python です!
🏆 InterSystems Python Contest 🏆
応募期間: 2022年2月7日~20日
💰 賞金総額: $10K 💰 + さらに賞品を用意予定です!
優勝特
1. Experts Nomination- 審査員から多く票を集めたアプリケーションには、以下の賞金が贈られます。
🥇 1位 - $4,000
🥈 2位 - $2,000
🥉 3位 - $1,000
🌟 4~15位 - $100
2. Community winners - 開発者コミュニティで多く票を集めたソリューションには、以下の賞金が贈られます。
🥇 1st place - $1,000
🥈 2nd place - $750
🥉 3rd place - $500
複数の参加者が同数の票を獲得した場合、全参加者が勝者となり賞金は勝者間で分配されます。
参加資格
どなたでもご参加いただけます!(InterSystems 開発者コミュニティのアカウントを作成するだけでご応募いただけます)
👥 開発者がチームを組んで共同でアプリケーションを作成し、応募することもできます! 1チーム 2~5名 までご参加いただけます。
チームでご応募いただく場合は、アプリケーションの README にチームメンバー名の記載をお忘れなく!!(開発者コミュニティのプロファイルのリンクもお願いします)
コンテストのスケジュー
🛠 2022年2月7日~2022年2月20日 応募期間
✅ 2022年2月21日~27日 投票(1週間)
応募、投票期間中、アップロードしたアプリケーションは改良できます。
2022年2月28日 勝者発表!(US時間に発表します)
コンテストのテーマ
最近リリースされた InterSystems IRIS 2021.1 には、新機能の Embedded Python が含まれ、IRIS のサーバ側コードを Python で記述することもできるようになりました! 今回のコンテストテーマは「Python」です。開発者の皆さん、ぜひ新機能の Embedded Python を使ってみてください!
もちろん、Native API for Python や PEX for Python を利用したアプリケーションの投稿も大歓迎です!
InterSystems IRIS または InterSystems IRIS for Health で Embedded Python または Native API for Python または PEX for Python を使用したオープンソースアプリケーションを投稿してください。
一般的な応募条件:
応募可能なアプリケーション
Open Exchange アプリケーションの新規作成、または既存アプリケーションであっても大幅に改善されているものであればご応募いただけます。
コミュニティの担当チームは、コンテストへの応募を承認する前に申請された全アプリケーションをレビューします。
全てのアプリケーションは IRIS Community Edition 、 IRIS for Health Community Edition 、 IRIS Advanced Analytics Community Edition のいずれかで動作する必要があります。
アプリケーションはオープンソースであり、GitHubで公開されている必要があります。
アプリケーションの README ファイルは、英語で記述してください(日本語で記述したものがあればそのまま掲載いただき、英文の追記をお願いします)。また、インストール手順や、アプリケーションがどのように動作するかの説明、またはビデオデモを含めてください。
Helpful resources
1. Developing Python Applications with InterSystems IRIS:
Learning Path Writing Python Application with InterSystems
Embedded Python ドキュメント(英語)
Native API for Python の使用法
PEX Documentation
日本語ドキュメント(日本語ドキュメントには PEX for Pythonはまだ含まれていません)
Embedded Pythonを簡単にご紹介します
Embedded Python 試してみました
2. For beginners with ObjectScript Package Manager (ZPM):
How to Build, Test and Publish ZPM Package with REST Application for InterSystems IRIS
Package First Development Approach with InterSystems IRIS and ZPM
3. コンテストへの応募方法
4. アプリケーション例
interoperability-python
pex-demo
python-examples
WebSocket
AOC2021
Python Faker
Native APIを使った例(キーバリュー形式で Python / Node.js / Java から IRIS にアクセスできるテンプレート(グラフ構造によくある人物相関図を IRIS で表現しています)
5. ビデオ:
Introduction to Embedded Python
Embedded Python: Bring the Python Ecosystem to Your ObjectScript App
Embedded Python for ObjectScript Developers: Working with Python and ObjectScript Side-By-Side
Embedded Python with Interoperability
InterSystems IRIS Native Python API in AWS Lambda
動画:Python エンジニアが IRIS を使う場合の2つの方法と今後の計画
2021年2月に開催された「InterSystems Japan Virtual Summit 2021」のアーカイブです。PyODBC、Native API、EmbeddedPython の例をご紹介しています(15分45秒~EmbeddedPythonについて解説しています。少し古いバージョンでのご紹介の為、バージョン2021.2で利用できる機能については含まれていません)。
審査及び投票ルール
投票ルールは近日公開します。
皆様からの✨素敵な✨プロジェクトをお待ちしております!コミュニティのコーディングマラソンに参加して、優勝を目指しましょう!(ง`0´)ง
❗️ コンテスト規約については、こちらをご参照ください。❗️
ご応募方法について
以下の応募方法ビデオをご参照ください。
以下、コンテストに応募する迄の手順をご説明します。
コンテスト応募までの流れは以下の通りです(※ビデオでは、3番以降の内容をご紹介しています)。
1、IRISプログラミングコンテスト用テンプレートを使用して、開発環境を準備します。
2、コンテスト用アプリケーションを作成します。
3、コンテストの準備が完了したら、ソースコードをローカルのGitリポジトリへコミットします。
初回コミット時に、Gitの初期設定がないためコミットが失敗することがあります。その場合は、以下のコマンドでGitユーザ名とEmailを設定します。
git config --global user.name "ここにユーザ名"
git config --global user.email "ここにメールアドレス”
4、ローカルのGitリポジトリのコミットが完了したら、リモートのGitリポジトリを作成します。
リポジトリ作成後、リモートリポジトリのURLをコピーします。
5、リモートのGitリポジトリへPushします。
git push ここにリモートのリポジトリのURL
6、OpenExchangeにログインし、アプリケーションを追加します。
※事前にDeveloper communityでユーザアカウントを作成する必要があります。ログイン後、Profile→Applications から Application をクリックし、4 でコピーしたリモートのGitリポジトリのURLを設定します。
アプリケーションを登録すると、画面右上に「Send Approval」のボタンが表示されるので、クリックします。
再度作成したアプリケーションを開くと、「Apply for Contest」ボタンが表示されるので、クリックすると応募が完了します。
Python コンテスト、始まりました 💨
↓紹介記事も追加されています↓是非チェックしてみてください。
Embedded Pythonを簡単にご紹介します
Embedded Python 試してみました
今回のコンテストですが、ObjectScript を使わず Python だけで開発されたアプリケーションには 5ポイントのボーナスポイント が付与されます!(詳しくは、テクノロジーボーナス紹介ページをご参照ください)
お知らせ
Mihoko Iijima · 2022年1月17日
開発者の皆さん、こんにちは!
InterSystems データセットコンテスト の投票結果が発表されました!この記事ではコンテスト受賞者を発表します!
受賞された開発者の皆さん、👏おめでとうございます!🎊
🏆 Experts Nomination -- 特別に選ばれた審査員によって選出されました。
🥇 1位 - $4,000 は、Medical Datasets を開発された @Muhammad.Waseem さんに贈られました。
🥈 2位 - $2,000 は、iris-kaggle-socrata-generator を開発された @José.Pereira さんと @Henrique.GonçalvesDias さんに贈られました。
🥉 3位 - $1,000 は、Health Dataset を開発された @Yuri.Gomes さんに贈られました。
さらに!
🏅 $100 - ApacheLog-Dataset を開発された @Evgeniy.Potapov さんに贈られました。
🏅 $100 - exchange-rate-cbrf を開発された @MikhailenkoSergey さんに贈られました。
🏅 $100 - dataset-finance を開発された @Oliver.Wilms さんに贈られました。
🏅 $100 - openflights_dataset を開発された @Andreas.Schneider さんに贈られました。
🏅 $100 - iris-python-faker を開発された @Dmitry.Maslennikov さんに贈られました。
🏅 $100 - Dataset OEX reviews を開発された @Robert.Cemper1003 さんに贈られました。
🏅 $100 - Dataset Lightweight M:N を開発された @Robert.Cemper1003 さんに贈られました。
🏅 $100 - dataset-covid19-fake-news を開発された @Henry.HamonPereira さんに贈られました。
🏆 Community Nomination - 最も多くの票を獲得したアプリケーションに贈られます。
🥇 1位 - $1,000 は、 iris-kaggle-socrata-generator を開発された @José.Pereira さんと @Henrique.GonçalvesDias さんに贈られました
🥈 2位 - $500 は、Medical Datasets を開発された @Muhammad.Waseem さんに贈られました
🥉 3位 - $250 は、iris-python-faker を開発された @Dmitry.Maslennikov さんに贈られました
🎊 受賞者の皆様、おめでとうございます!👏
今回も、コンテストにご注目いただきありがとうございました!