• このエントリーをはてなブックマークに追加

ss-1307455447

はじめに

groonga のMySQLストレージエンジンである mroonga を,Mac OSX でビルドできるようになるための(アドホックな!)パッチを書いてみたので,以下,そこに至るまでのプロセスでも書いてみます.

なお,私のビルド環境は次のとおりです:

OS
Mac OSX 10.6.7
CPU
Intel Core i7 2.66GHz
MySQL
5.1.56(Homebrewにてインストール)
MeCab
0.98 (Homebrewにてインストール)
groonga
1.2.2(Homebrewにてインストール,ひとつ前のエントリでも言及)
mroonga
0.6

とりあえずパッチから

ha_mroonga.cc に,次の変更を加えればOKです:

--- groonga-storage-engine-0.6/ha_mroonga.cc	2011-05-29 20:11:11.000000000 +0900
+++ groonga-storage-engine-0.6-fix/ha_mroonga.cc	2011-06-09 03:20:08.000000000 +0900
@@ -93,7 +93,7 @@
   if (mrn_logfile_opened) {
     pthread_mutex_lock(&mrn_log_mutex);
     fprintf(mrn_logfile, "%s|%c|%08x|%s\n", time,
-            *(slev + level), (uint)pthread_self(), msg);
+            *(slev + level), (uint)(long int)pthread_self(), msg);
     fflush(mrn_logfile);
     pthread_mutex_unlock(&mrn_log_mutex);
   }


2011-06-10 05:30 追記

ktouさんよりご返信いただいたのでこちらで.

@issm おぉ!なるほど!long intではなくunsigned long intにして取り込みました!(どうせ最後にはunsignedになるので。)ありがとうございます!(キャストを抜くやり方だとwarningがのこるんですね。。。)

Twitter / @ktou: @issm おぉ!なるほど!long intではなく …

確かにそのとおりですね.ということで,上記gistのリンク先の内容を,unsigned intunsigned long int に修正しておきました.

ビルドエラー

ソースコードからビルドするための,いつもの手順を踏みます.

% ./configure --prefix=$HOME/local --with-mysql-source=$HOME/src/else/mysql-5.1.56 --with-mysql-config=/usr/local/bin/mysql_config --with-mecab=/usr/local/Cellar/mecab/0.98
 
...
 
% make
 
...
 
g++ -DHAVE_CONFIG_H -I.  -I/Users/issm/src/else/mysql-5.1.56/sql -I/Users/issm/src/else/mysql-5.1.56/include -I/Users/issm/src/else/mysql-5.1.56/regex -I/Users/issm/src/else/mysql-5.1.56 -I/usr/local/Cellar/mysql/5.1.56/include/mysql -I/usr/local/Cellar/groonga/1.2.2/include/groonga   -I/usr/local/Cellar/mecab/0.98/include -DMYSQL51   -I/usr/local/Cellar/mysql/5.1.56/include/mysql  -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT  -DDONT_DECLARE_CXA_PURE_VIRTUAL -g -O2 -Werror -fno-implicit-templates -fno-exceptions -fno-rtti -felide-constructors -MT libgroonga_storage_engine_a-ha_mroonga.o -MD -MP -MF .deps/libgroonga_storage_engine_a-ha_mroonga.Tpo -c -o libgroonga_storage_engine_a-ha_mroonga.o `test -f 'ha_mroonga.cc' || echo './'`ha_mroonga.cc
ha_mroonga.cc: In function ‘void mrn_logger_func(int, const char*, const char*, const char*, const char*, void*)’:
ha_mroonga.cc:96: error: cast from ‘_opaque_pthread_t*’ to ‘uint’ loses precision
make[2]: *** [libgroonga_storage_engine_a-ha_mroonga.o] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2
%

失敗しました.

メッセージのとおり,ha_mroonga.cc の96行目を見てみます.

89
90
91
92
93
94
95
96
97
98
99
100
void mrn_logger_func(int level, const char *time, const char *title,
                     const char *msg, const char *location, void *func_arg)
{
  const char slev[] = " EACewnid-";
  if (mrn_logfile_opened) {
    pthread_mutex_lock(&mrn_log_mutex);
    fprintf(mrn_logfile, "%s|%c|%08x|%s\n", time,
            *(slev + level), (uint)pthread_self(), msg);  // ← ここでエラー!
    fflush(mrn_logfile);
    pthread_mutex_unlock(&mrn_log_mutex);
  }
}

どうやら,pthread_self() 関数が返す型がマズイみたいです.ので,同関数の定義部分を確認してみます.これは /usr/include/pthread.h で見つかります.

343
pthread_t pthread_self(void);

pthread_t という型でした.

そもそも pthread_t 型って?


Cプログラミングに長けている方にとっては,すぐにイメージがわきそうなこの型,素人の私にとってはサッパリです.ので,ファイルを遡ってさらに定義を探してみます.

CentOS

まず,エラーもなくビルドできた CentOS で,確認してみます.

/usr/include/bits/pthreadtypes.h に書いてありました.

34
35
36
/* Thread identifiers.  The structure of the attribute type is not
   exposed on purpose.  */
typedef unsigned long int pthread_t;

Mac OSX

では,エラーのあった Mac OSX では?

/usr/include/pthread.h で見つかりました.

109
typedef __darwin_pthread_t		pthread_t;

__darwin_pthread_t?これもわからないため,さらに探します.この定義を/usr/include/sys/_types.hにて発見.

129
130
typedef struct _opaque_pthread_t
			*__darwin_pthread_t;	/* [???] Used for pthreads */

えーと,_opaque_pthread_t 構造体へのポインタ,ということでしょうかね...(_opaque_pthread_tオブジェクト,みたいな?)

とにかく,unsigned long int 型とは異なっているだろうことはわかりました.

uint型について

uint は,unsigned int のエイリアスとでも考えればよさそうです./usr/include/sys/types.h にその定義を確認できました:

83
84
85
86
87
88
89
90
91
92
93
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
typedef	unsigned char		u_char;
typedef	unsigned short		u_short;
typedef	unsigned int		u_int;
#ifndef _U_LONG
typedef	unsigned long		u_long;
#define _U_LONG
#endif
typedef	unsigned short		ushort;		/* Sys V compatibility */
typedef	unsigned int		uint;		/* Sys V compatibility */
#endif

考え,というか勘

_opaque_pthread_t 型を,直接uint型にキャストすることに失敗しているので,「uint 型にキャストできる型」にキャストしてみてはどうか,という考えが出てきました.

キャストの内容をいくつか試してみた結果,コンパイルエラーの出なかったのが,一度 long int 型にキャストする方法でした:

(uint)(long int)pthread_self()

※ 二段階のキャストってアリなのかどうかはよくわかっていません!

検証(?)コード

ただ,これだけでは,スレッドID(のような値)が取得できているかどうかがわからないため,簡単な検証コードを書いてみました.

スレッドを10個生成し,それぞれのスレッドID(のような値)を出力する,というものです.

#include <stdio.h>
#include <iostream>
#include <pthread.h>
#include <sys/types.h>
 
 
void print_thread_id () {
  int pid = getpid();
  printf( "%6d: %08x\n", pid, (uint)(long int)pthread_self() );
}
 
 
void * thread_function (void *arg) {
  print_thread_id();
  pthread_exit(NULL);
}
 
 
main() {
  print_thread_id();
 
  int i;
  int count = 10;
  for ( i = 0; i < count; i++ ) {
    pthread_t th;
    pthread_create( &th, NULL, &thread_function, NULL );
  }
 
  sleep(5);
  return 0;
}

これを a.cc とかで保存してコンパイルします:

% g++ -lpthread a.cc

これを,Mac OSX,CentOSで,それぞれ実行してみます.

Mac OSX

% ./a.out
 27291: 70cd1ca0
 27291: 000b6000
 27291: 00281000
 27291: 00304000
 27291: 00387000
 27291: 0040a000
 27291: 0048d000
 27291: 00510000
 27291: 00593000
 27291: 00616000
 27291: 00699000
%

スレッドごとに異なる値が取得できているみたいです.

CentOS

% ./a.out
 18281: b7ef26d0
 18281: b7ef1b90
 18281: b4cecb90
 18281: b74f0b90
 18281: b6aefb90
 18281: b42ebb90
 18281: b38eab90
 18281: b2ee9b90
 18281: b24e8b90
 18281: b56edb90
 18281: b60eeb90
%

同じコードで,CentOSでも動作しています.

ちなみに,検証コードの print_thread_id() 関数中のキャスト部分を,

printf( "%6d: %08x\n", pid, (uint)pthread_self() );

と,uint型に直接キャストする場合でも,同様の結果が得られました.(取得するスレッドID値は異なっていますが.)

参考

検証コードを書くにあたり,次を参考にさせていただきました.

おわりに

ということで,mroonga を Mac OSX でもビルドできるよう,アドホックな修正を行ってみたお話でした.

なお,MySQLへの組み込み後の動作については,何も確認を行っていないのであしからず,です.(影響があるとしても,ログ出力部分だけ?)