WebSphere® eXtreme Scale は、使用可能な CopyMode 設定に基づいて値をコピーします。 デプロイメント要件に対して最も適切に機能する設定を判別してください。
BackingMap API setCopyMode(CopyMode, valueInterfaceClass) メソッドを使用して、com.ibm.websphere.objectgrid.CopyMode クラスで定義される、次の最終の静的フィールドの 1 つに、コピー・モードを設定することができます。
アプリケーションが ObjectMap インターフェースを使用してマップ・エントリーに対する参照を取得する場合、その参照は、それを取得したデータ・グリッド・トランザクション内でのみ使用してください。 別のトランザクションでその参照を使用するとエラーになることがあります。例えば BackingMap に対してペシミスティック・ロック・ストラテジーを使用する場合は、get メソッド呼び出しまたは getForUpdate メソッド呼び出しにより、トランザクションに応じて S (shared) ロックまたは U (update) ロックを取得します。トランザクションの終了時に get メソッドは値に参照を戻し、取得されているロックは解放されます。 トランザクションは get メソッドまたは getForUpdate メソッドを呼び出して、別のトランザクションでマップ・エントリーをロックする必要があります。 各トランザクションは、複数のトランザクションで同じ値参照を再利用する代わりに get メソッドまたは getForUpdate メソッドを呼び出すことにより、値への独自の参照を取得する必要があります。
EntityManager API エンティティーと関連付けられたマップを 使用する場合、そのマップは常にエンティティー Tuple オブジェクトを直接戻し、 COPY_TO_BYTES コピー・モードが使用されていない限り、コピーは作成しません。変更を行う場合、CopyMode が更新される、または、Tuple が適切にコピーされることが重要です。
COPY_ON_READ_AND_COMMIT モードはデフォルトのモードです。 このモードが使用される場合、valueInterfaceClass 引数は無視されます。 このモードは、BackingMap に含まれている値オブジェクトへの参照がアプリケーションに含まれていないことを保証します。その代わりに、アプリケーションは常に BackingMap 内の値のコピーを操作します。COPY_ON_READ_AND_COMMIT モードでは、BackingMap にキャッシュされているデータをアプリケーションが誤って壊してしまうことはありません。アプリケーションのトランザクションが指定されたキーの ObjectMap.get メソッドを呼び出し、それがそのキーにとって、ObjectMap エントリーへの初めてのアクセスの場合は、値のコピーが戻されます。トランザクションがコミットされると、アプリケーションによってコミットされたすべての変更は BackingMap にコピーされ、BackingMap にコミットされた値への参照をアプリケーションが持つことはありません。
COPY_ON_READ モードは、トランザクションがコミットされたときに発生するコピーを除去することによって、COPY_ON_READ_AND_COMMIT モード全体にわたるパフォーマンスを改善します。 このモードが使用される場合、valueInterfaceClass 引数は無視されます。 BackingMap データの整合性を保持するために、アプリケーションは、エントリーに対する各参照がトランザクションのコミット後に破棄されることを保証します。 このモードでは、ObjectMap.get メソッドは、値への参照の代わりに値のコピーを返し、アプリケーションがその値に対して行った変更が、トランザクションがコミットされるまで BackingMap 値に影響しないことを保証します。ただし、トランザクションがコミットすると変更のコピーは行われません。 代わりに、ObjectMap.get メソッドによって戻された、コピーへの参照が BackingMap に保管されます。トランザクションがコミットされた後、アプリケーションはすべてのマップ・エントリー参照を破棄します。 アプリケーションがマップ・エントリー参照を破棄しなかった場合、そのアプリケーションは、BackingMap 内にキャッシュされているデータを破壊してしまうことがあります。アプリケーションがこのモードを使用し、問題がある場合は、COPY_ON_READ_AND_COMMIT モードに切り替えてその問題がまだ続いているかどうかを調べます。 問題が解消されている場合は、トランザクションがコミットされた後でアプリケーションはその参照のすべてを破棄するのに失敗したことになります。
COPY_ON_WRITE モードは、指定したキーのトランザクションによって ObjectMap.get メソッドが初めて呼び出されるときに起こるコピーを排除することにより、COPY_ON_READ_AND_COMMIT モードを超えるパフォーマンスを実現します。 ObjectMap.get メソッドは、値オブジェクトへの直接参照の代わりに値のプロキシーを戻します。 プロキシーは、アプリケーションが valueInterfaceClass 引数によって指定した値インターフェース上で set メソッドを呼び出さない限り、値のコピーが行われないことを保証します。プロキシーは、copy on write インプリメンテーションを提供します。トランザクションがコミットすると、BackingMap はプロキシーを検査して、呼び出される set メソッドの結果としてコピーが行われたかどうかを判別します。 コピーが行われた場合は、そのコピーへの参照が BackingMap に保管されます。このモードの大きな利点は、トランザクションが値を変更するために set メソッドを呼び出さない場合には、読み取りまたはコミットの時点で値がコピーされないことです。
COPY_ON_READ_AND_COMMIT および COPY_ON_READ モードはどちらも、値が ObjectMap から検索される場合にディープ・コピーを行います。アプリケーションがトランザクションで検索されたいくつかの値を更新するだけの場合は、このモードは最適ではありません。 COPY_ON_WRITE モードはこの振る舞いを効率的にサポートしますが、このモードではアプリケーションが単純なパターンを使用する必要があります。 インターフェースをサポートするには、値オブジェクトが必要です。 アプリケーションは、セッション内で値と対話するときに、このインターフェースのメソッドを使用する必要があります。 その場合は、アプリケーションに返される値のプロキシーが作成されます。 プロキシーは実際の値への参照を持ちます。 アプリケーションが読み取り操作のみを実行した場合、その読み取り操作は常に実際のコピーに対して実行されます。アプリケーションがオブジェクト上の属性を変更すると、プロキシーは実際のオブジェクトのコピーを作成してから、そのコピーを変更します。 プロキシーは次に、そのポイントからコピーを使用します。 このコピーを使用することにより、アプリケーションによって読み取られるだけのオブジェクトに対するコピー操作は完全に避けることができます。 すべての変更操作は設定されたプレフィックスで開始する必要があります。 Enterprise JavaBeans は通常、オブジェクト属性を変更するメソッドに対してこのスタイルのメソッドの名前付けを使用するためにコード化されます。 この規則に従わなければいけません。 変更されたすべてのオブジェクトは、アプリケーションによって変更されるときにコピーされます。 この読み取りと書き込みのシナリオは、eXtreme Scale がサポートしている、最も効率的なシナリオです。COPY_ON_WRITE モードを使用するようマップを構成するには、以下の例を使用してください。この例では、アプリケーションは、Map 内の名前を使用してキーが付けられている Person オブジェクトを保管します。Person オブジェクトは以下のコード・スニペットで表されます。
class Person {
String name;
int age;
public Person() {
}
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
アプリケーションは、ObjectMap から取り出された値と対話する場合にのみ IPerson インターフェースを使用します。次の例のようにオブジェクトを変更してインターフェースを使用します。
interface IPerson
{
void setName(String n);
String getName();
void setAge(int a);
int getAge();
}
// Modify Person to implement IPerson interface
class Person implements IPerson {
...
}
ObjectGrid dg = ...;
BackingMap bm = dg.defineMap("PERSON");
// use COPY_ON_WRITE for this Map with
// IPerson as the valueProxyInfo Class
bm.setCopyMode(CopyMode.COPY_ON_WRITE,IPerson.class);
// The application should then use the following
// pattern when using the PERSON Map.
Session sess = ...;
ObjectMap person = sess.getMap("PERSON");
...
sess.begin();
// the application casts the returned value to IPerson and not Person
IPerson p = (IPerson)person.get("Billy");
p.setAge(p.getAge()+1);
...
// make a new Person and add to Map
Person p1 = new Person();
p1.setName("Bobby");
p1.setAge(12);
person.insert(p1.getName(), p1);
sess.commit();
// the following snippet WON'T WORK. Will result in ClassCastException
sess.begin();
// the mistake here is that Person is used rather than
// IPerson
Person a = (Person)person.get("Bobby");
sess.commit();
プロキシーを 2 つのタイプにキャストすることができます。先ほどのコード・スニペットの最後の部分は、COPY_ON_WRITE モードでは許可されないことを示しています。このアプリケーションは Bobby レコードを取り出して、そのレコードを Person オブジェクトにキャストしようとします。このアクションはクラス・キャスト例外により失敗します。戻されるプロキシーが Person オブジェクトではないからです。戻されたプロキシーは IPerson オブジェクトと ValueProxyInfo を実装します。
ValueProxyInfo インターフェースおよび部分更新サポート: このインターフェースはアプリケーションに対して、プロキシーによって参照される、コミットされた読み取り専用の値か、またはこのトランザクション中に変更された属性セットのどちらかの検索を許可します。
public interface ValueProxyInfo {
List /**/ ibmGetDirtyAttributes();
Object ibmGetRealValue();
}
ibmGetRealValue メソッドは、オブジェクトの読み取り専用のコピーを戻します。 アプリケーションはこの値を変更してはいけません。ibmGetDirtyAttributes メソッドは、このトランザクション中にアプリケーションによって変更された属性を表すストリングのリストを返します。 ibmGetDirtyAttributes メソッドの主要ユース・ケースは、Java Database Connectivity (JDBC) ローダーまたは CMP ベースのローダーにあります。 リスト内の命名された属性のみを、SQL ステートメントまたはテーブルにマップされたオブジェクトのいずれかで更新する必要があります。 こうすることで、より効率的な SQL がローダーによって生成されます。 copy on write トランザクションがコミットされ、ローダーが接続されると、ローダーは変更されたオブジェクトの値を ValueProxyInfo インターフェースにキャストしてこの情報を取得することができます。
COPY_ON_WRITE またはプロキシーを使用する場合の equals メソッドの処理: 例えば、次のコードは Person オブジェクトを構成してから、それを ObjectMap に挿入します。次に、ObjectMap.get メソッドを使用して同じオブジェクトを取り出します。 値はインターフェースにキャストされます。値が Person インターフェースにキャストされる場合は、ClassCastException 例外が起こります。戻り値が、Person オブジェクトではなく、IPerson インターフェースをインプリメントするプロキシーだからです。== 操作を使用する場合は、等価チェックが失敗します。これらは同じオブジェクトではないからです。
session.begin();
// new the Person object
Person p = new Person(...);
personMap.insert(p.getName, p);
// retrieve it again, remember to use the interface for the cast
IPerson p2 = personMap.get(p.getName());
if(p2 == p) {
// they are the same
} else {
// they are not
}
equals メソッドをオーバーライドする必要がある場合は、ほかにも考慮しなければならないことがあります。equals メソッドは、引数が IPerson インターフェースを実装するオブジェクトであることを確認し、引数を IPerson オブジェクトとしてキャストする必要があります。 引数が、IPerson インターフェースをインプリメントするプロキシーかもしれないので、インスタンス変数が等しいかどうかを比較するときに getAge メソッドと getName メソッドを使用する必要があります。 次の例を参照してください。
{
if ( obj == null ) return false;
if ( obj instanceof IPerson ) {
IPerson x = (IPerson) obj;
return ( age.equals( x.getAge() ) && name.equals( x.getName() ) )
}
return false;
}
ObjectQuery および HashIndex の構成要件: COPY_ON_WRITE を ObjectQuery または HashIndex プラグインと一緒に使用するときは、プロパティー・メソッドを使用してオブジェクトにアクセスするように ObjectQuery スキーマと HashIndex プラグインを構成する必要があります。これがデフォルトです。 フィールド・アクセスを構成した場合は、照会エンジンおよび索引がプロキシー・オブジェクト内のフィールドへのアクセスを試みますが、オブジェクト・インスタンスがプロキシーであるため、常にヌルまたは 0 を返します。
NO_COPY モードでは、アプリケーションのパフォーマンスは向上しますが、そのアプリケーションが、ObjectMap.get メソッドを使用して取得される値オブジェクトを絶対に変更しないようにする必要があります。 このモードが使用される場合、valueInterfaceClass 引数は無視されます。 このモードを使用する場合は、値がコピーされることはありません。 ObjectMap から取得される値オブジェクト・インスタンスや、ObjectMap に追加される値オブジェクト・インスタンスをアプリケーションが変更すると、BackingMap 内のデータは破壊されます。 NO_COPY モードは基本的に、アプリケーションによってデータが変更されることのない、読み取り専用マップで有用です。 アプリケーションがこのモードを使用し、問題がある場合は、COPY_ON_READ_AND_COMMIT モードに切り替えてその問題がまだ存在するかどうかを調べます。 問題が解消されている場合は、トランザクション中またはトランザクションがコミットされた後でアプリケーションは ObjectMap.get メソッドによって戻された値を変更しています。 EntityManager API エンティティーに関連付けられたすべてのマップは、eXtreme Scale 構成の指定にかかわらず、自動的にこのモードを使用します。
EntityManager API エンティティーに関連付けられたすべてのマップは、eXtreme Scale 構成の指定にかかわらず、自動的にこのモードを使用します。
POJO 形式の代わりに、シリアライズ形式で オブジェクトを保管できます。COPY_TO_BYTES 設定を 使用すると、大きなオブジェクト・グラフが消費するメモリー占有スペースを 削減できます。詳しくは、バイト配列マップを使用したパフォーマンスの向上を参照してください。
COPY_TO_BYTES_RAW を使用して、シリアライズ形式のデータに直接アクセスできます。このコピー・モードは、シリアライズされたバイトと対話するための効率的な方法を提供します。このモードを使用すると、メモリー内のオブジェクトにアクセスするためにデシリアライゼーション・プロセスをバイパスできます。
ObjectGrid 記述子 XML ファイルでは、コピー・モードを COPY_TO_BYTES に設定でき、生のシリアライズされたデータにアクセスしたいインスタンスでは、プログラマチックにコピー・モードを COPY_TO_BYTES_RAW に設定できます。アプリケーションがメイン・アプリケーション・プロセスの一部として生データを使用する場合に限り、ObjectGrid 記述子 XML ファイルでコピー・モードを COPY_TO_BYTES _RAW に設定します。上記で説明したように、アプリケーションが COPY_ON_READ、 COPY_ON_WRITE、または NO_COPY コピー・モードを使用してパフォーマンスを改善しようとすると、エラーが発生します。コピー・モードを COPY_ON_READ_AND_COMMIT モードに変更する際には偶発的なエラーは発生しません。
問題
この問題は、使用したコピー・ モードのプログラミング契約にアプリケーションが違反し、その結果 発生した ObjectGrid マップ内のデータ破壊に起因する場合があります。データ破壊は、 予測不能なエラーが、偶発的または解明不能または予期しない形で発生する原因になることが あります。
解決策
アプリケーションは、使用中のコピー・モード用プログラミング契約に従う必要があります。 COPY_ON_READ および COPY_ON_WRITE コピー・モードの場合、アプリケーションは、値参照を取得したトランザクションの有効範囲外の値オブジェクトへの参照を使用します。これらのモードを使用するためには、アプリケーションはトランザクションの完了後に値オブジェクトへの参照を削除し、値オブジェクトにアクセスするそれぞれのトランザクションの値オブジェクトへの新規参照を取得する必要があります。NO_COPY コピー・モードの場合、アプリケーションが値オブジェクトを一切変更しないようにする必要があります。この場合、値オブジェクトを変更しないようにアプリケーションを作成するか、別のコピー・モードを使用するようにアプリケーションを設定します。