Skip to main content

This is documentation for Caché & Ensemble. See the InterSystems IRIS version of this content.Opens in a new tab

For information on migrating to InterSystems IRISOpens in a new tab, see Why Migrate to InterSystems IRIS?

Light C++ バインディング

Light C++ バインディング (LCB) は、高いパフォーマンスを主な目標としたアプリケーションの中でも最も有用なアプリケーションであり、そのクラス設計は比較的単純です。特別な目的を持つ C++ バインディングの限定されたサブセットであり、主に、永続データベースに高速にデータをロードする必要のあるアプリケーションでの使用を意図しています。例えば、未処理のリアルタイム・データを高速に取得する一部のアプリケーションでは、一般に、データをメモリ内のデータベースに格納してから、処理および永続ストレージへの転送を実行する必要があります。LCB を使用すれば、同レベルのパフォーマンスを確保しながら、フェイルオーバー機能を利用することも可能です。これをメモリ内のデータベースで行うことはできません。

オブジェクトの基本的な操作 (オブジェクトの作成、ID によるオブジェクトのオープン、更新、および削除) について、LCB を標準的な C++ バインディングと比較すると、処理が 10 ~ 20 倍も高速になります。

LCB アプリケーションの制約

追加された高速性との最も重要なトレードオフは、格納対象オブジェクトの複雑さに制限が設けられていることです。LCB アプリケーションに対する主な制約は以下のとおりです。

  • Caché は “最小” または “通常” のセキュリティ・オプションでインストールする必要があります。

  • ダイナミック・バインディングは実行されません (コード生成時にクラスがわかっている必要があります)。

  • 投影された LCB オブジェクトに対応する Caché オブジェクトがサーバ上のメモリにはないため、Caché のメソッド呼び出しを使用することはできません。

  • 既定のストレージ構造を使用する必要があります。

  • 挿入時の ID キーの重複のチェック ("エラーのチェック" を参照) や一意のインデックスの重複のチェックを除いて、整合性制約はなく、データ検証も行われません。

  • 登録クラス (一時的なクラス) はありません。

  • Transient プロパティまたは Calculated プロパティはありません。

  • データ型のリストまたは配列以外のコレクションはありません。

  • ストリーム、リレーションシップ、または保存された OID はありません。

  • プロパティおよびインデックスには、%Integer、%Float、%Decimal、%Double、%String、%Date、%Time、%TimeStamp、および %Currency の Caché データ型クラスのみがサポートされます。

  • ID キー・プロパティの型は %String、%Integer、または %Date である必要があります。

  • 標準のインデックスおよびビットマップ・インデックスのみを使用します (ビットスライス・インデックスは使用しません)。

  • トリガは実行されません (SQL を使用した場合を除く)。

  • 標準以外の LogicalToStorage 変換または StorageToLogical 変換は行われません。

  • サポートされる照合タイプは、SQL 文字列、SQL UPPER および EXACT のみです。

LCB のインストール要件の詳細は、"Light C++ バインディングのインストール" を参照してください。

Light C++ バインディング・アーキテクチャ

LCB によってパフォーマンスが向上する主な理由は、C++ アプリケーションが Caché オブジェクト・サーバとより高速に通信することにあります。LCB では、Caché を個別のサーバ・プロセスとして実行する、標準バインディングのクライアント/サーバ・アーキテクチャは使用しません。代わりに、Caché を DLL または共有オブジェクトとしてロードし、アプリケーション・プロセスの一部として実行します。以下の図は、この構造を示しています。

Light C++ バインディング・アーキテクチャ
generated description: cppliteflow

LCB と標準 C++ バインディングは共に Caché C++ ジェネレータおよび Caché C++ バインディング・ライブラリを使用しますが、実行時に大きな違いがあります。

  • LCB では、Caché と通信する際、Caché カーネルやオブジェクト・サーバのプロセス間呼び出しに、TCP/IP ではなくコールイン API を使用します。サーバと C++ アプリケーションは同じマシン上にある必要がありますが、アプリケーションで Caché ECP を使用して、リモート・マシンのデータにアクセスすることも可能です。

  • 単純なクラスについて、LCB では、サーバ・ルーチンを完全にバイパスし、コールイン関数を使用してオブジェクトのロードおよびファイリングを直接実行します。コールイン・インタフェースは、Caché データベースへのアクセスにおいて、非常に効率的な低レベルの関数を提供します。

  • オブジェクトは、対応する C++ オブジェクトに Caché データベースから直接ロードされます。Caché サーバでは、これらのオブジェクトのコピーはメモリに保持されません。つまり C++ オブジェクトは、サーバ上のオブジェクトのプロキシとして機能するだけでなく、実際のデータを含みます。

  • C++ オブジェクトには、データのメモリ内にのみ存在するコピーが含まれているため、Caché オブジェクト・サーバと永続データベースが接続されていなくても、C++ アプリケーションはそれらのオブジェクトを使用して処理を継続できます。これは、2 つ以上のスレッドで接続を共有するマルチスレッド・アプリケーションにおいて特に重要です。

  • ほとんどの LCB プロパティは標準バインディングと同様に動作しますが、非数値型の getter は参照を最適化として返します。例えば、string プロパティの getter では、シグニチャが以下のようになります。

       virtual const d_string& getname() const;
    
    

Caché C++ ライブラリの LCB クラス

Caché C++ ライブラリは、特別な一連のクラスを使用して Light C++ バインディングを実装します。これらのほとんどは、標準のバインディングで使用されるクラスの LCB バージョンです。以下のクラスは、LCB アプリケーションに必要な機能を提供します。

接続およびマルチスレッド

LCB 接続では以下のクラスを使用します。

  • d_connection — 物理接続のハンドルです。このクラスは LCB と標準バインディングの両方で使用されます。

  • LC_Database — 標準の Database クラスのサブクラスです。Database 同様、開いている d_connection から初期化されます。

  • lc_conn — 標準の tcp_conn クラスの代わりに使用される LCB 接続クラスです。接続メソッド lc_conn::connect() の構文は、tcp_conn::connect() と同じです。

以下のコード例は、これらのクラスがどのように使用されるかを示しています。このコード内の呼び出しを "Caché データベースへの接続" の例と比較してください。クラス名のみが変更されています。

   #  include "lc_connection.h"
   #  include "lc_database.h"
      Db_err conn_err; 

      d_connection conn =  lc_conn::connect(
         conn_str, user, pwd, timeout, &conn_err); 
      LC_Database db(conn);
Important:

すべての LCB アプリケーションでは、GLOBALS_HOME 環境変数は Caché インスタンスのルート・ディレクトリに設定する必要があります (“LCB 追加条件” 参照)。この環境変数が設定されていないと、すべての接続の試行に失敗します。

マルチスレッド

LCB はスレッドセーフであり、コールイン API を使用して、マルチプロセッサ・マシンでのマルチスレッドを利用した並列処理を実現します。パフォーマンスはマルチスレッド・コールイン・アプリケーションに類似しています。コールイン・アプリケーションとは異なり、LCB アプリケーションではクラス定義が変更されるたびに C++ コードを再生成できるため、クラスの実装に関する詳しい知識は必要ありません。

各スレッドでは、独立したデータベース接続 (d_connection オブジェクトおよび LC_Database オブジェクトの両方を含む) を使用する必要があります。LC_Database のメンバ関数または LC_Database インスタンスに接続したプロジェクション・オブジェクトのメンバ関数を、LC_Database オブジェクトを作成したスレッドとは異なるスレッドで呼び出すと、"Database connection may not be shared by multiple threads" という例外がスローされます。

マルチスレッド化された LCB コードの例は、<cachesys>\Dev\cpp\samples にある mttest.cpp および qtest.cpp のサンプル・プログラムを参照してください (ご使用のシステムの <cachesys> の場所については、"Caché インストール・ガイド" の "Caché の既定のインストール・ディレクトリ" を参照してください)。

接続および複数のスレッド

プロジェクション・オブジェクトは一度に 1 つのデータベース接続にしか接続できず、そのデータベース接続が作成されたスレッド内でのみ使用可能です。1 つのプロジェクション・オブジェクトを複数のスレッドで使用するには、プロジェクション・オブジェクト・メソッドの disconnect() および connect() を使用します。接続の状態を判断するには、is_connected() メソッドを使用します。

  • プロジェクション・オブジェクトは、create_new() または openid() によって返された場合のみ接続されます。

  • プロジェクション・オブジェクトの接続を切断するには、その前にプロジェクション・オブジェクトのアタッチを解除する必要があります ("LCB オブジェクトのアタッチと解除" を参照してください)。接続を切断しないと、別のデータベース接続に (再) 接続することはできません。

  • connect() および disconnect() を使用すると、1 つのスレッドをプロジェクション・オブジェクトのファクトリにでき、このオブジェクトが異なるスレッドでデータベースに挿入されます。

  • データベースにアクセスするプロジェクション・オブジェクトのメンバ関数ではスレッドの親和性が指定されますが、get<name>() および set<name>() 関数では指定されないため、スレッドセーフにはなりません。

  • 独立したデータベース接続は、異なるスレッドで並行して使用できます。

LCB オブジェクトのアタッチと解除

C++ オブジェクトには、データのメモリ内にのみ存在するコピーが含まれているため、Caché オブジェクト・サーバと永続データベースが接続されていなくても、C++ アプリケーションはそれらのオブジェクトを使用して処理を継続できます。これは、2 つ以上のスレッドでオブジェクトを共有するマルチスレッド・アプリケーションにおいて特に重要です。

オブジェクトは以下の場合にアタッチされます。

  • openid() から返されたか、オブジェクトが作成されて save() または insert() が呼び出された場合

オブジェクトは以下の場合にアタッチを解除されます。

トランザクションおよびマルチスレッド

各スレッド/データベース接続には、独自のトランザクション・コンテキストがあります。

  • Caché には、各スレッドが独立したプロセスのように見えます。2 つのスレッドで同じ接続オブジェクトを使用することはできません。

  • あるスレッドによって取得されたロックがあり、別のスレッドで同じロックを取得しようとすると、そのロックによって試行がブロックされます。

  • Database トランザクション・メソッドの tstart()tcommit()、および trollback() ("トランザクションの使用法" を参照) は、呼び出し元のスレッドにのみ影響します。

LCB でのオブジェクトの使用法

LCB の投影されたオブジェクトは、標準の C++ バインディング・オブジェクトといくつかの点で異なります。以下の場合、これらの違いについて理解していることが重要です。

  • 永続オブジェクト参照をプロパティとして使用する場合

  • 他の永続クラスから継承するクラスを使用する場合

  • 埋め込みシリアル・オブジェクト・プロパティを使用する場合

  • リストおよび配列プロパティを使用する場合

永続オブジェクト参照をプロパティとして使用する

Caché クラスが永続クラスをプロパティとして使用する場合、LCB は、そのプロパティを永続オブジェクトへの参照として投影します。各永続参照プロパティは、参照オブジェクトをポイントする lc_d_ref と、オブジェクトの ID を表す文字列で構成されます。

プロパティ・アクセサは lc_d_ref<LC_xxx>& を取得して設定します。ここで LC_xxx は、プロパティのクライアント・タイプを示します (例えば LC_User_Person は、Caché クラス User.Person のクライアント・タイプです)。論理的に、アクセサは以下のように動作します。

  • getters — オブジェクト・ポインタが Null で ID 文字列が Null でない場合、openid() を呼び出して ID 文字列を返された ID に設定し、オブジェクト・ポインタを返します。オブジェクト・ポインタと ID 文字列の両方が Null の場合は、Null オブジェクト・ポインタを返します。

  • setters — オブジェクト・ポインタを参照オブジェクトに設定します。オブジェクトに ID がある場合は ID 文字列にその ID を設定し、ID がない場合は ID 文字列を Null または空に設定します。

例えば、永続クラス Sample.Office のプロパティ Office を含む、Caché クラスの Sample.Employee を考えます。各クラスには、ユーザが割り当てた ID キー (オフィスのある市区町村の Office および従業員名の Employee) があります。以下の例は、ニューヨーク・オフィスの Office オブジェクトと John Kent の Employee オブジェクトを開いています。Kent が現在ボストン・オフィスに割り当てられている場合は、ニューヨーク・オフィスへの再割り当てを行います。

   lc_d_ref<LC_Sample_Office> o = LC_Sample_Office::openid(db, "New York"); 
   lc_d_ref<LC_Sample_Employee> e = LC_Sample_Employee::openid(db, "Kent, John");
   if (e->getOffice()->getCity() = "Boston")  {
      e->setOffice(o);
      e->save();
   }

永続参照プロパティを含むクラスについて生成されたコードでは、save() 関数、および永続参照プロパティの getter 関数と setter 関数は、通常どおりに .h ファイルにインラインで生成されるのではなく、.cpp ファイルに生成されます。これにより、投影されたクラスの .h ファイルが、循環参照によって自身を間接的に含めないようにします。

他の getter 関数とは異なり、永続参照プロパティの getter 関数は const として宣言されません。これは、参照オブジェクトをスウィズルさせる際に、その参照オブジェクトを変更する必要があるためです。

他の永続クラスから継承するクラスを使用する

Light C++ バインディングでは、そのクラスを他の永続クラスから継承する永続オブジェクトの取得および更新をサポートしています。継承するクラスに対するバッチ挿入はサポートされません。

Caché クラスの LCB プロジェクション・クラスは、その Caché クラスのスーパークラスからプロジェクション・クラスを継承します。多重継承の場合、これはスーパークラスのリストの最初のクラスにのみ適用されます。他のスーパークラスは LCB に対して透過的であり、それらのプロパティは、そのサブクラスに直接属するものとして認識されます。

スーパークラスからサブクラスのオブジェクトを開く

他のクラスから継承するクラスのオブジェクトは、そのサブクラスの C++ コードが生成されアプリケーションにリンクされている場合、継承したスーパークラスの openid メソッドで開くことができます。

例えば、クラス LC_Sample_Person から継承するクラス LC_Sample_Employee を考えます。変数 sub_idLC_Sample_Employee オブジェクトの ID が含まれる場合、以下の文を使用してオブジェクトを開くことができます。

   lc_d_ref<LC_Sample_Person> newemployee = LC_Sample_Person::openid(db, sub_id); 

LCB は対象オブジェクトの実際のクラスを検出し、サブクラス LC_Sample_Employee のオブジェクトとして newemployee を透過的に開きます。

LCB では、そのストレージ・オペレーションをクライアント側のコードで実行するため、オブジェクトの実際のクラスを認識している必要があります。サブクラスについて生成されたコードがアプリケーションにリンクされていないと、LCB ではオブジェクトをそのクラスとして開くことができません。代わりに、そのオブジェクトを、リンクされたコードが使用可能なサブクラスの最も近い祖先として開きます。この場合、アプリケーションが該当オブジェクトを更新または削除しようとすると例外がスローされます。これは、LCB ではすべてのインデックス・エントリが正しく更新または削除されることを保証できないためです。

LCB では、オブジェクトを最も具体的な可能性のあるサブクラスとして透過的に開きます。そのため、同じオブジェクトが一度はスーパークラスから、もう一度はサブクラスから開かれると、両方の lc_d_ref はメモリ内の同じサブクラス・オブジェクトを参照します。

Note:

LCB とは異なり、標準の C++ バインディングでは、オブジェクトを、openid メソッドが呼び出されたクラスであるという以上に、より具体的なサブクラスとして透過的に開くことはできません。ただし、標準のバインディングでは、(オブジェクトの実際のクラスを認識している) Caché サーバ上で実際のストレージ・オペレーションがすべて行われるため、実際にはサブクラスのオブジェクトである、スーパークラスから開いたオブジェクトを更新したり削除したりすることができます。

埋め込みシリアル・オブジェクト・プロパティを使用する

LCB オブジェクトでは、埋め込みシリアル・オブジェクトをプロパティとして持つことができます。LCB シリアル・プロパティには、そのプロパティのタイプへのポインタを返す getter 関数があります。例えば、Caché クラスの Sample.Person に、シリアル・クラス Sample.Address のプロパティ Home が含まれている場合を考えます。投影されたシリアル・プロパティの getter 関数は LC_Sample_Address *getHome() のようになります。以下の例は、ある人物の自宅の住所から古い番地を取得し、新しい番地の値を割り当てています。

   lc_d_ref<LC_Sample_Person> p = LC_Sample_Person::openid(db, 1); 
   d_string oldStreet; 
   d_string newStreet("Broadway"); 
   oldStreet = p->getHome()->getStreet(); 
   p->getHome()->setStreet(newStreet); 
   p->save(); 

(%SerialObjectOpens in a new tab に基づいて Caché クラスから投影された) LCB シリアル・クラスは、LC_Serial_t を継承します。LCB シリアル・クラスについて生成されたコードは、(.h ファイルと .cpp ファイルの両方にコードを持つ永続 LCB クラスとは異なり) ヘッダ・ファイルのみで構成されます。例えば、LC_Sample_Address.h という名前のヘッダ・ファイルには、Caché クラス Sample.Address について生成されたプロジェクション・コードのみが含まれます。

リストおよび配列プロパティを使用する

LCB で使用できるコレクション・タイプは、データ型のリストまたは配列のみです。%Integer、%Float、%Decimal、%Double、%String、%Date、%Time、%TimeStamp、および %Currency の Caché データ型クラスがサポートされています (これらのデータ型の詳細は、"単純なデータ型クラスのリファレンス" を参照してください)。

32K を超えるリストおよび配列を保存するには、長い文字列の使用を有効にする必要があります。システム全体で長い文字列のサポートを有効にするには、管理ポータルを開き、システム管理, 構成, システム構成, メモリと開始設定 を選択して、[Long String有効] チェック・ボックスにチェックを付けます。$ZUTIL(69,69) を使用すると、長い文字列の設定を一時的にオーバーライドできます。

データ型のリスト

LCB はリスト・プロパティを std::vector<d_xxx> として投影します。ここで d_xxx は有効な LCB データ型のクラスです。例えば、%StringOpens in a new tab のリストは std::vector<d_string> として投影されます。

データ型の配列

LCB は配列プロパティを std::map<d_string,d_xxx> として投影します。ここで d_xxx はプロパティの配列要素のデータ型です。例えば、%StringOpens in a new tab の配列は std::map<d_string,d_string> として投影されます。

Important:

Caché クラスで配列プロパティを定義する際、プロパティ・パラメータ STORAGEDEFAULTlist に設定する必要があります。例えば、Caché クラスでは %StringOpens in a new tab 配列を以下のように定義します。

   Property MyArray As array Of %String(STORAGEDEFAULT = "list");

既定のパラメータ値 array は LCB ではサポートされません。

標準の LCB プロジェクション・クラス・メソッド

C++ ジェネレータは、一連のメソッドと共に LCB プロジェクション・クラスを提供します。これらのメソッドは、標準のプロキシ・クラスに対して生成されたメソッドに類似しています ("標準のプロキシ・クラス・メソッド" を参照してください)。このセクションで説明するメソッドは、すべてのプロジェクション・クラスに追加されます。

BuildIndices()

Caché %BuildIndices クラス・メソッドを起動して (%Library.PersistentOpens in a new tab を参照)、クラスのインデックスを完全に再構築します。(defer_indicestrue に設定して呼び出された) save() または delete_object() の後に使用すると、パフォーマンスが向上する場合があります。

   static InterSystems::d_status BuildIndices(
      InterSystems::LC_Database * db)
connect()

プロジェクション・オブジェクトをデータベース接続に接続 (または再接続) します。オブジェクトが切断されていない場合は例外がスローされます。

   void connect(
      InterSystems::LC_Database * db)
create_new()

新規プロジェクション・オブジェクトを作成します。このプロジェクション・オブジェクトは、save() または insert() を呼び出すまでデータベースに保存されません。save() を呼び出すとオブジェクトがアタッチされ、再度 save() を呼び出すとオブジェクトが更新されます。save() を使用して別の新規オブジェクトを作成するには、最初にもう一度 create_new() を呼び出すか、detach() を呼び出す必要があります。

   static lc_d_ref<LCBclass> create_new(
      LC_Database* db,
      const_str_t init_val = 0,    // const_str_t is a typedef of const wchar_t*
      Db_err* err = 0)

LC_Persistent_t から継承された create_new() メソッドは、特定のクラス (lc_d_ref<LCBclass>。ここで LCBclass はプロジェクション・クラスの名前) への参照を返すバージョンによってオーバーライドされます。

delete_object()

開いているオブジェクトをデータベースから削除します。このメソッドを使用すると、プロジェクション・オブジェクトを破棄することなく、開いているオブジェクトをデータベースから削除できます。

   d_status delete_object(
      bool defer_indices = false,
      int timeout = -1,
      Db_err* err = 0)

delete_object() を呼び出した後も、プロジェクション・オブジェクトにはプロパティのデータ値が含まれていますが、アタッチは解除されています。オブジェクトがロックされている場合、ロックは解除されます。

delete_object() の直後に save() を呼び出すと、明示的に異なる値に設定されたプロパティを除き、同じ値を持つデータベース・オブジェクトが新規に作成されます。

detach()

データベース内のオブジェクトから、プロジェクション・オブジェクトのアタッチを解除します (オブジェクトがアタッチされていない場合は使用できません)。保持されたロックがオブジェクトで維持されている場合、ロックは解除されます。

   void detach()

プロパティ値はプロジェクション・オブジェクトに保持されます。これにより、プロジェクション・オブジェクトを再利用した、複数の新しいデータベース・オブジェクトの作成が可能になります。また、create_new() を呼び出して同じ値を持つプロパティを複数のオブジェクトにコピーするオーバーヘッドが、回避されます。

direct_save()

新しいオブジェクトを作成するための、パフォーマンスの非常に高い代替インタフェースです。これにより、プロジェクション・オブジェクトのインスタンス化およびデータ変換のオーバーヘッドが回避されます。新しいオブジェクトの挿入にのみ使用でき、既存オブジェクトの更新には使用できません。direct_save() は、Unicode データベースで使用できますが、文字列には ASCII 文字のみを使用できます。

   static d_status direct_save(
      LC_Database* db,
      const char *<prop1>,
      ..., 
      const char *<propN>)

パラメータ <prop1>...<propN> はクラスのプロパティを示します。

このメソッドではインデックス・エントリは作成されません (保存を実行した後は、BuildIndices() を使用できます)。

disconnect()

プロジェクション・オブジェクトをデータベース接続から切断します。オブジェクトのアタッチを解除していなかったり、オブジェクトの現在のデータベース接続が異なるスレッドで作成されていたりした場合は、例外がスローされます。

   void disconnect()

id()

アタッチされたオブジェクトから ID を取得します。*buf パラメータには、マルチバイト文字列または Unicode 文字列のいずれかを指定できます。

   int id(
      wchar_t *buf,
      size_t bufsiz)
   int id(
      char *buf,
      size_t bufsiz)
insert()

データベースに新しいオブジェクトを挿入します。

   d_status insert(
      bool defer_indices = false, 
      int timeout = -1, 
      Db_err* err = 0)

insert()アタッチされているオブジェクトに対して呼び出すと、オブジェクトのアタッチが解除され、同じプロパティ値を持つ新しいオブジェクトの挿入が試行されます。ユーザが割り当てた ID キーでは、これによって ID キーの重複例外が発生します。

is_attached()

プロジェクション・オブジェクトがアタッチされている場合は、true を返します。

   bool is_attached()
is_connected()

プロジェクション・オブジェクトが現在データベースに接続されている場合は、true を返します。

   bool is_connected()

openid()

ID で指定された既存のオブジェクトを開きます。プロジェクション・オブジェクトのデータ・メンバがデータベース・オブジェクトの現在の値に設定され、プロジェクション・オブジェクトがデータベース・オブジェクトにアタッチされます。

   static lc_d_ref<LCBclass> openid(
      LC_Database* db,
      const_str_t ident,         // const_str_t is a typedef of const wchar_t*
      int concurrency = -1,
      int timeout = -1,
      Db_err* err = 0)

   static lc_d_ref<LCBclass> openid(
      LC_Database* db,
      const char * ident,
      int concurrency = -1,
      int timeout = -1,
      Db_err* err = 0)

ident パラメータには、マルチバイト文字列または Unicode 文字列のいずれかを指定できます。LC_Persistent_t から継承された openid() メソッドは、特定のクラス (lc_d_ref<LCBclass>。ここで LCBclass はプロジェクション・クラスの名前) への参照を返すバージョンによってオーバーライドされます。

release_shared_lock()

プロジェクション・オブジェクトが並行処理モード LC_CONCURRENCY_SHARED_RETAINED で開かれている場合に、共有ロックを明示的に解除します ("LCB および並行処理" を参照してください)。

void release_shared_lock()

save()

プロジェクション・オブジェクトをデータベースに保存します。新規作成したオブジェクトや変更内容をデータベースに保存するには、このメソッドを明示的に呼び出す必要があります。

   d_status save(
      bool defer_indices = false,
      int timeout = -1,
      Db_err* err = 0)

プロジェクション・オブジェクトがアタッチされている場合、save() はオブジェクトを更新します。オブジェクトのアタッチが解除されている場合、save() は新規オブジェクトを作成します。トランザクションでは、tstart() および tcommit() の暗黙的な呼び出しと共に、save() が更新内容を一括します ("トランザクションの使用法" を参照してください)。

set_from_err_list()

プロジェクション・オブジェクトのプロパティ値を、バッチ挿入によって返されたエラー・リストのエントリで設定します ("LCB バッチ挿入の使用法" を参照してください)。

   void set_from_err_list(
      const std::pair<d_status,d_binary> & list_entry)
update()

既存のデータベース・オブジェクトを更新します。

   d_status update(
      bool defer_indices = false, 
      int timeout = -1, 
      Db_err* err = 0)

オブジェクトは既にアタッチされている必要があります。アタッチされていない場合は、"Object must be opened or inserted before being updated" 例外がスローされます。

LCB アプリケーションでのクエリの使用法

LCB アプリケーションのクエリは、通常のバインディングと同じ API 呼び出しを使用して ("クエリの使用法" を参照)、同様のパフォーマンスを実現します。LCB アプリケーションでクエリを実行するには、LC_Database のインスタンスをデータベース引数として d_query コンストラクタに渡します。以下はその例です。

   LC_Database *db;
   d_query q(db);

標準のバインディングに比べ、LCB クエリにはいくつかの制限があります。

  • クエリでストリーム・タイプのプロパティを参照したり、返したりすることはできません。

  • 現在はアドホック・クエリのみサポートされており、事前定義された名前付きクエリやストアド・プロシージャはサポートされていません。

  • UNIX® での認証およびセキュリティでは、LCB アプリケーションを実行するユーザが cacheusr グループに属しているか、高信頼アプリケーションを実行している必要があります ("UNIX® での高信頼アプリケーションの実行" を参照してください)。

LCB バッチ挿入の使用法

LC_Batch クラスは、Light C++ バインディングを使用したバッチ挿入メソッドを提供します。<< operator は、オブジェクトをシリアル化してバッチに追加するために使用されます。バッチを flush() メソッドで保存する場合は、各オブジェクトに個別の暗黙のトランザクションがあり、エラーが発生するとそのトランザクションがロールバックされます。get_errors() メソッドは、失敗したトランザクションのリストを返します。

パフォーマンスは save() よりもわずかに向上するだけですが、1 つのプロジェクション・オブジェクトを異なるプロパティ値で繰り返しシリアル化できるため、挿入のたびに create_new() を呼び出すよりも処理のオーバーヘッドをかなり削減できます。

  • バッチにオブジェクトを追加するには、<< operator 演算子を使用します。

    create_new() でプロジェクション・オブジェクトを作成し、そのプロパティを設定したら、<< operator を使用してオブジェクトをバッチにシリアル化できます。バッチでのシリアル化には、同じプロジェクション・オブジェクトを再利用することも、異なるプロジェクション・オブジェクトを使用することもできます。前者の場合、バッチ内のすべてのオブジェクトで同じ値を持つプロパティは、一度だけ設定する必要があります。

  • バッチからオブジェクトを削除するには、clear() を使用します。

    オブジェクトをバッチにシリアル化した後、アプリケーションでそのバッチを保存しない場合は、clear() を呼び出して、バッチのオブジェクト数を 0 にリセットする必要があります (エラーまたは ID リストはリセットされません)。

  • バッチを保存するには、flush() を使用します。

    挿入対象のすべてのオブジェクトをバッチにシリアル化したら、flush() メソッドを直接的または間接的に呼び出してバッチを保存します。close() メソッドは flush() を呼び出し、LC_Batch デストラクタは close() を呼び出します。

  • flush() を呼び出したら、get_errors() メソッドでエラー・リストを返すことができます。

    • 各リストのエントリは、エラー・ステータスとオブジェクト・シリアル化の組み合わせになります。

    • エラーがない場合、リストの size() は 0 です。

    • エラーのあるオブジェクトのプロパティを検証するには、set_from_err_list() メソッドを使用できます。

トランザクションの処理

LC_Batch() コンストラクタ_do_tx が true に設定されていると、バッチの保存時、各オブジェクトに対して個別の暗黙のトランザクションが実行されます。この暗黙のトランザクションはオブジェクトが問題なく保存されるとコミットされ、エラーが発生するとロールバックされます。バッチ全体をコミットまたはロールバックする場合は、flush() の呼び出しを、LC_Database メソッドの tstart() および tcommit() の呼び出しと共に括弧で囲む必要があります ("トランザクションの使用法" を参照してください)。これにより、エラーが発生した場合に、バッチ挿入全体がロールバックされます。

最適化

  • クラスを最適化レベル o2 でコンパイルします。

    Visual Studio で [ツール] メニュー→[オプション]→[コンパイル] タブに移動し、[クラスおよびライブラリ・クラス呼び出しの最適化] チェック・ボックスにチェックを付けます。これにより、パフォーマンスは 5 ~ 10 % 向上します。

  • 新しい LC_Batch オブジェクトを作成する場合は、reserve_size パラメータを適切に設定します。

    バッチのシリアル化バッファに必要な実際のバイト数を確保することで、パフォーマンスは向上します。これにより、バッチにオブジェクトを追加するに従って、バッファを拡大したり、データをコピーしたりする負担が回避されます。reserve_size は、少なくとも、挿入対象オブジェクト数を平均的なオブジェクト・サイズに掛けたものと同じになるように指定します。

  • do_tx パラメータを false に設定します。

    do_txfalse (既定) に設定すると、パフォーマンスが大幅に高速化されます。true に設定すると、バッチ内の挿入ごとに tstart() および tcommit() または trollback() ("トランザクションの使用法" を参照) が実行されます。

LCB および並行処理

LCB では、標準の Caché 並行処理モデルをサポートしています ("Caché オブジェクトの使用法" の "オブジェクト同時処理" を参照してください)。並行処理レベルを指定するには、以下の定数を使用します。

  • 一切ロックしない :

    #define LC_CONCURRENCY_NO_LOCKING 0
    
    
  • 作成時にはロックせず、更新時に排他ロックを利用する :

    #define LC_CONCURRENCY_ATOMIC 1
    
    
  • 作成時には共有ロックを利用し、更新時には排他ロックを利用する :

    #define LC_CONCURRENCY_SHARED 2
    
    
  • openid() の後に共有ロックを保持する :

    #define LC_CONCURRENCY_SHARED_RETAINED 3
    
    
  • openid() の後に排他ロックを保持する :

    #define LC_CONCURRENCY_EXCLUSIVE 4 
    #define LC_CONCURRENCY_DEFAULT LC_CONCURRENCY_ATOMIC
    
    

並行処理レベルはオブジェクトを開く際に指定します。以下はその例です。

   d_ref<User_Person> person = 
      User_Person::openid(db, id, LC_CONCURRENCY_EXCLUSIVE);

Note:

新規オブジェクトの作成時、既定以外の並行処理レベルは指定できません (その後 openid() を呼び出して、目的の並行処理レベルを設定できます)。LCB の並行処理の既定は、常に LC_CONCURRENCY_ATOMIC です。

意味の更新

save() または update() を呼び出すと、C++ アプリケーションによってプロパティが変更されている場合でも、データベース・オブジェクトのすべてのプロパティはプロジェクション・オブジェクトから設定されます。

オブジェクトが並行処理レベル SHARED_RETAINED または EXCLUSIVE で開かれている場合、そのオブジェクトは他のアプリケーションによる変更から保護されています。

より低い並行処理レベルでオブジェクトが開かれていると、他のユーザの更新によって設定されたプロパティが save() によって上書きされたり、削除後にオブジェクトが再作成されたりする場合があります。適切なロックが行われるので、これでオブジェクトまたはインデックスが破壊されることはありません。それまでロックされていなかったオブジェクトをロックするには、より高い並行処理レベルで openid() を再度明示的に呼び出します。これにより、データベースから現在のプロパティ値が常に再ロードされます。

SHARED-RETAINED より低い並行処理レベルで開かれたオブジェクトを更新する場合、インデックスの更新が有効になっていて、オブジェクトのインデックス付きプロパティが変更されていると、オブジェクトはロックされ、古いプロパティ値がデータベースから再ロードされます。これは、古いインデックス・エントリを削除できるようにするために必要です。

最適化およびトラブルシューティング

パフォーマンスを最適化するには以下を実行します。

  • 必要のない限り wchar_t 文字列は使用しない。

  • 不要なインデックスは使用しない。

  • 初回ロード時は defer_indices = true で保存し、インデックスは最後に構築する。

  • 可能な限り、%Float ではなく %Double でプロパティを定義する。

SUSE 12 Linux の構築問題の回避策

SUSE 12 Linux システムの Light C++ バインディング・アプリケーションを構築すると、以前のバージョンの SUSE Linux から ID (リンカ) が変更されていることによりエラーが発生するため、このエラーを発生させずに構築するには、以下の 2 つの単純な回避策のいずれかが必要です。

  • アプリケーションの構築に使用する makefile の ID または g++ コマンド行のライブラリ仕様に -lpthread を追加します。例えば、Light C++ バインディングのサンプル・アプリケーションでインストールした Master.mak ファイルの 1 つに基づいた makefile を使用する場合は、以下の行を変更します。

       CACHETLIB = -L$(CACHETPATH) -lcachet
    

    を次のように変更します。

       CACHETLIB = -L$(CACHETPATH) -lcachet -lpthread
    
  • make が呼び出される環境で、環境変数 MULTITHREADED1 に設定します。Bourne シェルでは、構文は以下のようになります。

       export MULTITHREADED=1
    

どちらかのオプションで問題が解決するか、または両方のオプションを組み合わせて使用できます。リンク対象の他のライブラリの依存ライブラリを明示的に指定するためにリンカでアプリケーション makefile が必要になったため、これらの回避策が必要になっています。リンクしたときに前記の他のライブラリが依存ライブラリを指定した場合でも同様です。この場合、libcachet.solibpthread.so に依存するため、SUSE 12 Linux 以降は、両方のライブラリを明示的に指定する必要があります。

"object not found" エラーの検出

オプションの Db_err* パラメータを指定して openid() を呼び出した場合に、指定した ID を持つオブジェクトが存在しないと、Db_err コードが -3 に設定され、msg"object not found" が設定されます。openid() の結果が割り当てられる d_refnull が設定されます。これは、is_null() メンバ関数を呼び出すことで検出できます。

d_ref を逆参照する前に、Db_err コードが 0 でないことや d_ref が Null かどうかをテストするのは、呼び出す側の責任です。Null である d_ref を逆参照すると、コード -2 および msg msg "Can not dereference a null d_ref<> value" と共に例外がスローされます。例えば、以下のコード例が ID "2" で実行され、ID 値 2 のオブジェクトが存在しないとします。

   Db_err openerr; 
      person = User_Person::openid(db, id, concurrency, timeout, &openerr); 
   if (openerr) 
      std::cerr << openerr << ",\n source = " << openerr.get_src() << '\n'; 
   else 
      printf("Object was found\n"); 
   if (person.is_null()) 
      std::wcout << L"Person with id " << id << L" doesn't exist\n"; 
   // Go ahead and dereference the d_ref whether or not it is null 
   d_string name = person->get_name(); 

オブジェクトが見つからないため、出力は以下のようになります。

  Error: code = -3, msg = object not found, 
   source = LC_Database::lc_openid_obj 
  Person with id 2 doesn't exist 
  Error: code = -2, msg = Can not dereference a null d_ref<> value, 
   source = abs_d_ref::operator->() 

LC_Database および d_connection デストラクタの呼び出し

Caché からアプリケーションを完全に切断するには、LC_Database および d_connection デストラクタを呼び出して、ライセンスとその他のリソースを解放することが重要です。この例は、lcbdemo サンプル・アプリケーションに示しています。

d_connection または LC_Database インスタンスがローカル変数として宣言されている場合、変数が範囲外になると、それらのデストラクタが自動的に呼び出されます。しかし、それらが new を介して割り当てられ、ポインタに割り当てられている場合は、C++ の "delete" を使用して明示的に破棄する必要があります。

lc_conn::connect の使用法

  • lc_conn::connect を使用すると、呼び出し元のアプリケーションの作業ディレクトリが変更されます。

    lc_conn::connect では、ZN を使用して、ネームスペースを接続文字列で指定したネームスペースに変更するので、呼び出し元のアプリケーションの現在の作業ディレクトリが変更されるという副次的作用が発生します (既定)。

    この動作は、管理ポータルのシステム構成オプション ([構成]→[詳細、ObjectScript: SwitchOSDirectory]) で無効にできます。これを "true" に設定すると、Caché では、ネームスペースの変更時、OS の現在の作業ディレクトリが変更されません (SwitchOSDirectory という名前は直感的ではありません)。これは lc_conn::connect を介する場合だけでなく、ZN のすべての使用に影響します。

  • lc_conn::connect を使用する場合は、シグナル処理を実行しないでください。

    lc_conn::connect では、さまざまなシグナルにハンドラを設定する、コールイン API CacheStart() 関数を使用しています。これらのハンドラは、呼び出し元のアプリケーションが設定したシグナル・ハンドラと競合する可能性があります。

  • lc_conn::connect() では、SIGINT ハンドラは設定されません。

    lc_conn::connect()CacheStart() を起動する際、SIGINT にはハンドラは設定されていません。そのため、ユーザ・アプリケーションに独自のハンドラを設定できます。ただし、(明示的または暗黙的に接続の d_connection オブジェクトを破棄したり、CacheEnd() を直接呼び出したりすることによって) アクティブな LCB 接続を持つすべてのスレッドでそれらを終了しない限り、ユーザ・ハンドラの実行は終了しないようにする必要があります。

FeedbackOpens in a new tab