ポストグレスヲサイキドウセヨ
PHPカンファレンス2007前日辺りから酷い目にあっています。。。現在も進行中。うへぇ。_| ̄|○
この年齢になってくると徹夜の作業は流石に厳しい。。。歳は取りたくないものだ。
色んな方の参加レポートを拝見させて貰っていますが、楽しい雰囲気が充分伝わってきました。cocoitibanさんもモテになれて何よりです。(w
参加する事は出来なかったけど、色んな方の参加レポートを見ているうちにハッピーな気分になれました。
参加できた人、羨ましいなぁ。資料がダウンロードできる事を期待しています。
話を元に戻して(とりあえず)バージョンUPしてね、と連絡を頂いているのですが、それ以前にバージョンUPすれば解決する問題なのかを正しく検証しないと駄目だと思うんだよね。その為には再現させる事が必要、と。
結構きわどいタイミングでないと再現しないとの事だったので、すぐにピンときた(競合状態の問題)!
なので、マルチスレッド・プログラムをCで実装してみました。pthread初デビュー。pthread_exit関数の使い方が微妙に間違っている感じもするけど、正しく動かす事が目的じゃないので、その辺は大目に見てね、という事で。
思いがけず前に読んだ本が役に立った感じ?いやいや。
(想像していた通り)簡単に実装できた。。。って、実際に簡単な実装しかしてないからね。軽く見るのは良くないか。
以下のログが無事に出力されるようになったんだけど、肝心のPostgreSQLが強制的に再起動してしまうまでには至らない。。。他の要因が必要なのかしら。
[サーバ側ログ] WARNING: AbortTransaction and not in in-progress state ERROR: invalid message format [クライアント側エラーメッセージの戻り値] Message contents do not agree with length in message type "T" server sent data ("D" message) without prior row description ("T" message) WARNING: AbortTransaction and not in in-progress state ERROR: invalid message format WARNING: AbortTransaction and not in in-progress state message type 0x5a arrived from server while idle server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request.
これが解決できない限り、まともな状態にならないんだよなぁ。なんというか。。。しぶとい(良い意味でも悪い意味でも)。そろそろ勘弁して欲しい。
以下が調査に使っているプログラムです。意図的に競合状態を作り出す為、コネクション変数をグローバル領域に定義しています。
それにしても、マルチスレッド・プログラムで競合状態を作り出すのはスゲー簡単だね。壊すのはスゲー簡単(ある意味、凶器)。
怖い。。。というよりは、危ないモノを見て(何故か)ドキドキ胸が高揚する感じを覚えました。変態?
//------------------------------------------------------------------// // header include //------------------------------------------------------------------// #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include "libpq-fe.h" //------------------------------------------------------------------// // define of proto-type //------------------------------------------------------------------// void *go2hell( void *arg ); //------------------------------------------------------------------// // global value //------------------------------------------------------------------// PGconn *conn; //------------------------------------------------------------------// // main //------------------------------------------------------------------// int main( void ) { //-----------------------------------------------------------------// // local value //-----------------------------------------------------------------// int XX, threads_number = 10; pthread_t threads[threads_number]; //-----------------------------------------------------------------// // get connection //-----------------------------------------------------------------// conn = PQconnectdb( "host=localhost dbname=test" ); if( PQstatus( conn ) != CONNECTION_OK ) { fprintf( stderr, "connection error!!\n" ); fprintf( stderr, "%s\n", PQerrorMessage( conn ) ); exit( 1 ); } for( XX = 0; XX < threads_number; ++XX ) { if( pthread_create( &(threads[XX]), NULL, go2hell, NULL ) !=0 ) { fprintf( stderr, "create thread error!!\n" ); exit( 1 ); } } sleep( 3 ); return 0; } //------------------------------------------------------------------// // sub //------------------------------------------------------------------// void *go2hell( void *arg ) { //-----------------------------------------------------------------// // local value //-----------------------------------------------------------------// int nTuples, nFields, XX, YY; PGresult *res; //-----------------------------------------------------------------// // thread detach //-----------------------------------------------------------------// if( pthread_detach( pthread_self( ) ) != 0 ) { fprintf( stderr, "failed to detatch\n" ); pthread_exit( (void *)1 ); } //-----------------------------------------------------------------// // get connection //-----------------------------------------------------------------// if( conn == NULL ) { conn = PQconnectdb( "host=localhost dbname=test" ); if( PQstatus( conn ) != CONNECTION_OK ) { fprintf( stderr, "connection error!!\n" ); fprintf( stderr, "%s\n", PQerrorMessage( conn ) ); pthread_exit( (void *)2 ); } } //-----------------------------------------------------------------// // execute query //-----------------------------------------------------------------// res = PQexec( conn, "select version( )" ); if( PQresultStatus( res ) != PGRES_TUPLES_OK ) { fprintf( stderr, "SQL execute error!!\n" ); fprintf( stderr, "%s\n", PQerrorMessage( conn ) ); PQclear( res ); PQfinish( conn ); pthread_exit( (void *)3 ); } //-----------------------------------------------------------------// // get result //-----------------------------------------------------------------// nTuples = PQntuples( res ); nFields = PQnfields( res ); for( XX = 0; XX < nTuples; ++XX ) { for( YY = 0; YY < nFields; ++YY ) { fprintf( stderr, "##-----------------------------------------------##\n" ); /********************************************************************* fprintf( stderr, "fields name : [%s]\n", PQfname( res, YY ) ); fprintf( stderr, "fields size : [%d]\n", PQgetlength( res, XX, YY ) ); fprintf( stderr, "fields number : [%d]\n", PQfnumber( res, PQfname( res, YY ) ) ); fprintf( stderr, "fields is null : [%d]\n", PQgetisnull( res, XX, YY ) ); *********************************************************************/ fprintf( stderr, "fields value : [%s]\n", PQgetvalue( res, XX, YY ) ); fprintf( stderr, "##-----------------------------------------------##\n" ); } } //-----------------------------------------------------------------// // free result pointer //-----------------------------------------------------------------// PQclear( res ); //-----------------------------------------------------------------// // close connection //-----------------------------------------------------------------// PQfinish( conn ); conn = NULL; //-----------------------------------------------------------------// // thread exit //-----------------------------------------------------------------// pthread_exit( (void *)0 ); }
先は(まだまだ)長い。。。か?