エンティティー照会キュー

照会キューを使用して、アプリケーションはエンティティーに対し、照会によって限定されるキューを サーバー・サイドまたはローカルの eXtreme Scale に 作成できます。照会結果のエンティティーは、このキューに 保管されます。現在、照会キューは、ペシミスティック・ロック・ストラテジーを使用している マップでのみサポートされます。

照会キューは複数のトランザクションおよびクライアントによって共有されます。 照会キューが空になると、このキューに関連付けられたエンティティー照会が再実行され、新しい結果がキューに追加されます。照会キューは、エンティティー照会ストリングとパラメーターによって 一意的に識別されます。 1 つの ObjectGrid インスタンス内に存在する各固有の照会キューのインスタンスは 1 つのみです。追加情報については、EntityManager API 資料を 参照してください。

照会キューの例

次の例は、照会キューの 使用法を示します。

/**
 * Get a unassigned question type task 
 */
private void getUnassignedQuestionTask() throws Exception {
    EntityManager em = og.getSession().getEntityManager();
    EntityTransaction tran = em.getTransaction();

    QueryQueue queue = em.createQueryQueue("SELECT t FROM Task t
				WHERE t.type=?1 AND t.status=?2", Task.class);
    queue.setParameter(1, new Integer(Task.TYPE_QUESTION));
    queue.setParameter(2, new Integer(Task.STATUS_UNASSIGNED));

    tran.begin();
    Task nextTask = (Task) queue.getNextEntity(10000);
    System.out.println("next task is " + nextTask);
    if (nextTask != null) {
        assignTask(em, nextTask);
    }
    tran.commit();
}

上記の例は、最初にエンティティー照会ストリング "SELECT t FROM Task t WHERE t.type=?1 AND t.status=?2" を使用して QueryQueue を作成しています。その次に、QueryQueue オブジェクトのパラメーターを設定しています。 この照会キューは、タイプが "question" のすべての "unassigned" (未割り当て) タスクを示します。 QueryQueue オブジェクトは、エンティティー Query オブジェクトに非常によく似ています。

QueryQueue が 作成されると、エンティティー・トランザクションが開始され、getNextEntity メソッドが呼び出されます。 このメソッドは、タイムアウト値が 10 秒に設定され、次に使用可能なエンティティーを 取得します。エンティティーが取得されると、それは assignTask メソッドで処理されます。assignTask は Task エンティティー・インスタンスを変更し、 状況を "assigned" (割り当て済み) に変更します。これにより、このエンティティーは もはや QueryQueue のフィルターに一致しなくなるため、 事実上キューから削除されます。割り当てが終わると、トランザクションがコミットされます。

この簡単な 例からわかるように、照会キューはエンティティー照会に似ています。しかし、両者には次のような違いがあります。
  1. 照会キュー内のエンティティーは、反復方式で取得できます。 取得するエンティティーの数は、ユーザー・アプリケーションが決定します。 例えば、QueryQueue.getNextEntity(timeout) が使用された場合、取得される エンティティーは 1 つのみです。QueryQueue.getNextEntities(5, timeout) が使用された場合は、5 つの エンティティーが取得されます。分散環境では、エンティティーの数によって、 サーバーからクライアントへ転送されるバイト数が直接決まります。
  2. エンティティーが照会キューから取得される際、そのエンティティーには U ロックが かけられるため、他のトランザクションはアクセスできません。

ループでのエンティティーの取得

エンティティーをループで 取得できます。以下に、未割り当て (UNASSIGNED) の質問 (QUESTION) タイプのすべてのタスクを 完了させる方法の例を示します。

/**
 * Get all unassigned question type tasks 
 */
private void getAllUnassignedQuestionTask() throws Exception {
    EntityManager em = og.getSession().getEntityManager();
    EntityTransaction tran = em.getTransaction();

    QueryQueue queue = em.createQueryQueue("SELECT t FROM Task t WHERE 
			t.type=?1 AND t.status=?2", Task.class);
    queue.setParameter(1, new Integer(Task.TYPE_QUESTION));
    queue.setParameter(2, new Integer(Task.STATUS_UNASSIGNED));

    Task nextTask = null;

    do {
        tran.begin();
        nextTask = (Task) queue.getNextEntity(10000);
        if (nextTask != null) {
            System.out.println("next task is " + nextTask);
        }
        tran.commit();
    } while (nextTask != null);
}

エンティティー・マップ内に未割り当ての質問タイプの タスクが 10 個あった場合、ユーザーは、10 個のエンティティーがコンソールに プリントされると予想したでしょう。しかし、このサンプルを実行すると、 予想に反して、プログラムは永久に終了しません。

照会キューが 作成され、getNextEntity が呼び出されると、キューに関連付けられたエンティティー照会が実行され、 キューには 10 件の結果が追加されます。getNextEntity が呼び出されると、1 つのエンティティーが キューから取り出されます。getNextEntity 呼び出しが 10 回実行されると、 キューは空になります。エンティティー照会が自動的に再実行されます。これら 10 個のエンティティーはまだ存在し、照会キューのフィルター条件に一致するため、 それらは再度キューに追加されます。

次の行を println() ステートメントの 後に追加すれば、10 個のエンティティーのみが プリントされるようになります。

em.remove(nextTask);

コンテナーごとの配置デプロイメントでの SessionHandle と QueryQueue の使用について詳しくは、SessionHandle 統合を参照してください。

すべての区画にデプロイされる照会キュー

分散 eXtreme Scale では、 照会キューを 1 つの区画またはすべての区画に作成できます。 照会キューをすべての区画に作成する場合、各区画に 1 つの 照会キュー・インスタンスが存在します。

クライアントは、QueryQueue.getNextEntity または QueryQueue.getNextEntities メソッドを使用して次のエンティティーを取得しようとするとき、 要求を区画の 1 つに送信します。クライアントは、照合要求とピン要求を サーバーに送信します。

  • 照合要求では、クライアントが要求をある区画に送信すると、 すぐにサーバーから応答が返されます。エンティティーがキュー内にある場合、サーバーはエンティティーを 付けて応答を返します。エンティティーがない場合、 サーバーはエンティティーなしで応答を返します。いずれの場合も、サーバーは即時に 応答を返します。
  • ピン要求では、クライアントが要求をある区画に送信すると、 サーバーは、エンティティーが使用可能になるまで待機します。エンティティーがキュー内にある場合、 サーバーはエンティティーを付けて即時に応答を返します。 エンティティーがない場合、サーバーは、エンティティーが使用可能になるか、 または要求がタイムアウトになるまでキューで待機します。

すべての区画 (n 個) にデプロイされる照会キューのエンティティーを 取得する方法の例を以下に示します。

  1. QueryQueue.getNextEntity または QueryQueue.getNextEntities メソッドが 呼び出されると、クライアントは 0 から n-1 の中からランダムに区画番号を選出します。
  2. クライアントは照合要求を、そのランダムに選出した区画に送信します。
    • エンティティーが使用可能な場合は、エンティティーを返すことで、QueryQueue.getNextEntity または QueryQueue.getNextEntities メソッドは終了します。
    • エンティティーが使用不可で、かつそれがアクセスされていない最後の区画ではない場合、 クライアントは照合要求を次の区画に送信します。
    • エンティティーが使用不可で、かつそれがアクセスされていない最後の区画だった場合、 クライアントは代わりにピン要求を送信します。
    • 最後の区画に送信されたピン要求がタイムアウトになり、 まだ使用可能なデータが存在しない場合、クライアントは、最後の試みとして、 照合要求をもう 1 回すべての区画に順番に送信します。結果、 以前の区画に使用可能なエンティティーがあれば、 クライアントはそれを取得できます。

サブセット・エンティティーおよび非エンティティーのサポート

エンティティー・マネージャーに QueryQueue オブジェクトを作成するメソッドは、次のとおりです。

public QueryQueue createQueryQueue(String qlString, Class entityClass);

照会キュー 内の結果は、メソッドの 2 番目のパラメーターで定義されたオブジェクト である Class entityClass に射影されます。

このパラメーターが指定された場合、 クラスには、照会ストリングで指定されたものと同じエンティティー名が 必要です。これは、エンティティーをサブセット・エンティティーに 射影する場合に便利です。エンティティー・クラスにヌル値が使用された場合は、 結果には何も射影されません。マップに保管される値は、 エンティティー・タプル・フォーマットになります。

クライアント・サイドのキー競合

分散 eXtreme Scale 環境の場合、 ペシミスティック・ロック・モードを使用する eXtreme Scale マップでのみ 照会キューがサポートされます。したがって、クライアント・サイドにニア・キャッシュは存在しません。 しかし、クライアントはトランザクション・マップ内にデータ (キーと値) を 保持している可能性があります。このため、サーバーから取得されたエンティティーが、 既にトランザクション・マップ内にあるエントリーと同じキーを 共有していた場合、キー競合につながる可能性があります。

キー競合が発生すると、eXtreme Scale クライアント・ランタイムは、次の規則に従って、例外をスローするか、またはサイレントにデータをオーバーライドします。
  1. 競合したキーが、照会キューに関連付けられたエンティティー照会で指定された エンティティーのキーだった場合は、例外がスローされます。この場合、トランザクションはロールバックされ、 このエンティティー・キーに対する U ロックはサーバー・サイドで解除されます。
  2. そうでない場合、競合したキーがエンティティー・アソシエーションのキーであれば、 トランザクション・マップ内のデータは警告なしでオーバーライドされます。

キー競合は、トランザクション・マップ内にデータが 存在する場合のみ発生します。すなわち、それが発生するのは、 既にダーティーな (新規データが挿入されたか、データが更新された) トランザクション内で getNextEntity または getNextEntities 呼び出しが呼び出されたときに限られます。 アプリケーションでキー競合を発生させないようにするには、常に ダーティーでないトランザクション内で getNextEntity または getNextEntities を 呼び出す必要があります。

クライアント障害

クライアントは、getNextEntity または getNextEntities 要求をサーバーに送信した後、以下のような理由で 失敗することがあります。
  1. クライアントが要求をサーバーに送信してからダウンする。
  2. クライアントが 1 つ以上のエンティティーをサーバーから取得した後で ダウンする。

最初のケースでは、サーバーは応答をクライアントに 送信しようとするときに、クライアントのダウンをディスカバーします。 2 番目のケースでは、クライアントが 1 つ以上のエンティティーをサーバーから取得すると、 それらのエンティティーに X ロックがかけられます。クライアントがダウンすると、 トランザクションは最終的にタイムアウトになり、X ロックは解放されます。

ORDER BY 文節を使用する照会

通常、照会キューでは ORDER BY 文節が 守られません。照会キューから getNextEntity または getNextEntities を 呼び出すと、エンティティーが順序どおりに返される 保証はありません。その理由は、区画間でエンティティーを 正しい順序にすることができないためです。照会キューがすべての区画にデプロイされる ケースでは、getNextEntity または getNextEntities 呼び出しが実行されると、 要求を処理する区画がランダムに選出されます。このため、 順序は保証されません。

照会キューが単一区画にデプロイされる場合は、ORDER BY が守られます。

詳しくは、 EntityManager 照会 APIを参照してください。

トランザクションごとの 1 回の呼び出し

各 QueryQueue.getNextEntity 呼び出しまたは QueryQueue.getNextEntities 呼び出しは、1 つのランダム区画から一致したエンティティーを取得します。 アプリケーションは 1 つのトランザクションで QueryQueue.getNextEntity または QueryQueue.getNextEntities を 1 回だけ呼び出さなければなりません。 そうでなければ、eXtreme Scale は複数の区画からエンティティーをタッチすることになり、コミット時に例外がスローされます。