アプリケーション内でユーザー独自の Loader プラグイン実装を作成することができますが、WebSphere eXtreme Scale の共通プラグイン規則に従う必要があります。
この Loader インターフェースには、以下の定義があります。
public interface Loader
{
static final SpecialValue KEY_NOT_FOUND;
List get(TxID txid, List keyList, boolean forUpdate) throws LoaderException;
void batchUpdate(TxID txid, LogSequence sequence) throws
LoaderException, OptimisticCollisionException;
void preloadMap(Session session, BackingMap backingMap) throws LoaderException;
}
詳しくは、ローダーを参照してください。
バッキング・マップは Loader の get メソッドを呼び出し、keyList 引数として渡されるキー・リストに関連付けられた値を取得します。 get メソッドは、キー・リストにある各キーのうちの 1 つの値の java.lang.util.List リストを戻す必要があります。値リストに戻される最初の値はキー・リストの最初のキーに対応し、 値リストに戻される 2 番目の値はキー・リストの 2 番目のキーに対応し、以降同様になります。 キー・リスト内でキーの値を検出できなかったローダーは、 Loader インターフェースで定義された特別な KEY_NOT_FOUND 値オブジェクト を戻す必要があります。 バッキング・マップは、null を有効な値として許可するよう構成できるので、キーを検出できない Loader が特別な KEY_NOT_FOUND オブジェクトを戻すことが極めて重要になります。この特殊値により、バッキング・マップは null 値とキーが検出できなかったため存在しない値とを区別できます。バックアップ・マップが null 値をサポートしない場合、 存在しないキーについて KEY_NOT_FOUND オブジェクトではなく null 値を戻す Loader は、例外を発生します。
forUpdate 引数は、アプリケーションがマップ上で get メソッドまたは getForUpdate メソッドのいずれを呼び出したかを Loader に通知します。詳しくは、ObjectMap interfaceを 参照してください。ローダーは、永続ストアへの並行アクセスを制御する、並行性制御ポリシーの実装を担当します。 例えば、多くのリレーショナル・データベース管理システムは、リレーショナル・テーブルからデータを読み取るために 使用される SQL SELECT ステートメントの FOR UPDATE 構文をサポートします。 ローダーは、ブール値 true が、このメソッドの forUpdate パラメーターに引数値として渡されるかどうかに基づいて、SQL SELECT ステートメントの FOR UPDATE 構文を使用することを選択できます。 通常、ローダーはペシミスティック並行性の制御ポリシーが使用される場合にのみ FOR UPDATE 構文を使用します。オプティミスティック並行性制御の場合、ローダーは SQL SELECT ステートメントで FOR UPDATE 構文を使用することはありません。ローダーは、そのローダーが使用している並行性制御ポリシーに基づいて forUpdate 引数の使用を判別します。
txid パラメーターの説明については、トランザクションのライフサイクル・イベントの管理のためのプラグインを参照してください。
batchUpdate メソッドは、Loader インターフェースにおいて重要です。eXtreme Scale によって現在のすべての変更が Loader に適用される必要がある場合、必ずこのメソッドが呼び出されます。 ローダーには、選択されたマップの変更のリストが与えられます。変更は繰り返され、バックエンドに適用されます。 このメソッドは現行の TxID 値および適用する変更を受け取ります。 以下のサンプルは、一連の変更に対して繰り返し適応され、3 つの Java Database Connectivity (JDBC) ステートメント (INSERT、UPDATE、および DELETE) をバッチ処理します。
import java.util.Collection;
import java.util.Map;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.ibm.websphere.objectgrid.TxID;
import com.ibm.websphere.objectgrid.plugins.Loader;
import com.ibm.websphere.objectgrid.plugins.LoaderException;
import com.ibm.websphere.objectgrid.plugins.LogElement;
import com.ibm.websphere.objectgrid.plugins.LogSequence;
public void batchUpdate(TxID tx, LogSequence sequence) throws LoaderException {
// Get a SQL connection to use.
Connection conn = getConnection(tx);
try {
// Process the list of changes and build a set of prepared
// statements for executing a batch update, insert, or delete
// SQL operation.
Iterator iter = sequence.getPendingChanges();
while (iter.hasNext()) {
LogElement logElement = (LogElement) iter.next();
Object key = logElement.getKey();
Object value = logElement.getCurrentValue();
switch (logElement.getType().getCode()) {
case LogElement.CODE_INSERT:
buildBatchSQLInsert(tx, key, value, conn);
break;
case LogElement.CODE_UPDATE:
buildBatchSQLUpdate(tx, key, value, conn);
break;
case LogElement.CODE_DELETE:
buildBatchSQLDelete(tx, key, conn);
break;
}
}
// Execute the batch statements that were built by above loop.
Collection statements = getPreparedStatementCollection(tx, conn);
iter = statements.iterator();
while (iter.hasNext()) {
PreparedStatement pstmt = (PreparedStatement) iter.next();
pstmt.executeBatch();
}
} catch (SQLException e) {
LoaderException ex = new LoaderException(e);
throw ex;
}
}
eXtreme Scale の初期化中に、定義された各バックアップ・マップが初期化されます。Loader がバッキング・マップにプラグインされると、バッキング・マップは Loader インターフェースで preloadMap メソッドを呼び出し、 ローダーがバックエンドからデータをプリフェッチし、マップにデータをロードできるようにします。以下のサンプルでは、Employee テーブルの最初の 100 行がデータベースから 読み取られて、マップにロードされると仮定します。 EmployeeRecord クラスはアプリケーションが提供するクラスであり、 従業員テーブルから読み取った従業員データを保持します。
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.ibm.websphere.objectgrid.Session;
import com.ibm.websphere.objectgrid.TxID;
import com.ibm.websphere.objectgrid.plugins.Loader;
import com.ibm.websphere.objectgrid.plugins.LoaderException
public void preloadMap(Session session, BackingMap backingMap) throws LoaderException {
boolean tranActive = false;
ResultSet results = null;
Statement stmt = null;
Connection conn = null;
try {
session.beginNoWriteThrough();
tranActive = true;
ObjectMap map = session.getMap(backingMap.getName());
TxID tx = session.getTxID();
// Get a auto−commit connection to use that is set to
// a read committed isolation level.
conn = getAutoCommitConnection(tx);
// Preload the Employee Map with EmployeeRecord
// objects. Read all Employees from table, but
// limit preload to first 100 rows.
stmt = conn.createStatement();
results = stmt.executeQuery(SELECT_ALL);
int rows = 0;
while (results.next() && rows < 100) {
int key = results.getInt(EMPNO_INDEX);
EmployeeRecord emp = new EmployeeRecord(key);
emp.setLastName(results.getString(LASTNAME_INDEX));
emp.setFirstName(results.getString(FIRSTNAME_INDEX));
emp.setDepartmentName(results.getString(DEPTNAME_INDEX));
emp.updateSequenceNumber(results.getLong(SEQNO_INDEX));
emp.setManagerNumber(results.getInt(MGRNO_INDEX));
map.put(new Integer(key), emp);
++rows;
}
// Commit the transaction.
session.commit();
tranActive = false;
} catch (Throwable t) {
throw new LoaderException("preload failure: " + t, t);
} finally {
if (tranActive) {
try {
session.rollback();
} catch (Throwable t2) {
// Tolerate any rollback failures and
// allow original Throwable to be thrown.
}
}
// Be sure to clean up other databases resources here
// as well such a closing statements, result sets, etc.
}
}
preloadMap サンプルは、テーブルの行をすべて選択する SQL SELECT ステートメントを使用しています。 アプリケーションが提供する Loader では、マップにプリロードするテーブルの数を制御するために、 1 つ以上の Loader プロパティーを設定します。
preloadMap メソッドは BackingMap の初期化中に 1 回しか呼び出されないので、 1 回だけのローダー初期化コードの実行場所としても適切です。 ローダーがバックエンドからデータをプリフェッチせず、データをマップにロードしないことを選択した場合であっても、それ以外に何らかの 1 回だけの初期化を実行し、さらに効率的なローダーの別のメソッドを作成する必要があると考えられます。以下は、TransactionCallback オブジェクトおよび OptimisticCallback オブジェクト を Loader のインスタンス変数としてキャッシングして、Loader の別のメソッドが これらのオブジェクトにアクセスするためにメソッド呼び出しを行わなくても済むようにする例です。 BackingMap の初期化後に、TransactionCallback オブジェクトおよび OptimisticCallback オブジェクト を変更または置換できなくなるため、この ObjectGrid プラグインの値のキャッシングを行うことが可能です。 これらのオブジェクト参照をローダーのインスタンス変数としてキャッシュに入れることは許容されます。
import com.ibm.websphere.objectgrid.Session;
import com.ibm.websphere.objectgrid.BackingMap;
import com.ibm.websphere.objectgrid.plugins.OptimisticCallback;
import com.ibm.websphere.objectgrid.plugins.TransactionCallback;
// Loader instance variables.
MyTransactionCallback ivTcb; // MyTransactionCallback
// extends TransactionCallback
MyOptimisticCallback ivOcb; // MyOptimisticCallback
// implements OptimisticCallback
// ...
public void preloadMap(Session session, BackingMap backingMap) throws LoaderException
[Replication programming]
// Cache TransactionCallback and OptimisticCallback objects
// in instance variables of this Loader.
ivTcb = (MyTransactionCallback) session.getObjectGrid().getTransactionCallback();
ivOcb = (MyOptimisticCallback) backingMap.getOptimisticCallback();
// The remainder of preloadMap code (such as shown in prior example).
}
レプリカ生成フェイルオーバーに関係するプリロードおよび回復可能なプリロードについて詳しくは、可用性向上のためのレプリカ生成製品概要でレプリカ生成に関する説明を参照してください。
ローダーがエンティティー・マップにプラグインされている場合は、ローダーでタプル・オブジェクトを処理する必要があります。タプル・オブジェクトは特別なエンティティー・データ・フォーマットです。ローダーでは、タプルとその他のデータ・フォーマット間でデータ変換を実行する必要があります。例えば、get メソッドにより、このメソッドに渡されるキーのセットに対応する値のリストが返されます。渡されたキーは Tuple のタイプに置かれ、キー・タプルと呼ばれます。ローダーが JDBC を使用しているデータベースでマップをパーシストすると想定した場合、get メソッドは、各キー・タプルをエンティティー・マップにマップされているテーブルの 1 次キーの列に対応する属性値リストに変換し、データベースからデータをフェッチする基準として変換された属性値を使用する WHERE 文節が含まれている SELECT ステートメントを実行した後、返されたデータを値タプルに変換する必要があります。get メソッドは、データベースからデータを取得し、渡されたキー・タプルに対する値タプルにそのデータを変換した後、呼び出し元に渡されたタプル・キーのセットに対応する値タプルのリストを返します。get メソッドは 1 つの SELECT ステートメントを実行して一度にすべてのデータをフェッチするか、または各キー・タプルに対して SELECT ステートメントを実行します。データがエンティティー・マネージャーを使用して保管されるときにローダーを どのように使用するのかを示すプログラミングの詳細は、エンティティー・マップおよびタプルとのローダーの使用を参照してください。