/* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 【機能概要】 : 共有メモリアクセスSR【本体】 Java言語、C++言語等から本SRを呼び出して、共有メモリに設定された データ値を検索・取得する GG_SHM0011_logic(検索処理)とGG_SHM0011_getData(データ取得処理) の2つで構成されている 【作成日】 : 2021.04.23 【呼出形式1】 : GG_SHM0011_logic ( int prmNum # 入力パラメータ数を入力 , char in[][GG_SHM0001_MaxPrmLen] # 各パラメータを入力(パラメータ例は以下) # テーブルID / 検索ID / key1 / value1 / key2 / value2 ・・・ ) 【戻り値1】 : int # 検索結果バイト長 【呼出形式2】 : GG_SHM0011_getData ( char *arrOut # 返却データ格納領域を指定(各行は\n区切り) # 1行目:項目名(\t区切り)、2行目以降:データ値(\t区切り) ) 【戻り値2】 : void # なし _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ #include #include #include #include #include #include #include #include #include "GG_SHMCOM.h" /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 引数構造の変遷 ※ 業務クラス⇒(1)⇒ShmStaticTableクラス⇒(2)⇒GG_SHM0001 ⇒(3)⇒GG_SHM0011_logic ⇒(4)⇒GG_SHM0001getData⇒(5)⇒GG_SHM0011_getData (1) 業務APからShmStaticTableクラスに下記の情報が渡される。 ・String TableName テーブル名称(*1) ・String Key アクセスキー(アクセス方法)名称(*2) ・HashMap in 検索カラム名(*3)& 検索パラメータ値(*4) ※)アクセスパターンファイル(例) +--------------------------+ | | |
+--------------------------+ (2) ShmStaticTableクラスは、GG_SHM0001(Javaラッパー)呼び出し時には、上記パラメータ を「一つのjbyteArray領域」に格納する。また、各領域の区切り文字に「\n」を使用する ・「jbyteArray in」の構造 (TableName)\n(Key)\n(検索カラム名1)\n(検索パラメータ値1)\n(検索カラム名2)\n(検索パラメータ値2)\n・・・ (3) GG_SHM0001からGG_SHM0011_logic(本プログラム内部ルーチン)呼び出し時には、プログラ ムの扱い易さから、上記パラメータを領域名「Prm」(char配列)に設定 Prm[1]・・(TableName) Prm[2]・・(Key) Prm[3]・・(検索カラム名1) Prm[4]・・(検索パラメータ値1) Prm[5]以降は、Prm[3]/Prm[4]の繰り返し (4) ShmStaticTableクラスは、(2)呼び出しの結果で検索結果データ長が返却される。 そのデータ長分のバイト領域をJavaで生成して、GG_SHM0001getDataを行うと、バイト 領域に検索結果データが返却される。 (5) GG_SHM0001getDataからGG_SHM0011_getData(本プログラム内部ルーチン)呼び出し時には、 (4)で生成したバイト領域のポインタを指定すると、GG_SHM0011_logicで格納した検索結果 を返却する。 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 0.共有メモリ全体配置 +-----------------------------------------+ |            1.共有メモリ管理部                   | |                                         | | +--+ +------------+                     | | |1.1 | |1.2 識別管理面情報   |                     | | +--+ +------------+                     | | +-----------------+                     | | |1.3 共有メモリ識別管理部       |                     | | +-----------------+                     | | +-----------------+ +-----------------+ | | |1.4 テーブル/共有メモリグループ(1面)   | |1.4 テーブル/共有メモリグループ(2面)   | | | +-----------------+ +-----------------+ | |                                         | +-----------------------------------------+ +-------------------+ +-------------------+ |  2.共有メモリグループ(1面)      | |  2.共有メモリグループ(2面)      | |                   | |                   | | +---------------+ | | +---------------+ | | |2.1 共有メモリ・データ管理部    | | | |2.1 共有メモリ・データ管理部    | | | +---------------+ | | +---------------+ | | +---------------+ | | +---------------+ | | |2.2  |2.3  |2.4  |2.5  | | | |2.2  |2.3  |2.4  |2.5  | | | +---------------+ | | +---------------+ | | +---------------+ | | +---------------+ | | |2.2  |2.3  |2.4  |2.5  | | | |2.2  |2.3  |2.4  |2.5  | | | +---------------+ | | +---------------+ | | +---------------+ | | +---------------+ | | |2.2  |2.3  |2.4  |2.5  | | | |2.2  |2.3  |2.4  |2.5  | | | +---------------+ | | +---------------+ | |         :         | |         :         | |         :         | |         :         | |         :         | |         :         | +-------------------+ +-------------------+ +-------------------+ +-------------------+ |  2.共有メモリグループ(1面)      | |  2.共有メモリグループ(2面)      | +-------------------+ +-------------------+ +-------------------+ +-------------------+ |  2.共有メモリグループ(1面)      | |  2.共有メモリグループ(2面)      | +-------------------+ +-------------------+ +-------------------+ +-------------------+ |  2.共有メモリグループ(1面)      | |  2.共有メモリグループ(2面)      | +-------------------+ +-------------------+ 1.共有メモリ管理部 管理部のIDおよびサイズは、GG_SHMMEMLD.shl のGG_SHM1001_MEMORYID/GG_SHM1001_MEMORYSZ で決定する。 共有メモリ管理部は単一の共有メモリIDの中で、ログレベル(1面)、識別管理面情報 (1面)と、共有メモリ識別管理(2面)を格納する。 1.1 ログレベル(long 8 byte) GG_SHM0011(共有メモリアクセスAPI)、GG_SHM1000(共有メモリ展開)等、C言語プロ グラムのログ出力レベルを格納する。商用時のログレベルは、0 1.2 識別管理面情報 共有メモリ識別管理の使用面(1 or 2)および先頭からの相対位置を格納する。 ShmFlg 共有メモリ使用面 long 8 byte TblNum_A テーブル件数(1面) long 8 byte TblNum_B テーブル件数(2面) long 8 byte 1.3 共有メモリ識別管理 共有メモリ識別管理の使用面(1 or 2)およびメモリ番号等を格納する。 s_ShmDef 共有メモリ管理領域 構造体 × 件数 ShmName 共有メモリ名称 char 32 byte ShmFlg 使用面格納フラグ(1または2) long 8 byte ShmID_A 共有メモリ番号(1面) key_t(long) 8 byte ShmID_B 共有メモリ番号(2面) key_t(long) 8 byte ShmLength 共有メモリ領域サイズ long 8 byte 1.4 テーブル/共有メモリグループ管理 テーブルが属する共有メモリグループ名称を管理する領域。 共有メモリアクセスの高速化のために生成。使用面およびレコード件数は、 「1.2 識別管理面情報」で管理。 t_TblShmDef テーブル/グループ管理 構造体 × 件数 TblId テーブル名称 char 48 byte ShmName 共有メモリグループ名称 char 32 byte 2.共有メモリグループ情報 本領域は、ShmMng.defで定義された共有メモリ管理部情報に従って領域確保を行う。 共有メモリ名称1つに対して、下記構造の領域が2つの面で構成される。 2.1 共有メモリデータ・アクセス管理部 テーブルID毎のデータ・項目情報・アクセスパターンを管理する領域 テーブルに対する属性およびメモリ展開後の格納位置・サイズが格納されている。 TblDefNum テーブル属性情報件数 long 8 byte TblDef テーブル属性情報 構造体 × 件数 TblNo テーブル番号 char 8 byte TblId テーブルID char 48 byte AcType アクセスタイプ(未使用) char 24 byte TextName データファイル名称 char 256 byte XmlFileName アクセス定義ファイル名称 char 256 byte TblName テーブル名称(未使用) char 48 byte TblDataPos テーブルデータ相対位置 long 8 byte TblDataLen テーブルデータサイズ long 8 byte TblColPos テーブルヘッダ情報相対位置 long 8 byte TblColNum テーブルヘッダ情報件数 long 8 byte TblPtnPos アクセスパターン相対位置 long 8 byte TblPtnNum アクセスパターン件数 long 8 byte 2.2 テーブルヘッダ情報部 データファイルの先頭行に格納されたテーブル項目情報から、項目名称および項目長 を管理する領域。項目長は、テーブルデータ部に格納されたデータの最大長を設定。 また、共有メモリ上の格納場所・レコード件数は、「共有メモリデータ・アクセス管 理部」で管理されている。 ColumnName 項目名称 char 256 byte ColumnSize 項目長 long 8 byte 2.3 テーブルデータ部 テーブルID毎のデータを格納する領域 テーブルデータは、項目:TAB区切り、行:改行区切り、の可変長データを固定長デー タでメモリ管理する。 また、共有メモリ上の格納場所・レコード件数は、「共有メモリデータ・アクセス管 理部」で管理されている。 2.4 アクセスパターン部 アクセス定義ファイルに格納されたアクセスパターン毎に定義情報を管理する。 共有メモリ上では、アクセス定義ファイルを解析し、'\0'区切りで下記の順番に情報 管理を行う。colを除く各項目は、全て可変長データ。 また、共有メモリ上の格納場所・レコード件数は、「共有メモリデータ・アクセス管 理部」で管理されている。 インデックスがないアクセスパターンは、AcPt[3] インデックス領域開始位置には all_0が設定される。 col AcPt(パターン)項目数 int 4 byte AcPt[0] テーブル名称 char 可変 AcPt[1] アクセスパターン名称 char 可変 AcPt[2] 条件文(where句部分) char 可変 AcPt[3] インデックス領域開始位置 char 12 byte AcPt[4] インデックスレコード長 char 12 byte AcPt[5] インデックスレコード件数 char 12 byte AcPt[6] 検索カラム名称1 char 可変 AcPt[7]以降は、AcPt[6]同様に検索カラム名称を格納 2.5 インデックス領域部 インデックスデータ(項目名/データ値)を格納する。データフォーマットは、 「2.3 テーブルデータ部」と同じであり、行の格納順番は、キー値によって 昇順に並べ直しされた状態。 インデックスを生成する条件は、以下の通り。 ・アクセスパターン名称が「Index_」から始まる ・検索条件が一つ、またはandで連結されているもの ・検索条件が「=」かつ「文字列比較」のもの 例)アクセスパターン名称が「Index_sample01」であり、検索条件が   「項目A = ? and 項目B@NUM = ? and 項目C >= ? and 項目D = ?」の場合   項目Aと項目Dによるインデックスが生成される _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ static int initFlg = 0 ; // 0 : 未初期化 , 1 : 初期化処理中 , 2 : 初期化済み */ static char **c_SHMBaseArray_A ; // 共有メモリグループ情報(1面)管理ポインタ配列(2.1参照) static char **c_SHMBaseArray_B ; // 共有メモリグループ情報(2面)管理ポインタ配列(2.1参照) static ST_ShmDef *s_ShmDefBase ; // 共有メモリ識別管理先頭ポインタ(1.3参照) static ST_ThreadMng *s_Thrd ; // 検索結果データ返却一時保存管理領域 static int ThrdNum ; // 同時走行スレッド数(100から自動拡張) static char *c_ShmMngPtr ; // 共有メモリ管理部(1.1参照) CLSSharedMemory shmAcPtMng; CLSSharedMemory shmAcPtPtr_A[ GG_SHM1001_SHMIDNUM ]; CLSSharedMemory shmAcPtPtr_B[ GG_SHM1001_SHMIDNUM ]; #ifdef _NONSTOP #define SYS_gettid 2 int syscall(int id); // NONSTOPサーバ用スレッドID取得処理(宣言) #endif int isNumber( char *str ) ; // 数値チェック処理(宣言) int to_long_double ( char *in_str , long double *out_ld ) ; // 数値変換 & チェック /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリデータ結果返却処理 GG_SHM0011_logicで検索したデータを本処理で返却する。 GG_SHM0011_logicの検索結果を特定するためにスレッドIDを使用して、一時保存した データの返却を行い、返却後はfree解放と管理テーブルの初期化を行う。 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ void GG_SHM0011_getData ( char *arrOut ) { char szLogFileTmpPath [ MAX_PATH ] ; // ログファイル名フォーマット char g_szLogFilePath [ MAX_PATH ] ; // ログファイル名 char szAccessDate [ 30 ] ; // YYYY-MM-DD HH:MM:SS.mmmmmm int ThreadId = (int)syscall(SYS_gettid) ; // スレッドID取得 // ログ出力場所の決定 getEnvString ( szLogFileTmpPath , "GG_LogFileName" , GG_SHM0011_LOGPATH , sizeof(szLogFileTmpPath) ); getLocalTimeString ( g_szLogFilePath , sizeof(g_szLogFilePath) , szLogFileTmpPath ) ; int rc = startLock(0) ; // 排他制御(mutex:0) if ( rc != 0 ) { // 排他制御開始エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御開始エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } for ( int i = 0 ; i < ThrdNum ; i++ ) { if ( s_Thrd[i].tid == syscall(SYS_gettid) ) { if ( arrOut[0] != '\0' ) { strcpy ( (char *)arrOut , s_Thrd[i].arrOut ) ; } else { // printf("検索データ無により、メモリ削除\n") ; } s_Thrd[i].tid = 0 ; free ( s_Thrd[i].arrOut ) ; s_Thrd[i].arrOut = NULL ; break ; } } rc = endLock(0) ; // 排他制御(mutex:0) if ( rc != 0 ) { // 排他制御終了エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御終了エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリデータ検索処理 共有メモリデータの検索論理を実装。 業務アプリケーションによる検索指示とパラメータ(テーブルID・検索ID・検索条件等) に従い、検索データを一時領域に格納して、検索データ長を返却する。 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int GG_SHM0011_logic( int prmNum, char Prm[][ GG_SHM0001_MaxPrmLen ] ) { char szLogFileTmpPath [ MAX_PATH ] ; // ログファイル名フォーマット char g_szLogFilePath [ MAX_PATH ] ; // ログファイル名 char szAccessDate [ 30 ] ; // YYYY-MM-DD HH:MM:SS.mmmmmm char *c_SHMBase ; // テーブルヘッダ情報部先頭ポインタ(2.2参照) char *c_SHMemory ; // 共有メモリ検索ポインタ ST_TblDef *t_TblDef ; // 共有メモリグループ管理情報(2.1参照) ST_ShmDef *s_ShmDef ; // 共有メモリ識別管理(1.3参照) int ThreadId = (int)syscall(SYS_gettid) ; // スレッドID取得 // ログ出力場所の決定 getEnvString ( szLogFileTmpPath , "GG_LogFileName" , GG_SHM0011_LOGPATH , sizeof(szLogFileTmpPath) ); getLocalTimeString ( g_szLogFilePath , sizeof(g_szLogFilePath) , szLogFileTmpPath ) ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 全スレッドで最も早く動いたスレッドが 「initFlg=0」 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( initFlg == 0 ) { // 初期化フラグを「初期化中」に変更 initFlg = 1 ; // 開始メッセージ出力 getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 1 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ初期化開始 **** START ****" , ThreadId , szAccessDate ) ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリポインタ領域初期化 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ c_SHMBaseArray_A = (char **) malloc ( GG_SHM1001_SHMIDNUM * sizeof(char *) ) ; c_SHMBaseArray_B = (char **) malloc ( GG_SHM1001_SHMIDNUM * sizeof(char *) ) ; for ( int i = 0 ; i < GG_SHM1001_SHMIDNUM ; i ++ ) { c_SHMBaseArray_A[i] = (char *)NULL ; c_SHMBaseArray_B[i] = (char *)NULL ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 検索データ一時保存管理領域の初期化 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ ThrdNum = GG_SHM0001_MaxThread ; s_Thrd = (struct ThreadMngType *) malloc ( sizeof(ST_ThreadMng) * ThrdNum ) ; for ( int i = 0 ; i < ThrdNum ; i ++ ) { s_Thrd[i].tid = 0 ; } int rc = initLock(3) ; // 排他制御(mutex:3つ初期化) if ( rc != 0 ) { // 排他制御開始エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御初期化エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリポインタ取得 ( 管理部 ) _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; key_t keyShmMainMem = getEnvLong("GG_SHM1001_MEMORYID",GG_SHM1001_MEMORYID); c_ShmMngPtr = (char *)shmAcPtMng.OpenSheredMemory( keyShmMainMem ); if (c_ShmMngPtr == NULL) { GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ取得エラー **** ID = ( %d )" , ThreadId , szAccessDate, keyShmMainMem ) ; initFlg = 3 ; return (-10); } // 先頭は、ログレベル(long型)の設定に使用 s_ShmDef = (ShmDefType *)( c_ShmMngPtr + sizeof(long) ) ; s_ShmDefBase = s_ShmDef ; // 共有メモリ初期化終了メッセージ出力 getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 1 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ初期化終了 **** END ****" , ThreadId , szAccessDate ) ; // 初期化フラグを「初期化済」に変更 initFlg = 2 ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 最も早いスレッドが初期化処理中の場合、 「initFlg=1」 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ } else if ( initFlg == 1 ) { for (;;) { #ifndef WIN32 usleep ( 1000 ) ; #else Sleep ( 1000 ) ; #endif if ( initFlg == 2 ) { s_ShmDef = s_ShmDefBase ; break ; } else if ( initFlg == 3 ) { return (-11); } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 初期化が終わっていれば、 「initFlg=2」 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ } else if ( initFlg == 2 ) { s_ShmDef = s_ShmDefBase ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 前回初期化がNGの場合ば、 「initFlg=3」 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ } else if ( initFlg == 3 ) { // 初期化フラグを「初期化中」に変更 initFlg = 1 ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリポインタ取得 ( 管理部 ) _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; key_t keyShmMainMem = getEnvLong("GG_SHM1001_MEMORYID",GG_SHM1001_MEMORYID); c_ShmMngPtr = (char *)shmAcPtMng.OpenSheredMemory( keyShmMainMem ); if (c_ShmMngPtr == NULL) { GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ取得エラー **** ID = ( %d )" , ThreadId , szAccessDate, keyShmMainMem ) ; initFlg = 3 ; return (-10); } // 先頭は、ログレベル(long型)の設定に使用 s_ShmDef = (ShmDefType *)( c_ShmMngPtr + sizeof(long) ) ; s_ShmDefBase = s_ShmDef ; // 共有メモリ初期化終了メッセージ出力 getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 1 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ初期化終了 **** END ****" , ThreadId , szAccessDate ) ; // 初期化フラグを「初期化済」に変更 initFlg = 2 ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ログレベル値を共有メモリからGG_MsgOutに設定 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int rc = startLock(1) ; // 排他制御(mutex:1) if ( rc != 0 ) { // 排他制御開始エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御開始エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } // 共有メモリのログレベルをログ出力関数に設定 long LogLevel ; memcpy ( (void *)&LogLevel , (void *)c_ShmMngPtr , sizeof(long) ) ; GG_MsgOut_SetTraceLevel ( LogLevel ) ; rc = endLock(1) ; // 排他制御(mutex:1) if ( rc != 0 ) { // 排他制御終了エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御終了エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリ管理領域を検索し、テーブル名称から共有メモリID(ShmName)を取得 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ long l_TblShmNum ; ST_TblShmDef *s_TblShmDef ; // テーブル/共有メモリグループ管理ポインタ(1.4参照) char ShmName[32] ; ST_TblShmMng *s_TblShmMng = (ST_TblShmMng *)( s_ShmDefBase + GG_SHM1001_SHMIDNUM + 1 ) ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 検索面(1面or2面)の判定 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( s_TblShmMng->ShmFlg == 1 ) { l_TblShmNum = s_TblShmMng->TblNum_A ; s_TblShmDef = (ST_TblShmDef *)( (char*)s_TblShmMng + sizeof(ST_TblShmMng) ) ; } else{ l_TblShmNum = s_TblShmMng->TblNum_B ; s_TblShmDef = (ST_TblShmDef *)( (char*)s_TblShmMng + sizeof(ST_TblShmMng) + ( sizeof(ST_TblShmDef) * 4096 ) ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ テーブルIDの検索(目的:テーブルID→共有メモリGの特定) _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int x ; for ( x = 0 ; x < l_TblShmNum ; x++ ) { if ( strcmp ( s_TblShmDef[x].TblId , Prm[1] ) == 0 ) { strcpy ( ShmName , s_TblShmDef[x].ShmName ) ; break ; } } if ( x == l_TblShmNum ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** TblId = [%s] 不正1!!" , ThreadId , szAccessDate , Prm[1] ) ; return (-12); } // 共有メモリ管理テーブル検索開始 getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ管理テーブル検索 **** START ****" , ThreadId , szAccessDate ) ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリ管理領域を検索し、共有メモリIDから検索面のポインタ(c_SHMBase)を取得 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ for ( x = 0 ; s_ShmDef->ShmName[0] != '\0' ; x++ , s_ShmDef ++ ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ管理テーブル検索 s_ShmDef[%d].ShmName=[%s] ShmName=[%s]" , ThreadId , szAccessDate , x , s_ShmDef->ShmName , ShmName ) ; if ( strcmp ( s_ShmDef->ShmName , ShmName ) == 0 ) { int rc = startLock(2) ; // 排他制御(mutex:2) if ( rc != 0 ) { // 排他制御開始エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御開始エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ管理テーブル検索 c_SHMBaseArray[%d]=[%x]" , ThreadId , szAccessDate , x , c_SHMBaseArray_A[x] ) ; if ( c_SHMBaseArray_A[x] == NULL ) { c_SHMBaseArray_A[x] = (char *)shmAcPtPtr_A[x].OpenSheredMemory( s_ShmDef->ShmID_A ); c_SHMBaseArray_B[x] = (char *)shmAcPtPtr_B[x].OpenSheredMemory( s_ShmDef->ShmID_B ); getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリグループアドレス取得 **** s_ShmDef[%d].ShmName=[%s]" , ThreadId , szAccessDate , x , s_ShmDef->ShmName ) ; } if ( c_SHMBaseArray_A[x] == NULL || c_SHMBaseArray_B[x] == NULL ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath ,0,"(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ取得エラー [%s]****" , ThreadId , szAccessDate , ShmName ) ; return (-10); } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリフラグ(1/2面)の判定により、検索領域の決定 テーブルIDが「GG_SHM0001_AllDtBack」は、非検索面を検索するため、下記の ようにc_SHMBaseにポインタ設定を行う。(通常は検索面を使用) _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( strcmp ( Prm[2] , GG_SHM0001_AllDtBack ) != 0 ) { if ( s_ShmDef->ShmFlg == 1 ) { c_SHMBase = c_SHMBaseArray_A[x] ; } else if ( s_ShmDef->ShmFlg == 2 ) { c_SHMBase = c_SHMBaseArray_B[x] ; } } else { if ( s_ShmDef->ShmFlg == 1 ) { c_SHMBase = c_SHMBaseArray_B[x] ; } else if ( s_ShmDef->ShmFlg == 2 ) { c_SHMBase = c_SHMBaseArray_A[x] ; } } rc = endLock(2) ; // 排他制御(mutex:2) if ( rc != 0 ) { // 排他制御終了エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御終了エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 メモリグループ(ShmName)=%s 面フラグ(s_ShmDef->ShmFlg)=%d" , ThreadId , szAccessDate , ShmName , s_ShmDef->ShmFlg ) ; break ; } } // 指定されたテーブルIDの共有メモリグループ名称が見つからない場合(定義ファイル記述ミス) if ( s_ShmDef->ShmName[0] == '\0' ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ論理エラー [%s] ****" , ThreadId , szAccessDate , ShmName ) ; return (-13); } // 共有メモリ管理テーブル検索終了 getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 共有メモリ管理テーブル検索 **** END ****" , ThreadId , szAccessDate ) ; long TblDefNum ; ST_TblDef t_TblInfo ; c_SHMemory = c_SHMBase ; // 開始メッセージ出力 getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 テーブルデータ取得 **** START ****" , ThreadId , szAccessDate ) ; char *TableData , *TableDataBase ; rc = startLock(0) ; // 排他制御(mutex:0) if ( rc != 0 ) { // 排他制御開始エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御開始エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 検索結果データ返却一時保存管理領域(s_Thrd)の空き領域を検索 空き領域が見つかった場合は、データ返却領域をmallocして、空き領域にスレッドID とデータポインタを設定 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int ThrdCnt = -1 ; for ( int i = 0 ; i < ThrdNum ; i++ ) { if ( s_Thrd[i].tid == 0 ) { s_Thrd[i].tid = syscall(SYS_gettid) ; // 業務AP返却用のワーク領域を生成 s_Thrd[i].arrOut = (char *) malloc ( GG_SHM0001_MaxRetDataLen ) ; TableData = s_Thrd[i].arrOut ; TableDataBase = s_Thrd[i].arrOut ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 ThreadId[%d]=%d arrOut(PTR)=%x" , ThreadId , szAccessDate , i , (int)s_Thrd[i].tid , s_Thrd[i].arrOut ) ; ThrdCnt = i ; break ; } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ s_Thrdの空き領域がなかった場合 s_Thrd領域を拡張(+100ずつ)して、同時並行可能スレッド数を自動拡張する _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( ThrdCnt == -1 ) { ST_ThreadMng *s_ThrdWork = (struct ThreadMngType *) realloc ( s_Thrd , sizeof(ST_ThreadMng) * ( ThrdNum + GG_SHM0001_MaxThread ) ) ; s_Thrd = s_ThrdWork ; int i = ThrdNum ; for ( i = ThrdNum ; i < ThrdNum + GG_SHM0001_MaxThread ; i ++ ) { s_Thrd[i].tid = 0 ; } i = ThrdNum ; s_Thrd[i].tid = syscall(SYS_gettid) ; s_Thrd[i].arrOut = (char *) malloc ( GG_SHM0001_MaxRetDataLen ) ; TableData = s_Thrd[i].arrOut ; TableDataBase = s_Thrd[i].arrOut ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** GG_SHM0011 ThreadId[%d]=%d arrOut(PTR)=%x" , ThreadId , szAccessDate , i , (int)s_Thrd[i].tid , s_Thrd[i].arrOut ) ; ThrdNum = ThrdNum + GG_SHM0001_MaxThread ; } rc = endLock(0) ; // 排他制御(mutex:0) if ( rc != 0 ) { // 排他制御終了エラー getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** GG_SHM0011 排他制御終了エラー rc=%d" , ThreadId , szAccessDate , rc ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有データ・アクセス管理部サーチ処理 業務APが指定したテーブル名称から、共有メモリ上の共有データ・アクセス 管理部をサーチし、マッチした情報をt_TblInfo(ローカル領域)に設定 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ memset ( t_TblInfo.TblNo , 0x00 , sizeof(t_TblInfo.TblNo) ) ; memcpy ( (char *)&TblDefNum , c_SHMemory , sizeof(TblDefNum) ) ; t_TblDef = (struct TblDefType *)(c_SHMemory + sizeof(TblDefNum) ) ; int TblDefPos ; for ( int i = 0 ; i < TblDefNum ; i++ ) { if ( strcmp ( t_TblDef[i].TblId , Prm[1] ) == 0 ) { memcpy ( (char *)&t_TblInfo , (char *)&t_TblDef[i] , sizeof(t_TblInfo) ) ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; // ログ出力:テーブルNo/テーブルID/アクセスタイプ/データファイル名 GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** TblNo = %s TblId = %s AcType = %s TextName = %s" , ThreadId , szAccessDate , t_TblInfo.TblNo , t_TblInfo.TblId , t_TblInfo.AcType , t_TblInfo.TextName ) ; // ログ出力:アクセスパターンファイル名/テーブル名称 GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** XmlFileName = %s TblName =%s" , ThreadId , szAccessDate , t_TblInfo.XmlFileName , t_TblInfo.TblName ) ; // ログ出力:データポインタ開始位置/共有メモリデータ長 GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** TblDataPos = %d TblDataLen = %d" , ThreadId , szAccessDate , t_TblInfo.TblDataPos , t_TblInfo.TblDataLen ) ; // ログ出力:項目名称開始位置/項目数 GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** TblColPos = %d TblColNum = %d" , ThreadId , szAccessDate , t_TblInfo.TblColPos , t_TblInfo.TblColNum ) ; // ログ出力:アクセスパターン開始位置/パターン数 GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** TblPtnPos = %d TblPtnNum = %d" , ThreadId , szAccessDate , t_TblInfo.TblPtnPos , t_TblInfo.TblPtnNum ) ; TblDefPos = i ; break ; } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 業務APが指定したアクセスパターンがない場合 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( strcmp ( t_TblInfo.TblNo , "" ) == 0 ) { // printf ( "P1 = [ %s ] 不正\n" , Prm[1] ) ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** TblId = [%s] 不正2!!" , ThreadId , szAccessDate , Prm[1] ) ; return ( -1 ) ; } c_SHMemory = c_SHMBase + t_TblInfo.TblPtnPos ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ アクセスパターンのローカル展開 業務APが設定した「TableName」、「Key」から、共有メモリ上のアクセス定義を 検索し、合致した検索条件を「AcPt」(char配列)上に設定 AcPt[0]・・テーブル名称 AcPt[1]・・アクセスパターン名称 AcPt[2]・・条件文(where句部分) AcPt[3]・・インデックス情報開始位置 AcPt[4]・・インデックスレコード長 AcPt[5]・・インデックスレコード件数 AcPt[6]・・検索カラム名称1 AcPt[7]以降は、AcPt[6]同様に検索カラム名称を格納 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int row ; char AcPt [ GG_SHM0001_MaxPrmNum ][ GG_SHM0001_MaxCondLen ] ; if ( strcmp ( Prm[2] , GG_SHM0001_AllData ) != 0 && strcmp ( Prm[2] , GG_SHM0001_AllDtBack ) != 0 ) { for ( row = 0 ; row < t_TblInfo.TblPtnNum ; row++ ) { int colnum ; memcpy ( (char *)&colnum , c_SHMemory , sizeof(colnum) ) ; c_SHMemory = c_SHMemory + sizeof(colnum) ; int col ; for ( col = 0 ; col < colnum ; col++ ) { strcpy ( AcPt[col] , c_SHMemory ) ; AcPt[col+1][0] = '\0' ; c_SHMemory = c_SHMemory + strlen(AcPt[col]) + 1 ; } if ( strcmp ( AcPt[1] , Prm[2] ) == 0 ) { for ( col = 0 ; col < colnum ; col++ ) { // アクセスパターン情報のログ出力 getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** AcPt[%d] = [%s]" , ThreadId , szAccessDate , col , AcPt[col] ) ; } break ; } } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ データ全件検索/逆面データ全件検索のアクセスパターン指定 業務APが「Key」に「AllDataOutput」を指定した場合、検索条件がアクセスパターン 上に存在しなくても、全件データの返却を行うようにする また、「AllDataOutput-back」を指定した場合、共有メモリA面使用中にはB面、B面 使用中にはA面の全件データを返却する _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( strcmp ( Prm[2] , GG_SHM0001_AllData ) == 0 ) { strcpy ( AcPt[0] , Prm[0] ) ; strcpy ( AcPt[1] , GG_SHM0001_AllData ) ; AcPt[2][0] = '\0' ; AcPt[3][0] = '\0' ; } else if ( strcmp ( Prm[2] , GG_SHM0001_AllDtBack ) == 0 ) { strcpy ( AcPt[0] , Prm[0] ) ; strcpy ( AcPt[1] , GG_SHM0001_AllDtBack ) ; AcPt[2][0] = '\0' ; AcPt[3][0] = '\0' ; } else if ( row == t_TblInfo.TblPtnNum ) { // printf ( "P2 = [ %s ] 不正\n" , Prm[2] ) ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** AccessPtn = [%s] 不正!!" , ThreadId , szAccessDate , Prm[2] ) ; return ( -2 ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 共有メモリの検索条件文(AcPt[2])の解析・分解と、ローカル展開(下記に分解) Left[n] ・・検索カラム名称を設定 Hikaku[n] ・・=, !=, <, >, <=, >= のいずれかを設定 Right[n] ・・検索パラメータ値(?または固定値)を設定 Ketugo[n] ・・and, or のいずれかを設定 nは、検索条件の内容により可変(最大19の条件設定が可能) _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ char Left [GG_SHM0001_MaxCond][GG_SHM0001_MaxLeftLen] ; int Left_Nid [GG_SHM0001_MaxCond] ; char Hikaku [GG_SHM0001_MaxCond][5] ; char Right [GG_SHM0001_MaxCond][GG_SHM0001_MaxRightLen] ; long double Right_Num [GG_SHM0001_MaxCond] ; char Ketugo [GG_SHM0001_MaxCond][5] ; int Index_Pos [GG_SHM0001_MaxCond] ; Ketugo[0][0] = '\0' ; if ( strcmp ( AcPt[1] , GG_SHM0001_AllData ) != 0 && strcmp ( AcPt[1] , GG_SHM0001_AllDtBack ) != 0 ) { for ( int i=0 ,j=0 ,k=0; i <= strlen(AcPt[2]) ; i++ ) { int p = k / 4 ; int q = k % 4 ; if ( AcPt[2][i] == ' ' || i == strlen(AcPt[2]) ) { if ( q==0 ) { memcpy ( Left[p] , AcPt[2]+j , i-j ) ; Left[p][i-j] = '\0' ; Left[p+1][0] = '\0' ; // @NUM対応 char *Left_Num_Pos = strchr ( Left[p] , '@' ) ; if ( Left_Num_Pos != NULL ) { // 左項目名から@NUMを削除 *Left_Num_Pos = '\0' ; Left_Nid[p] = 1 ; } else { Left_Nid[p] = 0 ; } } else if ( q==1 ) { memcpy ( Hikaku[p] , AcPt[2]+j , i-j ) ; Hikaku[p][i-j] = '\0' ; Hikaku[p+1][0] = '\0' ; } else if ( q==2 ) { memcpy ( Right[p] , AcPt[2]+j , i-j ) ; Right[p][i-j] = '\0' ; Right[p+1][0] = '\0' ; } else if ( q==3 ) { memcpy ( Ketugo[p] , AcPt[2]+j , i-j ) ; Ketugo[p][i-j] = '\0' ; Ketugo[p+1][0] = '\0' ; } j = i + 1 ; k++ ; } } } else { Left[0][0] = '\0' ; Hikaku[0][0] = '\0' ; Right[0][0] = '\0' ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 検索条件文(AcPt[2])の分解結果のログ出力 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ for ( int i=0 ; Left[i][0] != '\0' ; i++ ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** Left[%s] Hikaku[%s] Right[%s] Ketugo[%s]" , ThreadId , szAccessDate ,Left[i] ,Hikaku[i] ,Right[i] ,Ketugo[i] ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 検索パラメータ置換処理 業務APが設定した「in」(HashMap:検索カラム名と検索パラメータ値)の検索 カラム名(Prm[3]、3,5,7・・)と共有メモリ上の検索カラム名称(AcPt[6]、6,7,8・・) を比較する。合致した場合、共有メモリのパラメータ順(AcPt[6,7,8・・])に従い、 Right[n]の「?」をPrm[3,5,7・・]のデータに置換 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ for ( int i = 0 ; AcPt[ i + PARM_STARTPOS ][0] != '\0' ; i++ ) { int j ; for ( j = 0 ; prmNum >= j*2+4 ; j++ ) { if ( strcmp ( AcPt[ i + PARM_STARTPOS ] , Prm[j*2+3] ) == 0 ) { int k ; for ( k = 0 ; Right[k][0] != '\0' ; k++ ) { if ( strcmp ( Right[k] , "?" ) == 0 ) { strcpy ( Right[k] , Prm[j*2+4] ) ; // 数値比較:入力パラメータの数値変換 if ( Left_Nid[k] == 1 ) { if ( to_long_double ( Right[k] , &Right_Num[k] ) < 0 ) { // エラー処理 // 検索条件に「@NUM」が指定されたにも関わらず、業務APから当該項目に数字以外の // 値が設定された場合 getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** [ %s ] = [ %s ] 数字比較項目に数値以外が設定された" , ThreadId , szAccessDate , Prm[j*2+3] , Prm[j*2+4] ) ; return (-3) ; } // ログ出力(数値の確からしさ) getLocalTimeString ( szAccessDate , sizeof(szAccessDate), "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** Right_Num[%d] = %Lf" , ThreadId , szAccessDate , k , Right_Num[k] ) ; } break ; } } // エラー処理 // 条件文の「?」の数 < 業務APの検索カラム名称の数(またはアクセスパターンのカラム数) // が不一致だった場合 if ( Right[k][0] == '\0' ) { for ( j = 3 ; j <= prmNum ; j++ ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** Prm[%d] = [%s]" , ThreadId , szAccessDate ,j , Prm[j*2+3] ) ; } getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** 検索パラメータが共有メモリ検索項目にありません2!!" , ThreadId , szAccessDate ) ; return ( -4 ) ; } break ; } } // エラー処理 // 業務APの検索カラムが、共有メモリの検索カラムになかった場合 if ( prmNum < j*2+4 && strcmp ( AcPt[1] , GG_SHM0001_AllData ) != 0 && strcmp ( AcPt[1] , GG_SHM0001_AllDtBack ) != 0 ) { // printf("j=%d\n",j) ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; for ( j = 0 ; j*2+4 <= prmNum ; j++ ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** Prm[%d] = [%s]" , ThreadId , szAccessDate ,j*2+3 , Prm[j*2+3] ) ; } GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** 検索パラメータが共有メモリ検索項目にありません!!" , ThreadId , szAccessDate ) ; return ( -4 ) ; } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 検索条件文(AcPt[2])の分解結果に、「?」置換結果を加えてログ出力 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ for ( int i=0 ; Left[i][0] != '\0' ; i++ ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 4 , "(%05d) **** ( %s ) **** Left[%s] Hikaku[%s] Right[%s] Ketugo[%s]" , ThreadId , szAccessDate ,Left[i] ,Hikaku[i] ,Right[i] ,Ketugo[i] ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ヘッダデータ返却処理 データ返却領域の先頭に、テーブルのヘッダデータを設定する。 ヘッダデータは、Column名1(TAB)Column名2(TAB)・・というように設定し、 最後に(改行)を設定する。 また、検索条件文で比較対象となったデータ項目は、行毎の開始位置とデータ長 を Leftpos[n]/Leftlen[n] に設定する。 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ ST_ColumnDef *t_ColumnDef ; long TblDataLen = 0 ; int Leftpos [GG_SHM0001_MaxCond] ; int Leftlen [GG_SHM0001_MaxCond] ; t_ColumnDef = (struct ColumnDefType *)(c_SHMBase + t_TblInfo.TblColPos) ; for ( int j = 0 ; Left[j][0] != '\0' ; j ++ ) { TblDataLen = 0 ; for ( int i = 0 ; i < t_TblInfo.TblColNum ; i ++ ) { if ( strcmp ( Left[j] , t_ColumnDef[i].ColumnName ) == 0 ) { Leftpos[j] = TblDataLen ; Leftlen[j] = t_ColumnDef[i].ColumnSize ; break ; } TblDataLen = TblDataLen + t_ColumnDef[i].ColumnSize ; } } TblDataLen = 0 ; for ( int i = 0 ; i < t_TblInfo.TblColNum ; i ++ ) { strcpy ( TableData , t_ColumnDef[i].ColumnName ) ; TableData = TableData + strlen(t_ColumnDef[i].ColumnName) ; TableData [0] = '\t' ; TableData ++ ; TblDataLen = TblDataLen + t_ColumnDef[i].ColumnSize ; } TableData -- ; TableData [0] = '\n' ; TableData ++ ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ データ検索・返却処理 検索条件と業務APが設定した値(バインド変数)にしたがって共有メモリデータの 検索を行う。 検索データはヘッダデータ同様、データ値1(TAB)データ値2(TAB)・・というように 設定し、行の最後に(改行)を設定する。 ・Full-Scan検索 ・全件検索(裏面全件検索) ・Index検索 の3パターンの検索方法ごとに処理を実装する。 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ c_SHMemory = c_SHMBase + t_TblInfo.TblDataPos ; long k = 0 ; int TblBufSize = GG_SHM0001_MaxRetDataLen ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Full-Scan検索、および全件検索の場合 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( strcmp ( AcPt[1] , GG_SHM0001_AllData ) == 0 || strcmp ( AcPt[1] , GG_SHM0001_AllDtBack ) == 0 || strcmp ( AcPt[3] , PARM_FULLSCAN ) == 0 ) { for ( int i = 0 ; i < t_TblInfo.TblDataLen ; ) { /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 通常のデータ検索の場合 (全件、逆面全面検索以外) データ返却領域に検索条件にマッチしたデータを格納する。 共有メモリデータは、各カラムとも固定長で管理されているため、業務APから 業務APから受け取った検索パラメータ値を共有メモリデータのカラム長にスペ ースパディングして比較を行う。(sprintfを使用) 比較結合識別子(Ketugo)は、Ketugo[0]に従って比較の繰り返しを行う。 比較結合識別子が「or」の場合、比較条件が一つでもマッチしたら返却領域に設定 を行う。「and」の場合、全ての比較条件がマッチするまで、比較を行う。 Ketugo[j]に設定されていなければ、「j-1」の比較でマッチング終了。 検索対象データは、共有メモリ上の固定長データのカラムの区切り文字として、 TAB文字を追加設定して、設定する。 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int match = 1 ; // 0 : データmatch 、 1 : データunmatch if ( strcmp ( AcPt[1] , GG_SHM0001_AllData ) != 0 && strcmp ( AcPt[1] , GG_SHM0001_AllDtBack ) != 0 ) { for ( int j = 0 ; Left[j][0] != '\0' ; j ++ ) { int comLeftLen ; // パディング値(0x1f)の削除 for ( comLeftLen=Leftlen[j]-1 ; comLeftLen>=0 ; comLeftLen-- ) { if ( (unsigned char)(c_SHMemory+i+Leftpos[j]+comLeftLen)[0] != (unsigned char)SP_REP ) { break ; } } comLeftLen++ ; long hkk = 0 ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 文字列比較の場合 / Left_Nid[j] == 0 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( Left_Nid[j] == 0 ) { // 業務APのパラメータ文字数が共有メモリデータの文字数より大きい場合 if ( strlen(Right[j]) > comLeftLen ) { // 業務APのパラメータ文字をスペースパディング int RightLen = strlen(Right[j])-1 ; for ( ; RightLen >= comLeftLen ; RightLen-- ) { if ( Right[j][RightLen] != ' ' ) break ; } RightLen++ ; Right[j][RightLen] = '\0' ; // 共有メモリデータをローカル領域に設定 char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , c_SHMemory + i + Leftpos[j] , comLeftLen ) ; shmChar [ comLeftLen ] = '\0' ; // 業務APパラメータと共有メモリデータの比較 hkk = (long)strcmp ( shmChar , Right[j] ) ; free ( shmChar ) ; } else // 業務APのパラメータ文字数が共有メモリデータの文字数より小さい場合 if ( strlen(Right[j]) < comLeftLen ) { // 共有メモリデータをローカル領域に設定 char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , c_SHMemory + i + Leftpos[j] , comLeftLen ) ; shmChar [ comLeftLen ] = '\0' ; // 共有メモリデータの文字をスペースパディング comLeftLen-- ; for ( ; comLeftLen >= strlen(Right[j]) ; comLeftLen-- ) { if ( shmChar[comLeftLen] != ' ' ) break ; } comLeftLen++ ; shmChar[comLeftLen] = '\0' ; // 業務APパラメータと共有メモリデータの比較 hkk = (long)strcmp ( shmChar , Right[j] ) ; free ( shmChar ) ; // 業務APのパラメータ文字数が共有メモリデータの文字数が同じ場合 } else { // 業務APパラメータと共有メモリデータの比較 hkk = (long)memcmp ( c_SHMemory + i + Leftpos[j] , Right[j] , comLeftLen ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 数値比較の場合 / Left_Nid[j] == 1 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ } else { // 共有メモリデータをローカル領域に設定 char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , c_SHMemory + i + Leftpos[j] , comLeftLen ) ; shmChar [ comLeftLen ] = '\0' ; // 共有メモリデータ値を「long double型」に変換 // 変換仕様は、標準関数strtoldに従う long double Left_Num ; int rc = to_long_double ( shmChar , &Left_Num ) ; // 比較結果をhkk(long型)に設定 if ( Left_Num == Right_Num[j] ) { hkk = 0 ; } else if ( Left_Num > Right_Num[j] ) { hkk = 1 ; } else if ( Left_Num < Right_Num[j] ) { hkk = -1 ; } free ( shmChar ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ アクセスパターンの検索方法と比較結果が一致した場合 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( ( strcmp ( Hikaku[j] , "=" ) == 0 && hkk == 0 ) || ( strcmp ( Hikaku[j] , "<" ) == 0 && hkk < 0 ) || ( strcmp ( Hikaku[j] , "<=" ) == 0 && hkk <= 0 ) || ( strcmp ( Hikaku[j] , ">" ) == 0 && hkk > 0 ) || ( strcmp ( Hikaku[j] , ">=" ) == 0 && hkk >= 0 ) || ( strcmp ( Hikaku[j] , "!=" ) == 0 && hkk != 0 ) ){ // 検索方法の結合子が「or」または検索が完了した場合(検索対象データとして確定) if ( strcmp ( Ketugo[0] , "or" ) == 0 || Ketugo[j][0] == '\0' ) { match = 0 ; break ; } else if ( strcmp ( Ketugo[0] , "and" ) == 0 ) { continue ; } else { // printf ( "比較演算子不正!! [%s]\n" , Ketugo[j] ) ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** 比較演算子不正!! Ketugo[%s]" , ThreadId , szAccessDate ,Ketugo[j] ) ; return ( -5 ) ; } // 比較方法と比較結果が不一致の場合 } else { // 比較方法の結合子が「or」で、検索が完了していない場合は、次のデータ比較を継続 if ( strcmp ( Ketugo[0] , "or" ) == 0 && Ketugo[j][0] != '\0' ) continue ; // 上記以外は、当該データは検索対象外に決定 match = 1 ; break ; } } } else // 全件、または逆面全面検索の場合、条件に関わらず返却領域にデータ設定 if ( strcmp ( AcPt[1] , GG_SHM0001_AllData ) == 0 || strcmp ( AcPt[1] , GG_SHM0001_AllDtBack ) == 0 ) { match = 0 ; } if ( match == 0 ) { // 共有メモリデータを返却領域にコピー int ColSzWrok = 0 ; for ( int h = 0 ; h < t_TblInfo.TblColNum ; h ++ ) { memcpy ( TableData , c_SHMemory + i + ColSzWrok , t_ColumnDef[h].ColumnSize ) ; TableData [ t_ColumnDef[h].ColumnSize ] = '\t' ; TableData = TableData + t_ColumnDef[h].ColumnSize + 1 ; ColSzWrok = ColSzWrok + t_ColumnDef[h].ColumnSize ; } TableData -- ; TableData [0] = '\n' ; TableData [1] = '\0' ; TableData = TableData + 1 ; k ++ ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 返却データのサイズが、TableDataBase で確保した返却領域の1/2を越えた場合、 返却データのサイズを2倍に拡張(malloc→memcpy→freeにより実施) _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( TblBufSize / 2 < (size_t)TableData - (size_t)TableDataBase ) { TblBufSize = TblBufSize * 2 ; char *TableDataTmp = (char *) malloc ( TblBufSize ) ; if ( TableDataTmp != NULL ) { memcpy ( TableDataTmp , TableDataBase , (size_t)TableData - (size_t)TableDataBase ) ; TableData = TableDataTmp + ( (size_t)TableData-(size_t)TableDataBase ) ; free ( TableDataBase ) ; TableDataBase = TableDataTmp ; startLock(0) ; // 排他制御(mutex:0) for ( int m = 0 ; m < ThrdNum ; m++ ) { if ( s_Thrd[m].tid == syscall(SYS_gettid) ) { s_Thrd[m].arrOut = TableDataBase ; break ; } } endLock(0) ; // 排他制御(mutex:0) } else { getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** realloc エラー発生!! DATA[%-100s]" , ThreadId , szAccessDate ,TableDataBase ) ; return ( -6 ) ; } } } i = i + TblDataLen ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ Index検索の場合 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ } else { getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** Index 検索開始" , ThreadId , szAccessDate ) ; int IndexLeftpos [GG_SHM0001_MaxCond] ; // インデックス項目と比較データ位置の抽出 // インデックス項目は、比較方法が「=」でかつ、文字列比較の場合が該当 for ( int j = 0 , p = 0 ,q = 0 ; Left[j][0] != '\0' ; j ++ ) { if ( strcmp ( Hikaku[j] , "=" ) == 0 ) { char *Left_Num_Pos = strchr ( Left[j] , '@' ) ; if ( Left_Num_Pos == NULL ) { Index_Pos[p] = j ; Index_Pos[p+1] = -1 ; IndexLeftpos[p] = q ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** Left[%d]=%s : (%d,%d)" , ThreadId , szAccessDate , j , Left[j] , Index_Pos[p] , IndexLeftpos[p] ) ; p ++ ; q += t_ColumnDef[j].ColumnSize ; } } } long stPos = atol ( AcPt[3] ) ; // インデックス開始位置(共有メモリ相対位置) long recLn = atol ( AcPt[4] ) ; // インデックスレコード長 long rowNm = atol ( AcPt[5] ) ; // インデックス件数 long st = 0 ; // インデックス検索レコード開始位置 long ed = rowNm - 1 ; // インデックス検索レコード終了位置 long search = stPos + ( st + ed ) / 2 * recLn ; // 検索行(バイナリサーチ) long stMatch = -1 ; // マッチング最上位行 long edMatch = -1 ; // マッチング最下位行 long hkk = 0 ; // 比較結果 for ( int j = 0 , p = 0 ;; ) { j = Index_Pos[p] ; // インデックス比較項目相対番号 // パディング値(0x1f)の削除 int comLeftLen ; for ( comLeftLen=Leftlen[j]-1 ; comLeftLen>=0 ; comLeftLen-- ) { if ( (unsigned char)(c_SHMBase + search + IndexLeftpos[p] + comLeftLen)[0] != (unsigned char)SP_REP ) { break ; } } comLeftLen ++ ; // 業務APのパラメータ文字数が共有メモリデータの文字数より大きい場合 if ( strlen(Right[j]) > comLeftLen ) { // 業務APのパラメータ文字をスペースパディング int RightLen = strlen(Right[j])-1 ; for ( ; RightLen >= comLeftLen ; RightLen-- ) { if ( Right[j][RightLen] != ' ' ) break ; } RightLen++ ; Right[j][RightLen] = '\0' ; // 共有メモリデータをローカル領域に設定 char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , c_SHMBase + search + IndexLeftpos[p] , comLeftLen ) ; shmChar [ comLeftLen ] = '\0' ; // 業務APパラメータと共有メモリデータの比較 hkk = (long)strcmp ( shmChar , Right[j] ) ; /* ログ出力ロジック */ if ( LogLevel >= 9 ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** Index比較 行番号=%d 列番号=%d パラメータ=[%s] メモリ=[%s]" , ThreadId , szAccessDate ,search , j , Right[j] , shmChar ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** stPos=%d st=%d ed=%d recLn=%d" , ThreadId , szAccessDate , stPos , st , ed , recLn ) ; } free ( shmChar ) ; // 業務APのパラメータ文字数が共有メモリデータの文字数より小さい場合 } else if ( strlen(Right[j]) < comLeftLen ) { // 共有メモリデータをローカル領域に設定 char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , c_SHMBase + search + IndexLeftpos[p] , comLeftLen ) ; shmChar [ comLeftLen ] = '\0' ; // 共有メモリデータの文字をスペースパディング comLeftLen-- ; for ( ; comLeftLen >= strlen(Right[j]) ; comLeftLen-- ) { if ( shmChar[comLeftLen] != ' ' ) break ; } comLeftLen++ ; shmChar[comLeftLen] = '\0' ; // 業務APパラメータと共有メモリデータの比較 hkk = (long)strcmp ( shmChar , Right[j] ) ; /* ログ出力ロジック */ if ( LogLevel >= 9 ) { getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** Index比較 行番号=%d 列番号=%d パラメータ=[%s] メモリ=[%s]" , ThreadId , szAccessDate ,search , j , Right[j] , shmChar ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** stPos=%d st=%d ed=%d recLn=%d" , ThreadId , szAccessDate , stPos , st , ed , recLn ) ; } free ( shmChar ) ; } else { // 業務APパラメータと共有メモリデータの比較 hkk = (long)memcmp ( c_SHMBase + search + IndexLeftpos[p] , Right[j] , comLeftLen ) ; /* ログ出力ロジック */ if ( LogLevel >= 9 ) { char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , c_SHMBase + search + IndexLeftpos[p] , comLeftLen ) ; shmChar[comLeftLen] = '\0' ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** Index比較 行番号=%d 列番号=%d パラメータ=[%s] メモリ=[%s]" , ThreadId , szAccessDate ,search , j , Right[j] , shmChar ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** stPos=%d st=%d ed=%d recLn=%d" , ThreadId , szAccessDate , stPos , st , ed , recLn ) ; free ( shmChar ) ; } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ バイナリサーチロジック1 1. 共有メモリデータ > 業務APのパラメータ 1.1 検索範囲が1行になったら、break 1.2 マッチング最上位行が決まっていなければ、検索範囲最下位行を[比較行-1]に設定 1.3 マッチング最上位行が決まっていれば、検索範囲最下位行を[比較行-1]に設定 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( hkk > 0 ) { if ( st == ed ) break ; if ( stMatch == -1 ) { ed = ( st + ed ) / 2 - 1 ; search = stPos + ( st + ed ) / 2 * recLn ; } else { ed = (st+ed)/2 + (st+ed)%2 - 1 ; search = stPos + ( (st+ed)/2 + (st+ed)%2 ) * recLn ; } p = 0 ; continue ; } else /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ バイナリサーチロジック2 2. 共有メモリデータ < 業務APのパラメータ 2.1 検索範囲が1行になったら、break 2.2 マッチング最上位行が決まっていなければ、検索範囲最上位行を[比較行+1]に設定 2.3 マッチング最上位行が決まっていれば、検索範囲最上位行を[比較行+1]に設定 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( hkk < 0 ) { if ( st == ed ) break ; if ( stMatch == -1 ) { st = ( st + ed ) / 2 + 1 ; search = stPos + ( st + ed ) / 2 * recLn ; } else { st = (st+ed)/2 + (st+ed)%2 + 1 ; search = stPos + ( (st+ed)/2 + (st+ed)%2 ) * recLn ; } p = 0 ; continue ; } else /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ バイナリサーチロジック3 3. 共有メモリデータ = 業務APのパラメータ 3.1 全Index項目の比較が完了したら 3.1.1 検索行の絞り込みが未完で、マッチング最上位行が未決定の場合 最上位行を再検索 3.1.2 検索行の絞り込みが完了で、マッチング最上位行が未決定の場合 マッチング最上位行を決定して、最下位行の検索を実施 3.1.3 検索行の絞り込みが未完で、マッチング最上位行が決定済の場合 最下位行を再検索 3.1.4 検索行の絞り込みが完了で、マッチング最上位行が決定済の場合 マッチング最下位行を決定して、break 3.2 全Index項目の比較が完了いなければ、次項目の比較を実施 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( hkk == 0 ) { if ( Index_Pos[p+1] == -1 ) { if ( st != ed && stMatch == -1 ) { ed = ( st + ed ) / 2 ; search = stPos + ( st + ed ) / 2 * recLn ; } else if ( st == ed && stMatch == -1 ) { stMatch = st ; ed = rowNm - 1 ; search = stPos + ( (st+ed)/2 + (st+ed)%2 ) * recLn ; } else if ( st != ed && stMatch != -1 ) { st = ( st + ed ) / 2 + ( st + ed ) % 2 ; search = stPos + ( (st+ed)/2 + (st+ed)%2 ) * recLn ; } else if ( st == ed && stMatch != -1 ) { edMatch = st ; break ; } p = 0 ; } else { p ++ ; } } } getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** 開始行=%d 終了行=%d 検索対象行数=%d" , ThreadId , szAccessDate ,stMatch,edMatch,edMatch-stMatch+1 ) ; // インデックス検索でマッチングデータが発生した場合 if ( hkk == 0 ) { // 検索開始行から終了行をFull-Scan検索 for ( int p = stMatch ; p <= edMatch ; p++ ) { // インデックス検索行を決定 search = stPos + p * recLn ; // 共有メモリ上の検索位置を決定。インデックス各行の右12桁に共有メモリ相対位置が設定されている char cTblRecPos[13] ; strncpy ( cTblRecPos , c_SHMBase + search + recLn - strlen(PARM_FULLSCAN) , strlen(PARM_FULLSCAN) ) ; long lTblRecPos = atol ( cTblRecPos ) ; char *w_SHMemory = c_SHMemory + lTblRecPos ; int match = 0 ; // 0 : データmatch 、 1 : データunmatch // このfor内に入ったら、Index以外の比較項目があったということ for ( int j = 0 ; Left[j][0] != '\0' ; j ++ ) { char *Left_Num_Pos = strchr ( Left[j] , '@' ) ; if ( strcmp ( Hikaku[j] , "=" ) == 0 && Left_Num_Pos == NULL ) continue ; match = 1 ; // Index以外の比較項目があれば、初期状態は「データunmatch」 // パディング値(0x1f)の削除 int comLeftLen ; for ( comLeftLen=Leftlen[j]-1 ; comLeftLen>=0 ; comLeftLen-- ) { if ( (unsigned char)(w_SHMemory+Leftpos[j]+comLeftLen)[0] != (unsigned char)SP_REP ) { break ; } } comLeftLen++ ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 文字比較の場合 / Left_Nid[j] == 0 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( Left_Nid[j] == 0 ) { // 業務APのパラメータ文字数が共有メモリデータの文字数より大きい場合 if ( strlen(Right[j]) > comLeftLen ) { // 業務APのパラメータ文字をスペースパディング int RightLen = strlen(Right[j])-1 ; for ( ; RightLen >= comLeftLen ; RightLen-- ) { if ( Right[j][RightLen] != ' ' ) break ; } RightLen++ ; Right[j][RightLen] = '\0' ; // 共有メモリデータをローカル領域に設定 char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , w_SHMemory + Leftpos[j] , comLeftLen ) ; shmChar [ comLeftLen ] = '\0' ; // 業務APパラメータと共有メモリデータの比較 hkk = (long)strcmp ( shmChar , Right[j] ) ; free ( shmChar ) ; } else // 業務APのパラメータ文字数が共有メモリデータの文字数より小さい場合 if ( strlen(Right[j]) < comLeftLen ) { // 共有メモリデータをローカル領域に設定 char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , w_SHMemory + Leftpos[j] , comLeftLen ) ; shmChar [ comLeftLen ] = '\0' ; // 共有メモリデータの文字をスペースパディング comLeftLen-- ; for ( ; comLeftLen >= strlen(Right[j]) ; comLeftLen-- ) { if ( shmChar[comLeftLen] != ' ' ) break ; } comLeftLen++ ; shmChar[comLeftLen] = '\0' ; // 業務APパラメータと共有メモリデータの比較 hkk = (long)strcmp ( shmChar , Right[j] ) ; free ( shmChar ) ; // 業務APのパラメータ文字数が共有メモリデータの文字数が同じ場合 } else { // 業務APパラメータと共有メモリデータの比較 hkk = (long)memcmp ( w_SHMemory + Leftpos[j] , Right[j] , comLeftLen ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 数値比較の場合 / Left_Nid[j] == 1 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ } else { // 共有メモリデータをローカル領域に設定 char *shmChar = (char *) malloc ( comLeftLen + 1 ) ; strncpy ( shmChar , w_SHMemory + Leftpos[j] , comLeftLen ) ; shmChar [ comLeftLen ] = '\0' ; // 共有メモリデータ値を「long double型」に変換 // 変換仕様は、標準関数strtoldに従う long double Left_Num ; int rc = to_long_double ( shmChar , &Left_Num ) ; // 比較結果をhkk(long型)に設定 if ( Left_Num == Right_Num[j] ) { hkk = 0 ; } else if ( Left_Num > Right_Num[j] ) { hkk = 1 ; } else if ( Left_Num < Right_Num[j] ) { hkk = -1 ; } free ( shmChar ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ アクセスパターンの検索方法と比較結果が一致した場合 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ if ( ( strcmp ( Hikaku[j] , "=" ) == 0 && hkk == 0 ) || ( strcmp ( Hikaku[j] , "<" ) == 0 && hkk < 0 ) || ( strcmp ( Hikaku[j] , "<=" ) == 0 && hkk <= 0 ) || ( strcmp ( Hikaku[j] , ">" ) == 0 && hkk > 0 ) || ( strcmp ( Hikaku[j] , ">=" ) == 0 && hkk >= 0 ) || ( strcmp ( Hikaku[j] , "!=" ) == 0 && hkk != 0 ) ){ // 検索が完了した場合(検索対象データとして確定)(「or」のケースはない) if ( strcmp ( Ketugo[0] , "or" ) == 0 || Ketugo[j][0] == '\0' ) { match = 0 ; break ; } else // 比較が未完了の場合(Ketugo[j][0] != '\0')は、データ比較を処理継続 if ( strcmp ( Ketugo[0] , "and" ) == 0 ) { match = 0 ; continue ; // 論理エラーここに入る場合はデータ破壊の可能性あり } else { // printf ( "比較演算子不正!! [%s]\n" , Ketugo[j] ) ; getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** 比較演算子不正!! Ketugo[%s]" , ThreadId , szAccessDate ,Ketugo[j] ) ; return ( -5 ) ; } // 比較方法と比較結果が不一致の場合 } else { // 比較方法の結合子が「or」で、検索が完了していない場合は、次のデータ比較を継続 if ( strcmp ( Ketugo[0] , "or" ) == 0 && Ketugo[j][0] != '\0' ) continue ; // 上記以外は、当該データは検索対象外に決定 match = 1 ; break ; } } if ( match == 0 ) { int ColSzWrok = 0 ; // 共有メモリデータを返却領域にコピー for ( int h = 0 ; h < t_TblInfo.TblColNum ; h ++ ) { memcpy ( TableData , w_SHMemory + ColSzWrok , t_ColumnDef[h].ColumnSize ) ; TableData [ t_ColumnDef[h].ColumnSize ] = '\t' ; TableData = TableData + t_ColumnDef[h].ColumnSize + 1 ; ColSzWrok = ColSzWrok + t_ColumnDef[h].ColumnSize ; } TableData -- ; TableData [0] = '\n' ; TableData [1] = '\0' ; TableData = TableData + 1 ; k ++ ; /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 返却データのサイズが、TableDataBase で確保した返却領域の1/2を越えた場合、 返却データのサイズを2倍に拡張(malloc→memcpy→freeにより実施) _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ // 返却データのサイズを2倍に拡張 if ( TblBufSize / 2 < (size_t)TableData - (size_t)TableDataBase ) { TblBufSize = TblBufSize * 2 ; char *TableDataTmp = (char *) malloc ( TblBufSize ) ; if ( TableDataTmp != NULL ) { memcpy ( TableDataTmp , TableDataBase , (size_t)TableData - (size_t)TableDataBase ) ; TableData = TableDataTmp + ( (size_t)TableData-(size_t)TableDataBase ) ; free ( TableDataBase ) ; TableDataBase = TableDataTmp ; startLock(0) ; // 排他制御(mutex:0) for ( int m = 0 ; m < ThrdNum ; m++ ) { if ( s_Thrd[m].tid == syscall(SYS_gettid) ) { s_Thrd[m].arrOut = TableDataBase ; break ; } } endLock(0) ; // 排他制御(mutex:0) } else { getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 0 , "(%05d) **** ( %s ) **** realloc エラー発生!! DATA[%-100s]" , ThreadId , szAccessDate ,TableDataBase ) ; return ( -6 ) ; } } } } } getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; GG_MsgOut ( g_szLogFilePath , 9 , "(%05d) **** ( %s ) **** Index 検索終了" , ThreadId , szAccessDate ) ; } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ShmStaticTable クラスに return データ返却領域にデータが1件以上設定された場合は、ShmStaticTable クラスに返却 データ長を返却。 注)ShmStaticTable クラスは、本return値分のbyte配列を用意して、データ取得用の 関数(GG_SHM0011getdata)を呼び出す。 データ返却領域にデータが設定されない場合は、0 を設定してreturn _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ getLocalTimeString ( szAccessDate , sizeof(szAccessDate) , "%Y/%m/%d %H:%M:%S.%U" ) ; if ( k > 0 ) { // ログ出力:0x1fコードを削除してログ出力(ログが見えなくなるため) if ( LogLevel > 0 ) { char *logBuff = (char *) malloc ( strlen(TableDataBase) + 1 ) ; char *p ; strcpy ( logBuff , TableDataBase ) ; while ( ( p = strchr (logBuff , SP_REP) ) != NULL ) { *p = ' ' ; } GG_MsgOut ( g_szLogFilePath , 1 , "(%05d) **** ( %s ) **** [%04d] 件\n%s" , ThreadId , szAccessDate , k , logBuff ) ; free ( (char *) logBuff ) ; } // 検索データの返却 return ( strlen(TableDataBase) ) ; } else { char logOutPrm [ 1024 ] ; logOutPrm [ 0 ] = '\0' ; for ( int i=1 ; i<=prmNum ; i++ ) { strcat ( logOutPrm , "[" ) ; strcat ( logOutPrm , Prm [ i ] ) ; strcat ( logOutPrm , "] " ) ; } // ログ出力:該当データはありません GG_MsgOut ( g_szLogFilePath , 1 , "(%05d) **** ( %s ) **** 該当データはありません !!" , ThreadId , szAccessDate ) ; GG_MsgOut ( g_szLogFilePath , 1 , "(%05d) **** ( %s ) **** inData=%s" , ThreadId , szAccessDate , logOutPrm ) ; // 検索データはなし return ( 0 ) ; } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 文字データ→long double型に変換 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int to_long_double ( char *in_str , long double *out_ld ) { char *err ; *out_ld = strtold ( in_str , &err ) ; if ( *err == '\0' ) { return (0) ; } else { return (-1); } } /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ 文字データが数値で構成されているかチェック _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int isNumber( char *str ) { int ret = 1; char ch ; int len = strlen( str ); for ( int i = 0 ; i < len ; i ++ ) { ch = str [ i ]; if ( i == 0 && len > 1 && (ch == '+' || ch == '-') ) { // 先頭の1文字目が符号でかつ符号のみの文字列でない場合 continue; } if ( isdigit( (unsigned char)ch ) == 0 ) { ret = 0; break; } } return ( ret ) ; } #ifdef _NONSTOP /* _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ NonStop用syscall _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ */ int syscall(int id) { pthread_t tid; tid = pthread_self(); // tidの内容 // tid.field1=134263616 // tid.field2=4 ← スレッドからアクセスされた場合、field2が増加する。 // tid.field3=4 return (tid).field2; } #endif