オブジェクト同期化機能の使用法
ここでは、オブジェクト同期化機能について説明します。この機能を使用すると、不定期的に接続されるシステム上のデータベースにある特定のテーブルを同期できます。
オブジェクトの同期化の概要
オブジェクトの同期化は、InterSystems IRIS® データ・プラットフォームのオブジェクトに使用できるツールのセットです。オブジェクトの同期化により、アプリケーション開発者は、不定期に接続されるシステム上のデータベースを同期化するためのメカニズムをセットアップできます。このプロセスを経て、各データベースのオブジェクトが更新されます。オブジェクトの同期化によって、高可用性を提供する InterSystems IRIS システム・ツールに機能が補足されます。これは、リアルタイムの更新をサポートするためのものではなく、不定期に更新する必要があるシステムで最も役立つ機能です。
例えば、中央のサーバにデータベースのマスタ・コピーがあり、クライアント・マシンにセカンダリ・コピーがある環境に、オブジェクトの同期化の標準アプリケーションがあるとします。各営業員がノート・パソコンに該当のデータベースのコピーを持っている営業用データベースの場合を考えてみましょう。営業員の Mary は、ネットワークに接続していないとき、データベースの自分用のコピーを更新します。彼女が自分のコンピュータをネットワークに接続すると、中央とリモートのデータベースのコピーが同期化されます。これは、時間単位、1 日単位、あるいは任意の間隔で実行できます。
2 つのデータベース間でオブジェクトを同期化するには、それぞれのデータベースをもう一方のデータベースのデータで更新する必要があります。しかし、InterSystems IRIS では、このような双方向での同期はサポートされていません。正確には、一方のデータベースの更新がもう一方のデータベースに送信された後、後者のデータベースの更新が前者のデータベースに送信されます。標準アプリケーションでは、(前述の営業データベースの例のように) 1 つのメイン・データベースと 1 つ以上のローカル・データベースがある場合、更新はまずローカル・データベースからメイン・データベースに送信され、次に、メイン・データベースからローカル・データベースに送信されるようにすることをお勧めします。
オブジェクトの同期化の場合、クライアントとサーバの概念は、慣例に従うという理由のみで存在します。任意の 2 つのデータベースでは、双方向の更新が可能です。2 つ以上のデータベースがある場合、すべてのデータベース (メイン・データベースと個別に同期化するローカル・データベースなど) の更新に使用する方法を選択できます。
この章では、以下の項目について説明します。
GUID
更新が正確に実行されるには、データベースの各オブジェクトを一意に区別できる必要があります。この機能のために、InterSystems IRIS では、各オブジェクト・インスタンスに GUID (Globally Unique ID) を割り当てます。この GUID によって各オブジェクトは例外なく一意に区別可能になります。
GUID は、GUIDENABLED パラメータ値に基づいてオプションで作成されます。GUIDENABLED の値が 1 である場合は、新しい各オブジェクト・インスタンスに GUID が割り当てられます。
以下の例を考えてみます。2 つのデータベースが同期化されて、それぞれのデータベースに同じオブジェクトのセットがあるとします。同期化の後、各データベースに新しいオブジェクトが 1 つ追加されています。オブジェクトの同期化では、この 2 つのオブジェクトが共通の GUID を共有している場合、これらのオブジェクトは状態が異なる同一のオブジェクトと見なされます。各オブジェクトに固有の GUID が割り当てられている場合、これらのオブジェクトは異なるオブジェクトと見なされます。
更新の機能
1 つのデータベースから別のデータベースへの各更新は、トランザクションのセットとして送信されます。これにより、相互依存するオブジェクトすべてが一緒に更新されます。各トランザクションの内容は、ソース・データベースのジャーナルの内容によって異なります。更新には、最後の同期化以降に発生したすべてのトランザクションを限度として、1 つ以上のトランザクションを含めることができます。
以下の状況はアプリケーションで解決します。
-
一意のキーを共有する 2 つのインスタンスの GUID が異なる場合。この 2 つのレコードが単一のオブジェクトを表しているのか、または 2 つの固有のオブジェクトを表しているのかを判別する必要があります。
-
2 つの変更を調整する必要がある場合。この 2 つの変更が共通のプロパティに対して行われたのか、または接点のないプロパティのセットに対して行われたのかを判別する必要があります。
SyncSet および SyncTime オブジェクト
2 つのデータベースを同期化するときは、それぞれが、他方のデータベースにはないトランザクションを含んでいます。以下はその図です。
データベース A とデータベース B は、データベース A のトランザクション 536 とデータベース B のトランザクション 112 で同期化されています。各データベースの後続のトランザクションは、他方のデータベースで更新される必要があります。これを行うために、InterSystems IRIS では SyncSet オブジェクトが使用されます。このオブジェクトには、データベースの更新に使用するトランザクションのリストが含まれています。例えば、データベース A からデータベース B に同期化する場合、SyncSet オブジェクトの既定の内容はトランザクション 547、555、562、および 569 です。同様に、データベース B からデータベース A に同期化する場合、SyncSet オブジェクトの既定の内容は、117、124、130、および 136 です (トランザクションでは連続した番号は使用されません。これは、各トランザクションに複数の挿入、更新、および削除がカプセル化されており、そのそれぞれがその間の番号を使用するためです)。
各データベースには、他方のデータベースとの同期化の履歴があります。このレコードを SyncTime テーブルと呼びます。データベースの場合、次の形式になっています。
Database Namespace Last Transaction Sent Last Transaction Received ------------------------------------------------------------------------------ B User 536 112
各トランザクションと対応している番号はタイム・スタンプではありません。個々のデータベース内でトランザクションを報告した順序を示しています。
データベース A からデータベース B への同期化が完了すると、2 つのデータベースは次のようになります。
トランザクションがデータベース B に追加されるため、そのデータベースで新しいトランザクション番号が付けられます。
同様に、データベース B からデータベース A への同期化によって、データベース A に 117、124、130、および 136 が追加され、新しいトランザクション番号が付きます。
データベース A が発端になるデータベース B のトランザクション (140 ~ 162) により、データベース A が更新されることはありません。これは、B から A への更新には、同期化機能の一部である特別な機能が使用されるためです。これは、以下のように実行されます。
-
データベース内の各トランザクションには、元のデータベースを示すラベルが付けられます。この例では、データベース B のトランザクション 140 にはデータベース A が元のデータベースであることを示すマークが付けられ、トランザクション 136 にはデータベース B が元のデータベースであることを示すマークが付けられています。
-
同期化のための一連のトランザクションを 1 つにまとめた SyncSet.AddTransactions() メソッドでは、特定のデータベースが元となっているトランザクションを除外できます。したがって、B から A に更新する場合、データベース A が元になっているすべてのトランザクションは、既にデータベース B のトランザクション・リストに追加されているために、AddTransactions() によって除外されます。
この機能によって、2 つのデータベースが、互いに同じセットのトランザクションを更新し続けるという無限ループを防止できます。
同期をサポートするためのクラスの変更
オブジェクトの同期化には、サイト間に同じ GUID のデータがある必要があります。既存のデータベースを使用する場合でそのレコードに GUID が割り当てられていないとき、そのデータベース内の各インスタンス (レコード) に GUID を割り当て、各サイトにそのデータベースと一致するコピーがあるようにします。詳細なプロセスは以下のとおりです。
-
同期対象のクラスごとに、OBJJOURNAL パラメータの値を 1 に設定します。
Parameter OBJJOURNAL = 1;
これにより、トランザクションごとのファイリング操作 (挿入、更新または削除) のログ機能を有効化します。この情報は、^OBJ.JournalT グローバルに格納されます。OBJJOURNAL の値に 1 を指定しておくと、ファイリング操作で変更したプロパティ値はシステムのジャーナル・ファイルに格納されます。同期化の際は、同期化を必要とするデータがそのファイルから取得されます。
Note:OBJJOURNAL では、値を 2 に設定することもできます。ただし、この値は特別な場合に限り使用可能です。既定のストレージ・メカニズムを使用するクラス (%Storage.Persistent) に対して使用することはできません。この値が 2 の場合、ファイリング操作で変更したプロパティ値は ^OBJ.Journal グローバルに格納されます。同期化の際は、同期化を必要とするデータがそのグローバルから取得されます。また、グローバルに情報を保存すると、データベースのサイズが急速に増加します。
-
オプションで、JOURNALSTREAM パラメータの値を 1 に設定します。
Parameter JOURNALSTREAM = 1;
既定で、オブジェクトの同期化は、ファイル・ストリームの同期化をサポートしません。JOURNALSTREAM パラメータは、OBJJOURNAL が真のときに、ストリームがジャーナル化されるかどうかを制御します。
-
JOURNALSTREAM が偽で、OBJJOURNAL が真の場合、オブジェクトはジャーナル化されますが、ストリームはジャーナル化されません。
-
JOURNALSTREAM が真で、OBJJOURNAL が真の場合、ストリームはジャーナル化されます。参照オブジェクトが処理されるときに、オブジェクト同期化ツールが、ジャーナル化されたストリームを処理します。
-
-
同期化する各クラスの GUIDENABLED パラメータを 1 に設定します。これによって、InterSystems IRIS によってクラスに GUID を付けて格納することが許可されます。
Parameter GUIDENABLED = 1;
この値が設定されていない場合、同期化が正確に機能しないことに注意してください。また、シリアル・クラスに対しては GUIDENABLED を設定する必要がありますが、埋め込みオブジェクトには設定しないでください。
-
クラスをリコンパイルします。
-
同期化する各クラスに対して、AssignGUID() メソッドを実行して、各オブジェクト・インスタンスにその GUID を割り当てます。
Set Status = ##class(%Library.GUID).AssignGUID(className,displayOutput)
各項目の内容は次のとおりです。
-
className は、GUID ("Sample.Person" など) が割り当てられているインスタンスを含むクラスの名前です。
-
displayOutput は、整数です。ゼロは、出力が表示されないことを示し、ゼロ以外の値は出力が表示されることを示します。
このメソッドは %StatusOpens in a new tab 値を返すので、その値を確認する必要があります。
-
-
各サイトにデータベースのコピーを配置します。
同期の実行
このセクションでは、同期を実行する方法について説明します。更新を提供するデータベースはソース・データベースと呼ばれ、更新を受け取るデータベースはターゲット・データベースと呼ばれます。実際の同期化の方法は、以下のとおりです。
-
2 つのデータベースを同期化するたびに、ソース・データベースのインスタンスに移動します。ソース・データベースで、%SYNC.SyncSet クラスの %New() メソッドを使用して新しい SyncSet を作成します。
Set SrcSyncSet = ##class(%SYNC.SyncSet).%New("unique_value")
%New() の整数引数である unique_value は、簡単に識別できる一意の値である必要があります。これにより、各サイトのトランザクション・ログに追加したものが区別可能になります。
-
SyncSet インスタンスの AddTransactions() メソッドを呼び出します。
Do SrcSyncSet.AddTransactions(FirstTransaction,LastTransaction,ExcludedDB)
以下はその説明です。
-
FirstTransaction は同期化する最初のトランザクション番号です。
-
LastTransaction は同期化する最後のトランザクション番号です。
-
ExcludedDB は、トランザクションが SyncSet から除外されるデータベース内のネームスペースを示します。
このメソッドは、同期データを収集して、それをグローバルに格納し、エクスポートできるようにします。
または、前回の同期以降のトランザクションをすべて同期するために、1 番目と 2 番目の引数を省略します。
Do SrcSyncSet.AddTransactions(,,ExcludedDB)
これによって、最初の同期化されていないトランザクションから最新のトランザクションまでのすべてのトランザクションが取得されます。このメソッドでは、SyncTime テーブルの情報を使用して値が決定されます。
ExcludedDB は $LIST です。以下のようにして作成します。
Set ExcludedDB = $ListBuild(GUID,namespace)
以下はその説明です。
-
GUID は、ターゲット・システム上のシステム GUID です。この値は、%SYS.System.InstanceGUIDOpens in a new tab クラス・メソッドを通じて使用できます。このメソッドを呼び出すには、##class(%SYS.System).InstanceGUID() 構文を使用します。
-
namespace は、ターゲット・システム上のネームスペースです。
-
-
ErrCount() メソッドを呼び出して、発生したエラー数を確認します。エラーが発生していた場合、SyncSet.Errors クエリを実行すると、詳細情報が得られます。
-
ExportFile() メソッドを使用して、そのデータをローカル・ファイルにエクスポートします。
Do SrcSyncSet.ExportFile(file,displaymode,bUpdate)
以下はその説明です。
-
file は、トランザクションのエクスポート先のファイルで、名前には相対パスまたは絶対パスが含まれています。
-
displaymode では、このメソッドが現在のデバイスに出力を書き込むかどうかを指定します。出力する場合は d を指定します。出力しない場合は -d を指定します。
-
bUpdate は、SyncTime テーブルが更新されるかどうかを指定するブーリアン値です (既定値は True を意味する 1 です)。この時点ではこれを明示的に 0 に設定し、ターゲットが実際にデータを受信し、同期化が実行されたことの確認をソースが受信した後に、これを 1 に設定すると便利です。
-
-
エクスポートしたファイルを、ソース・マシンからターゲット・マシンに移動します。
-
SyncSet.%New() メソッドを使用して、ターゲット・マシンに SyncSet オブジェクトを作成します。%New() の引数に、ソース・マシンと同じ値を使用します。これは、同期化されるトランザクションのソースを識別する値です。
-
Import() メソッドを使用して、SyncSet オブジェクトを、ターゲット・マシンの InterSystems IRIS インスタンスに読み込みます。
Set Status = TargetSyncSet.Import(file,lastSync,maxTS,displaymode,errorlog,diag)
以下はその説明です。
-
file はインポートするデータを含むファイルです。
-
lastSync は、最後に同期化されたトランザクション番号 (既定値は synctime テーブルから取得) です。
-
maxTS は、SyncSet オブジェクトの最後のトランザクション番号です。
-
displaymode では、このメソッドが現在のデバイスに出力を書き込むかどうかを指定します。出力する場合は d を指定します。出力しない場合は -d を指定します。
-
errorlog は、エラー情報のリポジトリです (アプリケーションに情報を提供するために参照によって呼び出されます)。
-
diag は、インポート時に発生した詳細な診断情報です。
このメソッドにより、データがターゲット・データベースに格納されます。これは、以下のように動作します。
-
最後の同期化以降、ソース・データベースとターゲット・データベースの両方でオブジェクトが変更されたことをメソッドが検出すると、%ResolveConcurrencyConflict() コールバック・メソッドが呼び出されます。他のコールバック・メソッドと同様、%ResolveConcurrencyConflict() のコンテンツはユーザが提供します (この 2 つの変更が共通のプロパティに対して行われた場合、またはこの 2 つの変更がそれぞれ接点のないプロパティのセットに対して行われた場合のいずれかに、このコールバック・メソッドが呼び出されます)。%ResolveConcurrencyConflict() メソッドが実装されない限り、この競合は解決されません。
-
Import() メソッドの実行後、解決できない競合がある場合、これらは未解決の項目として SyncSet オブジェクトに残ります。残っている競合には、適切に対処してください。例えば、競合を解決する、その項目を未解決の状態にしておくなどの処置が考えられます。
Important:Import() メソッドはステータス値を返しますが、そのステータス値は、SyncSet の処理を妨げるエラーが発生せずにこのメソッドが完了したことを示すだけです。SyncSet 内の各オブジェクトがエラーの発生なしに正常に処理されたことを示すわけではありません。同期エラー報告の詳細は、%SYNC.SyncSet のクラス・リファレンスの "Import()" を参照してください。
-
-
最初のデータベースが 2 番目のデータベースを更新したら、2 番目のデータベースが最初のデータベースを更新できるように、2 番目のデータベースから最初のデータベースに対して同じプロセスを実行します。
GUID と OID との変換
オブジェクトの OID から、そのオブジェクトの GUID を判断する (またはその逆を判断する) ために、以下の 2 つのメソッドを使用できます。
-
%GUIDFind() は、%GUIDOpens in a new tab クラスのクラス・メソッドで、オブジェクト・インスタンスの GUID を取得して、そのインスタンスに関連付けられた OID を返します。
-
%GUID() は、%PersistentOpens in a new tab クラスのクラス・メソッドであり、オブジェクト・インスタンスの OID を取得して、そのインスタンスに関連付けられた GUID を返します。このメソッドは、対応するクラスの GUIDENABLED パラメータが TRUE の場合にのみ実行できます。このメソッドは多様な形式でディスパッチし、OID にクラス情報が含まれない場合、最も適切なタイプのクラスを決定します。インスタンスに GUID が割り当てられていない場合は空文字列を返します。
SyncTime テーブルの手動更新
データベースの SyncTime テーブルを手動で更新するには、最後のトランザクション番号を設定する SetlTrn() メソッドを呼び出します。
Set Status=##class(%SYNC.SyncTime).SetlTrn(syncSYSID, syncNSID, ltrn)
以下はその説明です。
-
syncSYSID は、ターゲット・システム上のシステム GUID です。この値は、%SYS.System.InstanceGUIDOpens in a new tab クラス・メソッドを通じて使用できます。このメソッドを呼び出すには、##class(%SYS.System).InstanceGUID() 構文を使用します。
-
syncNSID は、ターゲット・システム上のネームスペースであり、$Namespace 変数に保持されています。
-
ltrn は、インポートされたことがわかっているトランザクション番号の最大値です。この値は、SyncSet の GetLastTransaction() メソッドを呼び出すことで取得できます。
SetlTrn() メソッドは、既定の動作 (ソース・システムからエクスポートされたトランザクションの番号の最大値を設定) とは異なって、ターゲット・システム上の同期化されたトランザクションの番号の最大値を設定します。どちらの方法を使用しても問題ありません。アプリケーションの開発中にいずれかを選択できます。