18 シャードを使用するためのOCIインタフェース

この章では、Oracle Shardingを使用するためのOCIインタフェースについて説明します。

シャードは、各データベースがデータの一部を格納するデータベース・セットの場所です。各データベースに格納されたデータの一部は、チャンクのセットによって表され、各チャンクはデータの特定の範囲に関連付けられます。

チャンクを対象に読取りまたは書込みを行う要求を作成するには、接続開始ステップでそのチャンクを格納している適切なデータベース(シャード)にアプリケーションをルーティングする必要があります。このルーティングを行うには、データ・キーを使用します。データ・キーにより、特定のチャンクへのルーティング(シャーディング・キーを指定)またはチャンクのグループへのルーティング(スーパー・シャーディング・キーを指定)が可能になります。操作対象のチャンクを含む適切なシャードに接続するためには、アプリケーションでキーを指定してから、シャードされたOracle Databaseへの接続(スタンドアロン接続またはOCIセッション・プールから取得された接続)を取得する必要があります。OCIセッション・プールでは、プールから接続をチェックアウトする前にデータ・キーを指定する必要があります。

OCIセッション・プールおよびスタンドアロン接続の場合、シャーディング・キーおよびシャード・グループ・キーを構成して基礎となる接続でセッションを取得するステップは、次のとおりです。

  1. シャーディング・キー記述子を割り当てるため、OCIDescriptorAlloc()をコールし、シャーディング・キーを構成するためにOCI_DTYPE_SHARDING_KEYとして記述子型パラメータを指定します。

    1. シャーディング・キーのすべての列を追加するため、必要な回数だけOCIShardingKeyColumnAdd()をコールし、完全なシャーディング・キーを構成します。

    2. OCIAttrSet()をコールしてOCI_ATTR_SHARDING_KEY属性を指定し、認証ハンドルにシャーディング・キーを設定します。

  2. シャード・グループ・キー記述子を割り当てるため、OCIDescriptorAlloc()をコールし、シャード・グループ・キーを構成するためにOCI_DTYPE_SHARDING_KEYとして記述子型パラメータを指定します。

    1. シャーディング・キーのすべてのグループ列を追加するため、必要な回数だけOCIShardingKeyColumnAdd()をコールし、完全なシャード・グループ・キーを構成します。

    2. OCIAttrSet()をコールしてOCI_ATTR_SUPER_SHARDING_KEY属性を指定し、認証ハンドルにシャード・グループ・キーを設定します。

  3. シャーディング・キーおよびシャード・グループ・キー情報が含まれる前のステップの初期化済認証ハンドルを使用してOCISessionGet()をコールし、シャーディング・キーで指定されたシャードおよびチャンクと、シャード・グループ・キーで指定されたチャンクのグループに対するデータベース接続を取得します。

カスタム・プールの場合、シャーディング・キーおよびシャード・グループ・キーを構成してプールから接続をチェックアウトするステップは、次のとおりです。

  1. カスタム・プールに既存の接続がない場合、直接ステップ7に進みます。それ以外の場合、次のステップを実行します。

  2. シャーディング・キー記述子を割り当てるため、OCIDescriptorAlloc()をコールし、シャーディング・キーを構成するためにOCI_DTYPE_SHARDING_KEYとして記述子型パラメータを指定します。シャーディング・キーのすべての列を追加するため、必要な回数だけOCIShardingKeyColumnAdd()をコールし、完全なシャーディング・キーを構成します。

  3. シャード・グループ・キー記述子を割り当てるため、OCIDescriptorAlloc()をコールし、シャード・グループ・キーを構成するためにOCI_DTYPE_SHARDING_KEYとして記述子型パラメータを指定します。シャーディング・キーのすべてのグループ列を追加するため、必要な回数だけOCIShardingKeyColumnAdd()をコールし、完全なシャード・グループ・キーを構成します。

  4. シャーディング・キー、スーパー・シャーディング・キー記述子および接続文字列を使用してOCIShardInstancesGet()をコールし、指定したシャーディング・キー記述子とスーパー・シャーディング・キー記述子に応じた目的のチャンクが含まれる1つ以上のインスタンス名を戻します。

  5. カスタム・プールの各接続を調べて、それがOCIShardInstancesGet()で戻された名前を持ついずれかのインスタンスを指し示しているかどうかを確認します。カスタム・プールの接続が指し示しているインスタンスをチェックするには、サービス・コンテキスト・ハンドル(OCISvcCtx *)のOCI_ATTR_INSTNAMEを使用してインスタンス名を取得します。

  6. カスタム・プールに目的のインスタンスのいずれかを指し示す適切な接続が見つかったら、OCIAttrSet()をコールしてシャーディング・キーおよびスーパー・シャーディング・キーをその接続に関連付けます。これで、目的のシャードでアプリケーションのOCIコールを実行するための接続の準備が整いました。ステップ7はスキップできます。カスタム・プールに目的のインスタンスを指し示す適切な接続が見つからない場合は、ステップ7に進みます。

  7. 一致する接続が見つからない場合、シャーディング・キー、スーパー・シャーディング・キーおよび接続文字列を使用して新しい接続を作成し、OCISessionGet()をコールしてOCI_SESSGET_CUSTOM_POOLモードを指定することで、シャードとチャンクのマッピング情報が含まれるシャード・トポロジを明示的にキャッシュします。これにより、目的のシャードに対する接続が用意されました。これで、目的のシャードでアプリケーションのOCIコールを実行するための接続の準備が整いました。

シャーディング・キーまたはスーパー・シャーディング・キーをOCIに提供することで、目的のシャードに対する接続を取得できます。前述のとおり、目的のシャードに対する適切な接続を戻すことができるように、データベースに対するスタンドアロン接続を取得する前、またはOCIセッション・プールからの接続をチェックアウトする前に、これらのキーを指定する必要があります。

カスタム・プールの場合、プールが空であるときは、カスタム・プール実装者は、前述のステップを使用して、シャーディング・キーおよびスーパー・シャーディング・キーを(OCI_SESSGET_CUSTOM_POOLモードで)提供して目的のシャードに対するスタンドアロン接続を最初に作成し、カスタム・プールに移入できます。次に、特定のシャードへの接続に対する後続の要求について、OCI_ATTR_INSTNAMEOCIAttrGet()と組み合せて説明のとおりOCIShardInstancesGet()コールを使用して、目的のシャードに対する既存の接続がカスタム・プールにすでに存在するかどうかを確認し、存在する場合はその接続を再利用できます。

この項では、次のようなOCIインタフェースについて説明します。
  • OCIデータ型を使用してシャーディング・キーおよびスーパー・シャーディング・キーを作成します。

  • シャーディング・キーおよびスーパー・シャーディング・キーを指定して接続を作成します。

  • OCIセッション・プールからの接続要求に対してシャーディング・キーまたはスーパー・シャーディング・キーを指定します。

  • カスタム接続プーリングを使用して、指定された接続に対応するシャード名を取得し、指定されたシャーディング・キーおよびスーパー・シャーディング・キーに対応するシャード名およびチャンク名を取得します。

スタンドアロン接続のシャーディング・キーおよびスーパー・シャーディング・キーの指定について

接続を作成するにはOCISessionGet()コールを使用します。このコールは、入力として認証ハンドルauthpを使用し、そこで特定のシャードに対する接続の作成をサポートする2つの属性(シャーディング・キーの場合はOCI_ATTR_SHARDING_KEY、スーパー・シャーディング・キーの場合はOCI_ATTR_SUPER_SHARDING_KEY)を含め、様々なプロパティを設定できます。

シャーディング・キーおよびスーパー・シャーディング・キーの作成について

シャーディング・キーおよびスーパー・シャーディング・キーを構成するには、OCI記述子型のOCIShardingKeyを使用します。この記述子は、キー値(単一のパート・キーの場合)または複数値(複合キーの場合)をラップします。

次のOCIShardingKeyColumnAdd()コールを使用して、完全なキーを構成するためにキーのすべての列を追加します。
OCIShardingKeyColumnAdd(OCIShardingKey *shardingKey, 
                     OCIError    *errhp, 
                     void        *col, 
                     ub4          colLen, 
                     ub2          colType, 
                     ub4          mode)
データベースでキーが定義されている順序で、複合キーの列の数だけ(単純なシャーディング・キーの場合は1回のみ)このコールを実行する必要があります。columnTypeパラメータは、列のデータ型を示します。

次の表は、columnTypeパラメータでサポートされるOCIデータ型とその対応するCデータ型を示しています。

OCIデータ型 Cデータ型
SQLT_NUM ub1*
SQLT_CHR OraText*
SQLT_DATE ub1*
SQLT_TIMESTAMP OCIDateTime*
SQLT_RAW ub1*
SQLT_VNU ub1*
SQLY_INT int*

キャラクタ・キー値は、(NLS_LANGまたはOCIEnvNLSCreate()コールで指定された)クライアント文字セットであるとみなされます。

OCIShardingKeyColumnAdd()コールを使用してシャーディング・キーおよびスーパー・シャーディング・キーを構成した後、認証ハンドルでキーを設定するには、シャーディング・キー属性OCI_ATTR_SHARDING_KEYおよびスーパー・シャーディング・キー属性OCI_ATTR_SUPER_SHARDING_KEYを次のように使用します。

OCIAttrSet(authp, 
           OCI_HTYPE_AUTHINFO, 
           shardKey, 
           sizeof(shardKey),
           OCI_ATTR_SHARDING_KEY,
           errhp);
OCIAttrSet(authp, 
           OCI_HTYPE_AUTHINFO, 
           shardGroupKey, 
           sizeof(shardGroupKey),
           OCI_ATTR_SUPER_SHARDING_KEY, 
           errhp);

OCISessionGet()コールでこのauthpパラメータを使用すると、設定されているシャーディング・キーおよびスーパー・シャーディング・キーの値に対応するデータを含むシャードに対する接続の作成が保証されます。

シャーディング・キーおよびスーパー・シャーディング・キーの実際の値の取得について

診断目的でシャーディング・キーおよびスーパー・シャーディング・キーのBASE64表現を確認する場合、OCIShardingKey記述子でOCI_ATTR_SHARDING_KEY_B64属性を使用できます。OCIAttrGet()コールは、入力としてOCIShardingKey記述子を使用して、シャーディング・キーおよびスーパー・シャーディング・キーのBASE64形式でテキスト値を戻します。

OCIAttrGet((dvoid *) OCIShardingKey,
   (ub4)             OCI_DTYPE_SHARDING_KEY,
   (dvoid *)         &sekyVale, 
   (ub4*)            &skeyValueLen,
                     OCI_ATTR_SHARDING_KEY_B64, 
   (OCIError *)      errhp);

また、アプリケーションで次のようにOCIShardingKeyReset()コールを使用すると、新しいシャーディング・キーおよびスーパー・シャーディング・キーを作成するために、割当て済の記述子をリセットして再利用できます。

sword OCIShardingKeyReset(OCIShardingKey *shardKey, 
                          OCIError       *errhp, 
                          ub4             mode);

OCIセッション・プールから接続を取得するためのシャーディング・キーおよびスーパー・シャーディング・キーの指定について

このトピックでは、OCIセッション・プールから接続を取得するためのシャーディング・キーおよびスーパー・シャーディング・キーの指定方法について説明します。

デフォルトでは、OCISessionGet()コールにより新しい接続を作成します。このコールを使用して、OCIセッション・プールから既存の接続を取得することもできます。OCI_ATTR_SHARDING_KEY属性とOCI_ATTR_SUPER_SHARDING_KEY属性の設定を使用すると、OCIセッション・プールから目的のシャードに対する接続を取得できます。OCIセッション・プールでは、プール内のセッションは、初期化済認証ハンドルのauthpを使用してOCISessionGet()コールから渡されるデータベース資格証明によってそれぞれ認証される様々なシャードを表します。

次の例は、指定された同種および文キャッシュ・モードで作成されたOCIセッション・プールから、目的のデータベース・シャードに対する接続を取得する方法を示しています。この例では同種プールを使用していますが、そのタイプのプールに限定されるわけではありません。

OCIShardingKey   *shardKey, *shardGroupKey;
  /* Error handling is omitted for brevity. */
  /* Create a homogeneous session pool. */
  checkerr(&status, errhp,
           OCISessionPoolCreate(envhp, errhp,
                 spoolhp,                                     /* session pool handle */
                (OraText **) poolName, poolNameLenp,          /* returned poolname, length */
                (const OraText *) connstr, strlen(connstr),   /* connect string */
                 min, max, increment,                         /* pool size constraints */
                (OraText *) "hr", strlen((char *) "hr"),      /* username */
                (OraText *) apppassword,                      /* password */
                 strlen((char *) apppassword),
                 OCI_SPC_HOMOGENEOUS|OCI_SPC_STMTCACHE));     /* modes */
                
/* Allocate the sharding key and super sharding key descriptors. */
OCIDescriptorAlloc(envhp,(dvoid **)&shardKey,
               OCI_DTYPE_SHARDING_KEY, 0,(dvoid **)0)))
text *name = “KK”;
text *gname = “GOLD”;
int  empid = 150;

/* Add all the columns of the key to form the final sharding key. */
OCIShardingKeyColumnAdd(shardKey,(ub1*)&empid, sizeof(empid), 
                               SQLT_INT, errhp, OCI_DEFAULT);
OCIShardingKeyColumnAdd(shardKey, name, strlen(name), 
                               SQLT_CHAR, errhp, OCI_DEFAULT));

OCIAttrSet(authp, OCI_HTYPE_AUTHINFO,
           shardKey, sizeof(shardKey),
           OCI_ATTR_SHARDING_KEY, errhp);

/* Setting a shard group key. */
/* Create a shard group key, in the same way as for a sharding key. */
OCIDescriptorAlloc(envhp,(dvoid **)&shardGroupKey,
                   OCI_DTYPE_SHARDING_KEY, 0, (dvoid **)0));

/* Add the column of the key to form the final super sharding key. */
OCIShardingKeyColumnAdd(shardGroupKey, gname, strlen(gname),
                     SQLT_CHAR, errhp, OCI_DEFAULT)); 

OCIAttrSet(authp, OCI_HTYPE_AUTHINFO,
           shardGroupKey, sizeof(shardGroupKey),
           OCI_ATTR_SUPER_SHARDING_KEY, errhp));

/* Get the database connection from the OCI Session Pool. */
checkerr(&status,
         errhp, OCISessionGet(envhp, errhp,
                &svchp,                              /* returned database connection */
                authp,                               /* initialized authentication handle */
               (OraText *) poolName, poolNameLen,    /* connect string */
                NULL, 0, NULL, NULL, NULL,           /* session tagging parameters: optional */ 
                OCI_DEFAULT));                       /* modes */

シャーディングでのチャンク移行およびOCISessionGet()

チャンク移行では、あるシャード・インスタンスから別のシャード・インスタンスへのチャンクの移行時に、OCIセッション・プールによって、OCISessionGet()がチャンク移行時に暗黙的に再試行を行うことで、書込み可能なチャンクを含むインスタンスに対する接続を戻すことが保証されます。この場合、次のいくつかのプロパティを設定する必要があります。
  • 接続文字列でREADONLY_CHUNK_OKFALSEに設定します。

  • プール・ハンドル属性のOCI_ATTR_SPOOL_GETMODEおよびOCI_ATTR_SPOOL_WAIT_TIMEOUTを、OCI_SPOOL_ATTRVAL_TIMEDWAITと適切なタイムアウト値(ミリ秒単位)に設定します。タイムアウト期間内に書込み可能なインスタンスに対する接続をプールで取得できない場合、OCISessionGet()ORA-24495エラーを戻します。

アプリケーションで読取り専用チャンクを使用できる場合、接続文字列でREADONLY_CHUNK_OK=trueを設定できます。この場合、読取り専用とマークされたチャンクを含むインスタンスで使用できる接続も割り当てられます。このような接続でアプリケーションがデータベース書込み操作を試行すると、対応するエラーが発生します。

カスタム・プールから接続を取得するためのシャーディング・キーおよびスーパー・シャーディング・キーの指定について

このトピックでは、カスタム・プールから接続を取得するためのシャーディング・キーおよびスーパー・シャーディング・キーの指定をサポートする機能について説明します。

この項では、カスタム・プールから接続を取得するためにシャーディング・キーおよびスーパー・シャーディング・キーを指定するアプリケーションをサポートする次の機能について説明します。
  • OCISessionGet()のモードOCI_SESSGET_CUSTOM_POOL - OCIが新しいシャード・インスタンスに接続するたびに明示的にシャード・トポロジをキャッシュするために使用します。

  • OCIShardInstancesGet() - 指定されたシャーディング・キー記述子、スーパー・シャーディング・キー記述子および接続文字列に対応するインスタンス名を戻します。

OCI_ATTR_INSTNAME属性

OCIクライアント・アプリケーションでカスタム接続プーリングを使用する場合、特定のシャードに対する接続を戻すことができる必要があります。これを行うには、接続が作成されているシャードのシャード名と、一致する接続の検索を可能にするシャーディング・キーおよびスーパー・シャーディング・キーとシャード名のマッピングを確認する必要があります。

これは、この目的でサービス・コンテキスト(svchp)のOCI_ATTR_INSTNAME属性を使用することで可能になります。この属性は、指定された接続に対応するインスタンス名を戻します。インスタンス名は、指定された接続によって指し示されたシャード・インスタンスにとって一意です。どのシャード・インスタンスにも一意の名前があります。次のコード例は、この属性を使用して、指定されたサービス・コンテキストsvchpからインスタンス名を取得する方法を示しています。

OraText shardName[OCI_INSTNAME_MAXLEN];
ub4 shardNameLen;  
   OCIAttrGet(svchp,
   OCI_HTYPE_SVCCTX,
   shardName,
   (ub4 *) &shardNameLen,
   OCI_ATTR_INSTNAME,
   errhp);

OCISessionGet()のモードOCI_SESSGET_CUSTOM_POOL

カスタム・プーリングを実行するOCIクライアントは、OCISessionGet()のモードOCI_SESSGET_CUSTOM_POOLを使用して、OCIがまだアクセスしていない新しいシャードに接続するたびにシャードとチャンクのマッピング情報が含まれるシャード・トポロジを明示的にキャッシュする必要があります。カスタム・プーリングを使用しないOCIクライアントでは、このキャッシュはOCIセッション・プールの使用時などに暗黙的に実行されるため、このモードを使用する必要はありません。

OCIShardInstancesGet()

OCIShardInstancesGet()は、指定されたシャーディング・キー記述子およびスーパー・シャーディング・キー記述子に対応するインスタンス名を戻します。このメソッドのシグネチャは次のとおりです。

sword OCIShardInstancesGet(
           void            **shTopoCtx,
           OCIError         *errhp,
           const OraText    *connstr,
           ub4               constrl,
           OCIShardingKey   *shardingKey,
           OCIShardingKey   *superShardingKey,
           OCIShardinst   ***shardinsts,
           ub4               numShardInsts,
           ub4               mode);

このコールは、クライアントのシャード・トポロジ・キャッシュを参照します。

OCI_SESSGET_CUSTOM_POOLモードで接続が作成されている場合、OCIは、シャード・トポロジ・キャッシュをローカルで管理します。

OCI_SESSGET_CUSTOM_POOLで接続が作成されていないため、またはOCI_SESSGET_CUSTOM_POOLでそれまでに作成された接続により要求されたシャーディング・キーおよびスーパー・シャーディング・キーのチャンクを含むシャードに接続していないため、シャード・トポロジ・キャッシュにまだマッピングが含まれない場合、戻される値はNULLになる可能性があります。どちらの場合でも、カスタム・プールは、OCI_SESSGET_CUSTOM_POOLモードを有効にして適切に設定されたOCI_ATTR_SHARDING_KEYおよびOCI_ATTR_SUPER_SHARDING_KEY属性に基づいて、OCISessionGet()を使用して新しい接続を明示的に作成する必要があります。これを行うと、OCIシャード・トポロジ・キャッシュに新しいシャードに関する情報が追加されます。後続のOCIShardInstancesGet()コールは、これらのシャードに存在するチャンクに属するキー範囲を検索し、これらのシャード・インスタンス名を戻します。

シャーディング・キーおよびスーパー・シャーディング・キーは、レプリケートされたチャンクの結果として複数のシャードを参照する可能性があることに注意してください。カスタム・プールに目的のシャードに対する接続が含まれる場合、カスタム・プールでは、割当ての前に接続でOCI_ATTR_SHARDING_KEYおよびOCI_ATTR_SUPER_SHARDING_KEYプロパティが設定されていることを確認する必要があります。これらのプロパティを設定することで、データベース側でチャンクの使用状況を追跡し、データベースでチャンクの分断が発生していないかどうかを確認できます。

関連項目:

カスタム・プーリングを使用する場合の例は、「OCIShardInstancesGet()」を参照してください。