ヘッダーをスキップ
Oracle Coherenceリリース・ノート
リリース3.4.2
B53784-01
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

2 ドキュメントの記載内容の誤り

この章では、既存のOracle Coherenceドキュメント・ライブラリ(『Oracle Coherenceスタート・ガイド』、『Oracle Coherence開発者ガイド』および『Oracle Coherenceユーザーズ・ガイド』)への変更、追加および修正の内容について説明します。Oracle Coherenceの最新ドキュメント・ライブラリは、次のURLで入手できます。

http://download.oracle.com/docs/cd/E13924_01/index.htm

2.1 「インプリメンタの概要」に対する修正

この項では、『Oracle Coherenceスタート・ガイド』の「インプリメンタの概要」の章に対する変更について説明します。

表2-1は、「キャッシュの問合せ」の項の例8-1および8-2に対するコードの変更を示しています。この表の中で、文章の変更箇所は「」で、コードの変更箇所はイタリック文字で、それぞれ示されています。

表2-1 「キャッシュの問合せ」の項に対する変更

変更前の記述 変更後の記述

次の例8-1では索引を作成します。

例8-1 索引を作成するサンプル・コード

NamedCache cache = CacheFactory.getCache("MyCache");
ValueExtractor extractor = new ReflectionExtractor("getAttribute");
cache.addIndex(extractor, true, null);

例8-2のコードはNamedCacheを問い合せ、Attribute5より大きい値オブジェクトすべてに対応するキーを返します。

例8-2 NamedCacheを問い合せるサンプル・コード

NamedCache cache = CacheFactory.getCache("MyCache");
Filter filter = new GreaterFilter("getAttribute", 5);
Set keySet = cache.keySet(filter);

次の例8-1では索引を作成します。

例8-1 索引を作成するサンプル・コード

NamedCache cache = CacheFactory.getCache("MyCache");
ValueExtractor extractor = new ReflectionExtractor("getQuantity");
cache.addIndex(extractor, true, null);

「注意: 指定されている属性は、データ・オブジェクトに対するパブリックで引数を持たないメソッドを参照しています。」

例8-2のコードはNamedCacheを問い合せ、「Quantity」5より大きい値オブジェクトすべてに対応するキーを返します。

例8-2 NamedCacheを問い合せるサンプル・コード

NamedCache cache = CacheFactory.getCache("MyCache");
Filter filter = new GreaterFilter("getQuantity", 5);
Set keySet = cache.keySet(filter);

2.2「Coherenceのエディション別機能」に対する修正

『Oracle Coherenceスタート・ガイド』の「Coherenceのエディション別機能」の付録で、注意6のテキストが変更されています。

表2-2 「Coherenceのエディション別機能」の付録に対する変更

変更前の記述 変更後の記述

6. データ・クライアントおよびリアルタイム・クライアントからのInvocationServiceリクエストはクライアント専用であり、Coherence 3.2には制限があります。

6. データ・クライアントとリアルタイム・クライアントの起動は、それが接続している拡張プロキシ・サーバーで実行します。


2.3 「Coherence C++オブジェクト・モデルについて」に対する修正

この項では、『Oracle Coherenceユーザーズ・ガイド』の「Coherence C++オブジェクト・モデルについて」の章に対する変更について説明します。修正された記述は「」で示されています。

表2-3は、「スレッド・セーフティ」の項に対する変更を示しています。

表2-3 「スレッド・セーフティ」の項の記述に対する変更

変更前の記述 変更後の記述

オブジェクト・モデルにはスレッドセーフな参照カウントが含まれていますが、これによって派生クラスの状態に対するスレッド・セーフティが自動的に実現するわけではありません。多くの場合と同様、より高いレベルのスレッドセーフティを実現できるかどうかは、個々のクラスの実装にかかっています。より高いレベルのスレッドセーフティが存在するかどうかにかかわらず、参照カウントはスレッドセーフな状態で維持できます。

「ベース・オブジェクト・クラスはスレッドセーフですが、」これによって派生クラスの状態に対するスレッド・セーフティが自動的に実現「できる」わけではありません。多くの場合と同様、より高いレベルのスレッドセーフティを実現できるかどうかは、個々の「派生」クラスの実装にかかっています。「オブジェクト・モデルは、スレッドセーフなコードを作成するための機能をいくつか備えています。」


表2-4は、「スレッド・セーフなハンドル」の項に対する変更を示しています。

表2-4 「スレッド・セーフなハンドル」の項に対する変更

変更前の記述 変更後の記述

管理クラスに定義されている、ネストしたタイプのHandle、ViewおよびHolderは「スレッドセーフではありません」。つまり、複数のスレッドで1つの同じハンドルを使用している場合、そのスレッドのいずれかでこの1つのハンドルを変更して別のオブジェクトを参照する可能性があれば、これは安全な状態ではありません。ここで扱っているスレッドセーフティはハンドルに関するものであり、そのハンドルで参照するオブジェクトに関するものではない点を明確に理解しておくことが重要です。別々のスレッドからそれぞれ個別のハンドルを使用し、同期処理をせずに同じオブジェクトを参照することは安全です。

管理クラスに定義されている、ネストしたタイプのHandle、ViewおよびHolderは「意図的にスレッドセーフにはなっていません」。つまり、「複数のスレッドが1つのハンドルを共有することは安全ではありません」。ここで扱っているスレッドセーフティはハンドルに関するものであり、そのハンドルで参照するオブジェクトに関するものではない点を明確に理解しておくことが重要です。別々のスレッドからそれぞれ個別のハンドルを使用し、同期処理をせずに同じオブジェクトを参照することは安全です。

これらのタイプのハンドルをスレッドセーフティとしていないことから、ハンドルの大部分をスタックに割り当てることを前提として、パフォーマンスを大幅に最適化できます。スタックに割り当てたこれらのハンドルに対する参照を複数のスレッドで共有しないかぎり、スレッドセーフティに関する問題の発生を考慮する必要はなくなります。多くの場合、次のいずれかの条件でハンドルを共有する場合は注意が必要です。

  • 管理クラスを実装する場合。管理クラスのインスタンスは、複数のスレッドによる共有を想定する必要があります。厳密にはあり得ない状況とはいえ、管理担当者の制御が及ばない領域でオブジェクトがコードに渡された場合(キャッシュに保存された場合など)は、そのオブジェクトが他のスレッドから認識されないという保証はありません。

  • 非管理のマルチスレッド・アプリケーション・コードの場合。

これらのタイプのハンドルをスレッドセーフティとしていないことから、ハンドルの「大部分がスタックに割り当てられるので」、パフォーマンスを大幅に最適化できます。スタックに割り当てたこれらのハンドルに対する参照を複数のスレッドで共有しないかぎり、スレッドセーフティに関する問題の発生を考慮する必要はなくなります。

1つのハンドルを複数のスレッドで参照する可能性がある場合は、スレッドセーフなハンドルが必ず必要になります。一般的には次のような状況が考えられます。

  • グローバル・ハンドル - 標準のハンドル・タイプをグローバル変数または静的変数として使用することは安全ではありません。

  • 非管理のマルチスレッド・アプリケーション・コード - 複数のスレッドで共有する可能性のあるデータ構造内で標準のハンドルを使用することは安全ではありません。

  • データ・メンバーとしてのハンドルを持つ管理クラス - 管理クラスのインスタンスは複数のスレッドで共有される可能性があることを想定する必要があります。したがって、標準のハンドルをデータ・メンバーとして使用することは安全ではありません。厳密に考えれば、複数のスレッドで共有される可能性がすべての管理クラスにあるわけではありませんが、管理担当者の明示的な制御が及ばない領域で管理クラスのインスタンスがコードに渡された場合(キャッシュに格納された場合など)は、そのオブジェクトが他のスレッドから認識できないという保証はありません。

最初の状況では最適化の手段が用意されています。つまり、次の特別なスレッドセーフなハンドルを使用します。

  • coherence::lang::MemberHandle<T> - T::Handleのスレッドセーフ・バージョン

  • coherence::lang::MemberView<T> - T::Viewのスレッドセーフ・バージョン

  • coherence::lang::MemberHolder<T> - T::Holderのスレッドセーフ・バージョン

  • coherence::lang::WeakHandle<T> - Tに対するスレッドセーフなウィーク・ハンドル

  • coherence::lang::WeakView<T> - Tに対するスレッドセーフなウィーク・ハンドル

このような場合は、標準ハンドルのかわりにスレッドセーフなハンドルを使用します。オブジェクト・モデルには次のようなスレッドセーフなハンドルが用意されています。

  • coherence::lang::MemberHandle<T> - T::Handleのスレッドセーフ・バージョン

  • coherence::lang::MemberView<T> - T::Viewのスレッドセーフ・バージョン

  • coherence::lang::MemberHolder<T> - T::Holderのスレッドセーフ・バージョン

  • coherence::lang::WeakHandle<T> - Tに対するスレッドセーフなウィーク・ハンドル

  • coherence::lang::WeakView<T> - Tに対するスレッドセーフなウィーク・ハンドル

これらのハンドル・タイプは、さらに同期化を実行しなくても、複数のスレッドで読取りおよび書込みを行えます。これらは主に、他の管理クラスのデータ・メンバーとして使用されており、親タイプの内部的なアトミック状態を利用してスレッド・セーフティを実現します。これらのハンドル・タイプをコード・ブロック内で複数回アクセスする場合は、通常のスタック・ベース・ハンドルに読み取って使用することをお薦めします。この通常のスタック・ベース・ハンドルへの割当てはスレッドセーフであるため、割当てが完了すれば、基本的にはスタック・ベース・ハンドルの参照解除を自由に行えます。スレッドセーフなハンドルを初期化する場合は、最初のパラメータとしてガーディアン・オブジェクトへの参照を指定する必要があります。この参照は、包含するオブジェクトに対してself()をコールすることで取得できます。

これらのハンドル・タイプは、さらに同期化を実行しなくても、複数のスレッドで読取りおよび書込みを行えます。これらは主に、他の管理クラスのデータ・メンバーとして使用されており、「各インスタンスにはガーディアン管理オブジェクトへの参照が提供されます。ガーディアンの内部的でスレッドセーフなアトミック状態を利用してハンドルのスレッド・セーフティを実現します」。これらのハンドル・タイプをコード・ブロック内で複数回アクセスする場合は、通常のスタック・ベース・ハンドルに読み取って使用することをお薦めします。この「標準」のスタック・ベース・ハンドルへの割当てはスレッドセーフであるため、割当てが完了すれば、基本的にはスタック・ベース・ハンドルの参照解除を自由に行えます。スレッドセーフなハンドルを初期化する場合は、最初のパラメータとしてガーディアン・オブジェクトへの参照を指定する必要があります。この参照は、包含するオブジェクトに対してself()をコールすることで取得できます。

非管理クラスにも同じ手法を適用できます。非管理クラスは、coherence::lang::Objectを拡張したものではないので、スレッドセーフなハンドルのガーディアンとしては使用できません。ただし、別のオブジェクトをガーディアンとして使用することは可能です。このアプローチを採用する場合は、ガーディアン・オブジェクトの存続時間が、ガード対象のスレッドセーフなハンドルの存続時間より長いことが必要です。Coherence 3.4.1以降でこれを実現するには、System::common()をコールして、coherence::lang::Systemから永続的なガーディアンを取得します。

非管理クラスにも同じ手法を適用できます。非管理クラスは、coherence::lang::Objectを拡張したものではないので、スレッドセーフなハンドルのガーディアンとしては使用できません。ただし、別のオブジェクトをガーディアンとして使用することは可能です。このアプローチを採用する場合は、ガーディアン・オブジェクトの存続時間が、ガード対象のスレッドセーフなハンドルの存続時間より長いことが必要です。Coherence 3.4.1以降でこれを実現するには、「System::common()へのコールを経由して」、coherence::lang::Systemから「ランダムな永続的ガーディアン」を取得します。

管理クラスを作成するときは、self()をコールし、次にSystem::common()をコールしてガーディアンを取得することをお薦めします。

該当なし

次の注意を例2-18の前に追加します。

注意: まれな状況として、mutableキーワードを使用してこれらのハンドルのいずれかを宣言する場合は、コンストラクションの際にfMutabletrueに設定することで、この状況を通知する必要があります。」


表2-5は、「メモリー・リークの検出」の項に対する変更を示しています。

表2-5 「メモリー・リークの検出」の項に対する変更

変更前の記述 変更後の記述
  • object - coherence::lang::ObjectCountHeapAnalyzerが使用されます。これは、システムに存在する有効なオブジェクトの数のみに基づく簡単なヒープ分析を提供します。これはデフォルトのアナライザです。

  • object - coherence::lang::ObjectCountHeapAnalyzerが使用されます。これは、システムに存在する有効なオブジェクトの数のみに基づく簡単なヒープ分析を提供します。


2.4 「C++クライアント向け統合オブジェクトの構築」に対する修正

この項では、『Oracle Coherenceユーザーズ・ガイド』の「C++クライアント向け統合オブジェクトの構築」の章に対する変更について説明します。

表2-6は、この章の概要に対する変更を示しています。修正された記述は「」で示されています。

表2-6 「C++クライアント向け統合オブジェクトの構築」の概要に対する変更

変更前の記述 変更後の記述

C++クライアントを有効にしてCoherenceクラスタ内にC++ベースのオブジェクトを適切に格納するには、POF(Portable Object Format)と呼ばれる、プラットフォームに依存しないシリアライズ・フォーマットを使用する必要があります。POFを使用すると、値オブジェクトの作成元であるプラットフォームや言語との関係を持たない形態で、その値オブジェクトをバイナリ・ストリームにエンコードできます。

C++クライアントを有効にしてCoherenceクラスタ内にC++ベースのオブジェクトを適切に格納するには、POF(Portable Object Format)と呼ばれる、プラットフォームに依存しないシリアライズ・フォーマットを使用する必要があります。POFを使用すると、値オブジェクトの作成元であるプラットフォームや言語との関係を持たない形態で、その値オブジェクトをバイナリ・ストリームにエンコードできます。「その後は、類似のPOFベースのクラス定義を使用して、そのストリームを代替言語でデシリアライズできます。」


新しい項「POFに固有の内容」が「C++クライアント向け統合オブジェクトの構築」の章に追加されました。

POFに固有の内容

POFでは次のタイプが内部的にサポートされていますが、ユーザー側で特別な取扱いをする必要はありません。

さらに、次の一般的なインタフェースを実装するクラスには自動POFシリアライズが提供されます。

「PofSerializer(外部シリアライズ)」の項の例3-6が修正されました。修正されたコードは、太字イタリックで示されています。

#include "coherence/lang.ns"
using namespace coherence::lang;
class Address
  : public cloneable_spec<Address> // extends<Object> is implied
  {
  friend class factory<Address>;
  protected: // constructors
    Address(String::View vsCity, String::View vsState, int32_t nZip)
       : m_vsCity(self(), vsCity), m_vsState(self(), vsState), m_nZip(nZip) {}
    Address(const Address& that)
       : super(that), m_vsCity(self(), that.m_vsCity), m_sState(self(), that.m_vsState), m_nZip(that.m_nZip) {}
  public: // Address interface
    virtual String::View  getCity()  const {return m_vsCity;}
    virtual String::View  getState() const {return m_vsState;}
    virtual int32_t       getZip()   const {return m_nZip;}
  public: // Object interface
    virtual bool equals(Object::View that) const
      {
      if (instanceof<Address::View>(that))
        {
        Address::View vThat = cast<Address::View>(that);
        return getZip() == vThat->getZip() &&
               Object::equals(getState(), vThat->getState()) &&
               Object::equals(getCity(), vThat->getCity());
        }
      return false;
      }
    virtual size32_t hashCode() const
      {
      return (size32_t) m_nZip;
      }
    virtual void toStream(std::ostream& out) const
      {
      out << getCity() << ", " << getState() << "  " << getZip();
      }
  private:
    const MemberView<String> m_vsCity;
    const MemberView<String> m_vsState;
    const int32_t            m_nZip;
  };

表2-7は、「Javaクラスの必要性」の項に対する変更を示しています。修正された記述は「」で示されています。

表2-7 「Javaクラスの必要性」の項に対する変更

変更前の記述 変更後の記述

前述のアプローチのいずれかを完了すると、Coherenceクラスタにデータ・オブジェクトを保存できるようになります。これにより、オブジェクトでgetベースの操作およびputベースの操作を実行できます。しかし、問合せやエントリ・プロセッサなど、Coherenceの高度な機能を使用するには、なんらかのJavaコードを記述する必要があります。これらの高度な機能を使用するには、 CoherenceのJavaベースのキャッシュ・サーバーが、データ・オブジェクトのシリアライズ表現を保持できるだけでなく、データ・オブジェクトと相互作用できるようになっている必要があります。データ・オブジェクトと相互作用してそのプロパティにアクセスするには、Javaのいずれかのバージョンをキャッシュ・サーバーで利用できることが必要です。そのJavaのバージョンをPOFに対してシリアライズ可能にする方法は、前述の例と非常によく似ています。詳細は、com.tangosol.io.pof.PortableObjectおよびcom.tangosol.io.pof.PofSerializerを参照してください。これらはいずれも3種類のC++ベースのアプローチすべてで矛盾なく使用できます。

前述のアプローチのいずれかを完了すると、Coherenceクラスタにデータ・オブジェクトを保存できるようになります。「これだけでも、」オブジェクトでgetベースの操作およびputベースの操作を実行できます。しかし、問合せやエントリ・プロセッサなど、Coherenceの高度な機能を使用するには、なんらかのJavaコードを記述する必要があります。 「これらの高度な機能をC++クライアントから使用するには、Javaベースの」キャッシュ・サーバーが、データ・オブジェクトのシリアライズ表現を保持できるだけでなく、データ・オブジェクトと相互作用できるようになっている必要があります。データ・オブジェクトと相互作用してそのプロパティにアクセスするには、「そのデータ・オブジェクト・クラスのJavaバージョンをキャッシュ・サーバーで利用できることが必要です。」そのJavaのバージョンをPOFに対してシリアライズ可能にする方法は、前述の例と非常によく似ています。詳細は、com.tangosol.io.pof.PortableObjectおよびcom.tangosol.io.pof.PofSerializerを参照してください。これらはいずれも3種類のC++ベースのアプローチすべてで矛盾なく使用できます。「これらの対応するJavaデータ・オブジェクト・クラスをキャッシュ・サーバーで取得すると、問合せやエントリ・プロセッサなどの高度なCoherence機能をC++クライアントから直接呼び出すことができます。」


2.5 「JMXを使用したCoherenceの管理方法」に対する修正

この項では、『Oracle Coherence開発者ガイド』の「JMXを使用したCoherenceの管理方法」の章に対する変更について説明します。

表2-8は、「Coherenceの管理フレームワークの構成」の項に対する変更を示しています。変更された記述は「」で示されています。

表2-8 「Coherenceの管理フレームワークの構成」の項に対する変更

変更前の記述 変更後の記述

専用のJMXクラスタ・メンバーの使用はよく見られる手法です。この手法では、単独のクラスタ・メンバーごとにJMXソフトウェアをロードする必要がありませんが、フォルト・トレランスを引き続き提供することで、個々のJMXメンバーで問題が発生します。

専用のJMXクラスタ・メンバーの使用はよく見られる手法です。この手法では、単独のクラスタ・メンバーごとにJMXソフトウェアをロードする必要がありませんが、フォルト・トレランスを引き続き提供することで、個々のJMXメンバーで問題が発生します。「MBeanServerホストとして機能していないノードに対してtangosol.coherence.managementallに設定しておくと、そのノードが起動してクラスタへの結合に必要な時間が増加したときに、3〜5%の容量が消費されます。したがって、リモートで管理するノードに対しては、この値をnoneまたはlocal-onlyに設定することをお薦めします。」


2.6 「本番チェックリスト」に対する修正

この項では、『Oracle Coherence開発者ガイド』の「本番チェックリスト」の付録に対する変更について説明します。

表2-9は、「JVM」の項に対する変更を示しています。新しい記述は「」で示されています。

表2-9 「JVM」の項に対する変更

変更前の記述 変更後の記述

使用しているプラットフォームとCoherenceのバージョンに基づき、サポートされている最新のSun JVMを使用して、テストおよびデプロイを実施することをお薦めします。

使用しているプラットフォームとCoherenceのバージョンに基づき、サポートされている最新のSun JVMを使用して、テストおよびデプロイを実施することをお薦めします。「バージョン1.5以降のJVMでCoherenceを実行すると、1.5より古いバージョンのJVMで実行した場合と比較して、パフォーマンスが大幅に向上することが確認されています。」


表2-10は、「Coherenceのキャッシュ構成」の項に対する変更を示しています。修正された記述は「」で示されています。

表2-10 「Coherenceキャッシュ構成」の項に対する変更

変更前の記述 変更後の記述

明示的な指定がないかぎり、すべてのクラスタ・ノードはストレージ対応であり、つまりキャッシュ・サーバーとして機能します。本番環境の中でどのノードをストレージ対応とし、どのノードをストレージ非対応とするかを管理することは重要です。tangosol.coherence.distributed.localstorageシステム・プロパティをtrueまたはfalseに設定することで、この管理が可能です。一般的には、専用のキャッシュ・サーバーのみをストレージ対応とし、他のクラスタ・ノードはすべてストレージ非対応として構成します。これは、クラスタに参加してなんらかの作業を実行した後でクラスタから離れる短期間のプロセスで特に重要です。このようなノードをストレージ非対応にすると、不要な再パーティション化が発生します。

明示的な指定がないかぎり、すべてのクラスタ・ノードはストレージ対応であり、つまりキャッシュ・サーバーとして機能します。本番環境の中でどのノードをストレージ対応とし、どのノードをストレージ非対応とするかを管理することは重要です。tangosol.coherence.distributed.localstorageシステム・プロパティをtrueまたはfalseに設定することで、この管理が可能です。一般的には、専用のキャッシュ・サーバーのみをストレージ対応とし、他のクラスタ・ノードはすべてストレージ非対応として構成します。これは、クラスタに参加してなんらかの作業を実行した後でクラスタから離れる短期間のプロセスで特に重要です。このようなノードをストレージ「対応」にすると、不要な再パーティション化が発生します。