read.cgi再開発スレ Part2
■ このスレッドは過去ログ倉庫に格納されています
◆cZfSunOs.Uさん作成のmod_cgidsoにより、大きな負荷軽減が図られたread.cgi。 このスレでは、そんなread.cgiの(再)開発・実装すべき機能について取り扱います。 前スレより: 574 名前:FOX ★[sage] 投稿日:05/01/05 15:54:28 ID:??? 全てのサーバ cobra/toger/banana で read.cgi の dso化が完了。 これから href の置き換え ime.nu 対応を行い それが終了したら第一ステップは完。 第2ステップは 2-1) bug つぶし 2-2) 仕様の変なところは変更 2-3) 時代背景にあわせたデコレーション こんなとこかと、 前スレ: read.cgi再開発スレ http://qb5.2ch.net/test/read.cgi/operate/1087199303/ >395 空欄のコメントにも、意味がある場合もある。 一番典型的なのは、メール欄で会話するスレかな。 もちろん、ただのスレ潰しの場合もあるが。 >>396 ,397 FireFoxだと、E-mail欄の「sage」が記憶されているので コメントが空欄でも、 間違って「書き込む」を押すと書き込まれてしまいます。 e-mail欄が入ってても、本文が空白なら書き込まれないよ。 400ゲトついでに改善要望(定期) ■定期>>373 スレスト処理済のスレの書き込み欄が表示されてる→表示させないように (以前は書き込み欄自体が消えていた) ■定期>>372 容量で埋まったスレのエラーメッセージがない http://qb5.2ch.net/test/read.cgi/operate/1128074121/ >>399 ほんとだ。じゃ、名前欄に名前が残ってたばあいは? >>396 ,399 どうやら本文が空欄だと書き込めないようですね。 スレ汚し失礼しました。 あえて言うなら、コメントを途中まで書いて、 やっぱりやめようと「掲示板に戻る」を押そうとして 間違えて「書き込む」を押しちゃった場合は書き込まれてしまいますね。 レアケースですけど。 ここの管轄か知らんけど ■http://qb5.2ch.net/operate/kako/ 過去ログ倉庫クリックした時にsubbackのほうの窓じゃなくてスレの窓のほうを書き換えるの やめて >405をクリックした時は新しく窓が開くからややこしい ここの管轄か知らんけど ■http://news18.2ch.net/mnewsplus/1000.txt 実際にはいるのは普通1001(かそれ以降)じゃないの ■ime.nu判定 2chのスレにbbspinkのスレを貼った時、以前はJumpページ (ime.nu経由?)になったと思うんだけど、今は直で飛べるみたい。 http://qb5.2ch.net/test/read.cgi/saku2ch/1131265364/793 BBSPINKは21禁の別サイトのはずなので、 間にJumpが挟まってた方がいいのでは。 それだったらむしろime.st行く前に 「ジャンプ先にアダルト広告(画像つき)があります ジャンプしますか?(y/n)」 が必要なんでは >>410 なおたとおもう。 (memoriesに収容したので、read.cgiバイナリをi386→amd64に変更(配布しなおし)) >>287 をやろうと思って、read.cgi のソースを眺め始めたりして。 今のread.cgiを見てみると、 if(!lookfor(ch2,r)) return 3001 ; ってやって、まずdatがあるかどうか調べて、lookforの中で、 if(!apr_stat(&CountStat,ch2->zz_fName,APR_FINFO_MIN,r->pool)) /* found */ { ch2->zz_filesize = CountStat.size ; ch2->zz_mtime = CountStat.mtime ; ch2->where = W_LIVE ; return 1 ; } ってやって、datのサイズとmtimeを読んで、その次に、 if(apr_file_open(&in,ch2->zz_fName,APR_READ,APR_OS_DEFAULT,r->pool)) {return 3011;} apr_file_read(in, ch2->BigBuffer, &ch2->zz_filesize); apr_file_close(in) ; とやって、datをバッファに読み込んでいると。 ここに >>287 相当品を組み込めばよさげなわけですが、さて、どうすればいいのかと。 たぶん、HEADしてGETするとか、そういう感じなのかしら。 >>411 てか板トップから表示されてるスレの外部リンクは全部ime.st抜けてるよ まず,Apache 2.0 → 2.2 移行に関して......おおかたの API は ソースレベルの互換性は維持されているので,mod_cgidso やそれ用の プログラム (read.cgi 等) はソースの手直しは不要だと思います. ただ,バイナリレベルの互換性はないのでリコンパイルは必要です. しかし,>>287 のは正攻法ではなくトリッキーな方法を用いているため, 2.2 対応には若干の手直しが必要となります(下記のソースでは その点も含め対応し,2.0 / 2.2 両対応となっています). まぁこれは,正攻法でやろうとすると別途フィルタモジュールを 作らなければならなくなるので...... >>415 乙です. >たぶん、HEADしてGETするとか、そういう感じなのかしら。 そのように2回サブリクエストを実行する形だと非効率になりそうなので, 雪だるま版では lookfor() で内容取得まで一緒にやってしまった方が良さそうな気もします. その代わり,dat ファイルを読み込んでる部分をスキップすると. ----[この関数を定義しておく]------------------------------------------ #ifdef SNOWMAN static apr_status_t rdat_filter(ap_filter_t *f, apr_bucket_brigade *b) { return ap_save_brigade(f, (apr_bucket_brigade **)&f->ctx, &b, f->r->pool); } #endif ----[lookfor() の中]-------------------------------------------------- #ifdef SNOWMAN int rv; #if defined(AP_SERVER_MINORVERSION_NUMBER) && AP_SERVER_MINORVERSION_NUMBER >= 2 ap_filter_rec_t frec = {"READDAT", {rdat_filter}, NULL, AP_FTYPE_RESOURCE, NULL, NULL, 0, 0}; #else ap_filter_rec_t frec = {"READDAT", {rdat_filter}, NULL, AP_FTYPE_RESOURCE, NULL}; #endif ap_filter_t f = {&frec, NULL, NULL, r, r->connection}; char *uri = apr_pstrcat(r->pool, "/", ch2->zz_bbs, "/dat/", ch2->zz_key, ".dat", NULL); request_rec *rdat = ap_sub_req_lookup_uri(uri, r, &f); if (!(rv = rdat->status == HTTP_OK ? ap_run_sub_req(rdat) : rdat->status)) { apr_brigade_pflatten(f.ctx, &ch2->BigBuffer, &ch2->zz_filesize, r->pool); apr_brigade_destroy(f.ctx); ch2->zz_mtime = rdat->mtime ? rdat->mtime : apr_date_parse_http(apr_table_get(rdat->headers_out, "Last-Modified")); } ap_destroy_sub_req(rdat); if (!rv) { ch2->where = W_LIVE; return 1; } #else if(!apr_stat(&CountStat,ch2->zz_fName,APR_FINFO_MIN,r->pool)) /* found */ { ch2->zz_filesize = CountStat.size ; ch2->zz_mtime = CountStat.mtime ; ch2->where = W_LIVE ; return 1 ; } #endif ----[BigBuffer アロケート / dat 読み込みの部分はスキップ]------------- #ifndef SNOWMAN ch2->BigBuffer = apr_palloc(r->pool, ch2->zz_filesize); /* ←多分こんな形で BigBuffer 領域を確保してますよね? */ if (apr_file_open(&in,ch2->zz_fName,APR_READ,APR_OS_DEFAULT,r->pool)) {return 3011;} apr_file_read(in, ch2->BigBuffer, &ch2->zz_filesize); apr_file_close(in) ; #endif ---------------------------------------------------------------------- >>416 ほんとに? >>417 了解です。 あとで、>>418 に挑戦してみるです。 やってみました。 しかし、 Request exceeded the limit of 10 subrequest nesting levels due to probable confguration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace. ううむ。 で、>>421 は出なくなって、今は、 [notice] child pid 67012 exit signal Segmentation fault (11) うむむ。 >>421 >Request exceeded the limit of 10 subrequest nesting levels >due to probable confguration error. う〜む......サブリクエストが無限ループになってるんですかね...... proxy 関連の設定はどうなってますか? あと気になる点は...... ・ ch2->zz_filesize の型 (apr_size_t? apr_off_t?) ・ ch2->BigBuffer[ch2->zz_filesize] に '\0' を置く必要あり? >>424 > apr_size_t zz_filesize ; のようです。 で、apr_file_close(in) の後は、 p = ch2->BigBuffer ; for(i=0;i<ch2->zz_filesize;i++,p++) { if(*p == '\0') *p = '*' ; } *p = '\0' ; p = ch2->BigBuffer ; ch2->lineNum = 0 ; と、やっている模様。 >>423 > proxy 関連の設定はどうなってますか? # livejupiter ProxyPass /livejupiter/SETTING.TXT ! ProxyPass /livejupiter/ http://live22x.2ch.net/livejupiter/ ProxyPassReverse /livejupiter/ http://live22x.2ch.net/livejupiter/ です。 >>425 了解です.zz_filesize の型は良かったのですが, >*p = '\0' ; があるので apr_brigade_pflatten() のところはこうした方がよさそうです. - apr_brigade_pflatten(f.ctx, &ch2->BigBuffer, &ch2->zz_filesize, r->pool); + apr_off_t blen; + apr_brigade_length(f.ctx, 1, &blen); + ch2->zz_filesize = blen; + ch2->BigBuffer = apr_palloc(r->pool, ch2->zz_filesize + 1); + apr_brigade_flatten(f.ctx, ch2->BigBuffer, &ch2->zz_filesize); >>426 了解です.特に問題はなさそうですね.何が起こってるのかトレースできればいいんですが...... ううむ、>>422 のようです。>>427 で、ch2->BigBuffer は、dso_main で最初に、 CH2READ ch2 ; と言っていて、CH2READ は、構造体になっているです。 で、その中でこんなかんじでとっているです。 つまり、apr_pallocで取っているわけではないみたい。 char BigBuffer[SZ_BIGBUF] ; で、入れてみましたが、 ・バーチャルホスト毎の access.log error.log は出ない ・一番親のログは >>422 のようです。 >>428 なるほど.とするとこんな感じですか...... apr_off_t blen; apr_brigade_length(f.ctx, 1, &blen); if ((ch2->zz_filesize = blen) >= SZ_BIGBUF) return 何かのエラー番号; apr_brigade_flatten(f.ctx, ch2->BigBuffer, &ch2->zz_filesize); # デカい構造体をスタックに確保するってのはちょっと不安があるわけですが, # 今までそれで動いてたのなら今回の問題とは無関係だろうということで...... で......死んだ時の core のバックトレースを取るとか,truss でトレースするとか できますでしょうか......? 現在のもの: +#ifdef SNOWMAN +static apr_status_t rdat_filter(ap_filter_t *f, apr_bucket_brigade *b) +{ + return ap_save_brigade(f, (apr_bucket_brigade **)&f->ctx, &b, f->r->pool); +} +#endif +#ifdef SNOWMAN + int rv; +#if defined(AP_SERVER_MINORVERSION_NUMBER) && AP_SERVER_MINORVERSION_NUMBER >= 2 + ap_filter_rec_t frec = {"READDAT", {rdat_filter}, NULL, AP_FTYPE_RESOURCE, NULL, NULL, 0, 0}; +#else + ap_filter_rec_t frec = {"READDAT", {rdat_filter}, NULL, AP_FTYPE_RESOURCE, NULL}; +#endif + ap_filter_t f = {&frec, NULL, NULL, r, r->connection}; + char *uri = apr_pstrcat(r->pool, "/", ch2->zz_ita, "/dat/", ch2->zz_key, ".dat", NULL); + request_rec *rdat = ap_sub_req_lookup_uri(uri, r, &f); + + if (!(rv = rdat->status == HTTP_OK ? ap_run_sub_req(rdat) : rdat->status)) { + apr_off_t blen; + apr_brigade_length(f.ctx, 1, &blen); + ch2->zz_filesize = blen; + apr_brigade_flatten(f.ctx, ch2->BigBuffer, &ch2->zz_filesize); + apr_brigade_destroy(f.ctx); + ch2->zz_mtime = rdat->mtime ? rdat->mtime + : apr_date_parse_http(apr_table_get(rdat->headers_out, "Last-Modified")); + } + ap_destroy_sub_req(rdat); + + if (!rv) { + ch2->where = W_LIVE; + return 1; + } +#else (続く) >>430 何かのエラー番号: datが大き杉 ってことですかね。 で、Apacheのcoreをとるには、、、。 if(ch2->zz_filesize > SZ_BIGMAX) return 3002 ; だから、3002でいいのかな。 ということで、今こうです。 結果は同じか。 で、core dumpとってみるです。 +#ifdef SNOWMAN + int rv; +#if defined(AP_SERVER_MINORVERSION_NUMBER) && AP_SERVER_MINORVERSION_NUMBER >= 2 + ap_filter_rec_t frec = {"READDAT", {rdat_filter}, NULL, AP_FTYPE_RESOURCE, NULL, NULL, 0, 0}; +#else + ap_filter_rec_t frec = {"READDAT", {rdat_filter}, NULL, AP_FTYPE_RESOURCE, NULL}; +#endif + ap_filter_t f = {&frec, NULL, NULL, r, r->connection}; + char *uri = apr_pstrcat(r->pool, "/", ch2->zz_ita, "/dat/", ch2->zz_key, ".dat", NULL); + request_rec *rdat = ap_sub_req_lookup_uri(uri, r, &f); + + if (!(rv = rdat->status == HTTP_OK ? ap_run_sub_req(rdat) : rdat->status)) { + apr_off_t blen; + apr_brigade_length(f.ctx, 1, &blen); + if ((ch2->zz_filesize = blen) >= SZ_BIGBUF) + return 3002; + apr_brigade_flatten(f.ctx, ch2->BigBuffer, &ch2->zz_filesize); + apr_brigade_destroy(f.ctx); + ch2->zz_mtime = rdat->mtime ? rdat->mtime + : apr_date_parse_http(apr_table_get(rdat->headers_out, "Last-Modified")); + } + ap_destroy_sub_req(rdat); + + if (!rv) { + ch2->where = W_LIVE; + return 1; + } +#else >>432 CoreDumpDirectory /tmp とかで(httpd プロセスが書き込み可能なディレクトリを指定). >>433 というか,lookfor() はエラー時 0 を返すので,とりあえずその部分では - return 何かのエラー番号; + return 0; にしないとしょうがないですか...... >>435 設定してみた。 で、 if(!lookfor(ch2,r)) return 3001 ; なので、return 0ですか。 ううむ、core dumpしないみたいです。 [Mon Dec 05 10:25:09 2005] [notice] child pid 74701 exit signal Segmentation fault (11) # XXX CoreDumpDirectory /tmp を、httpd.conf に書いたのですが。 そうか.....httpd が最初に root で立ち上がってると OS のデフォルトでは core 吐かないようになってるのかな......とすると,とりあえず直接 User ディレクティブで指定してるユーザで立ち上げてみるとか...... 302 みたいです。<= rdat->status core dumpしてるの、ここじゃないですね。 もっとあとみたい。 ap_rprintf(r, "%s\n", ch2->BigBuffer); ってやっても、なんかちゃんと出ないみたい。 >>441-445 乙です.こちらのローカル環境ではOkなんですが,う〜む...... -funsigned-char しているせいかなぁ、、、。 strlen(ch2->BigBuffer) が、3らしい。ううむ。 う〜む......原因もつかめないとすると......サブリクエスト方式をやめて ソケットで localhost に取りに行く方式にした方がいいんですかねぇ. read.cgi 1呼び出しごとに2プロセス消費することになっちゃいますが...... 同じだった。 BigBufferの最初の4バイトが、どのdatを読んでも 1f 8b 8 0 になるです。 >>449 それも、なんかしゃくですね。ううむ。 バッファを大域変数でとってみたけど、同じだった。 apr_brigade_flatten のところが、ちゃんと動いていない?? ch2->zz_filesize はどうですか......? http://live22x1.2ch.net/test/read.cgi/livejupiter/9240000003/ を読んで、 ap_rprintf(r, "%d\n", ch2->zz_filesize); ってやったら、832 って出たです。 実際には、1428バイトあるですね。 ってことは、、、。 ここは1Gbps内部接続だし、圧縮はなくてもいいような気もするです。 どうすんのがいいのかな。 live22のhttpdでgzipしないようにする? のも、いまいちだなぁ。 サブリクエスト(って言うんでしたっけ)の時に、no gzip にできないのかしら。 ううむ、 こりゃ、live22側のhttpdをごにょごにょするほうがよさげですね。 SetEnvIfか何か使うか。 ってことは、 ・フロントエンドからのリクエストだったら、gzipかからないようにする で、いけるのか。 やろう、やろう。 うーむ、、、。諸事情によりmod_rpaf使っているからなぁ。 REMOTE_ADDRではできないのか。 どうすべ。 とりあえず、後で考えることにして、 mod_deflateはずしておこう。 @ live22 で、read.cgiを入れてみるか。 355 ▲ ◆cZfSunOs.U sage 2005/12/06(火) 05:04:33 なぜか read.cgi スレで「連続投稿ですか?10回」とか出てしまうんで一時避難でこちらへ...... >>455-458 むむ......ってことは...... apr_table_set(r->subprocess_env, "no-gzip", ""); を ap_run_sub_req() の前に実行かな...... 356 ▲ ◆cZfSunOs.U sage 2005/12/06(火) 05:13:01 apr_table_unset(r->headers_in, "Accept-Encoding"); も入れた方がいいかな...... # 相変わらずあっちに書けないんでどなたか転載して頂けると助かります...... 357 ▲ ◆cZfSunOs.U sage 2005/12/06(火) 05:14:25 間違えた...... r じゃなくて rdat じゃないとダメです. apr_table_set(rdat->subprocess_env, "no-gzip", ""); apr_table_unset(rdat->headers_in, "Accept-Encoding"); >>464 これの 357 のやつで、live22の設定をgzipありにしても動いたー。 すばらしいです。これでread.cgiもフロントにできる。 まだ #ifdef しているけど、フロント動作版 read.cgi を live22x[123] に入れた。 これで、大会前の準備はほぼすべて整いました。 深夜までつきあっていただいた SunOS さん、 それから神様 >>455 さん、ありがとう、ありがとう。 rdat(rnew)のヘッダいじるとrにも反映される予感。 2.0と2.2でちょっと違うけど、 rnew->headers_in = r->headers_in; こんな風になってる。 envはコピーのようだけど。 rnew->subprocess_env = apr_table_copy(rnew->pool, r->subprocess_env); >>467 おぉ......となると,こうすべきですね. # "no-gzip" は多分なしで平気ですね. rdat->headers_in = apr_table_copy(rdat->pool, rdat->headers_in); apr_table_unset(rdat->headers_in, "Accept-Encoding"); >>468 組み込みます。 で、昨日の会話でわかったのは、 Apache 2.2系と2.0系のread.cgiでは、バイナリレベルでの互換性がなくなるってことすね。 いずれ2.2化する時には、注意しないと。 live22x[123] に、read.cgi の広告を配布するようにした。 緊急の問題ではないですが,ここ(スタックにデカい配列・構造体を確保)が やはりちょっと気がかりではあります. >>428 >CH2READ ch2 ; >char BigBuffer[SZ_BIGBUF] ; 現状では一応問題なしのようですが,もし今後マルチスレッド MPM を使用するとなると...... メイン以外のスレッドに割り当てられるデフォルトのスタックサイズはメインのより小さいです. ulimit での指定もメイン以外のスレッドには効きません.FreeBSD での具体的数値は わかりませんが,Solaris では 1MB(32-bit) / 2MB(64-bit) がデフォルトです. そして,dat の最大サイズが 512kB となると...... もちろん global / static 変数はマルチスレッドではマズいんで,apr_palloc() で ヒープ領域に確保するようにした方がよさそうです.Apache 2.2 では ThreadStackSize で スタックサイズを指定可能なんで,それで乗り切るって手もなくはないですが...... >>471 気になりますか。 ぼちぼち、apr_palloc にしてみますか。 ちなみにそれで確保したやつって、なんか解放とかしなくていいのかしら。 >>472 malloc() だと明示的な解放が必要ですが,apr_palloc() ではプールの寿命が尽きた時点で自動解放されます. 例えばリクエストプール (r->pool) で確保すれば,リクエスト処理が完了した時点で自動解放されます. >>473 了解です。安心していいってことですね。 【きりたんぽ】雪だるま作戦に思いを馳せながら雑談するスレッド Part28 http://aa5.2ch.net/test/read.cgi/nanmin/1133468879/739-740 739 名前: ◆MUMUMUhnYI [sage] 投稿日:2005/12/07(水) 12:05:52 ?### 過去ログにいったやつが、うまく出ないみたい。< フロント版read.cgi だめな例: 基本的にdat落ちしたやつ全部 http://live22x.2ch.net/test/read.cgi/dancesite/1115133136/ あとで、みてみるということで。 740 名前: ◆MUMUMUhnYI [sage] 投稿日:2005/12/07(水) 12:24:56 ?### >>739 なおした。 read.cgi ver 05.0.2.1 2005/12/07 ライブなdatじゃない場合は、通常と同じ方法でディスクを参照。 >>475 乙です. ---------------------------------------------------------------------- 以前 worker MPM を試してみたら SIGBUS になってしまったことがありましたが, http://aa5.2ch.net/test/read.cgi/nanmin/1118138260/278-279n これは >>471 の要因でスタック領域からはみ出てしまってたのかも知れませんね. >>476 なるほど、ありえますね。 # worker MPMはSpeedyCGIがそのままでは動かないかもという話も。 >>477 そのあたりはこういうことで. # これを受けての worker MPM 挑戦だったわけで...... http://aa5.2ch.net/test/read.cgi/nanmin/1118138260/147 >そういえば...... 今 SpeedyCGI は speedy プロセス呼び出しの形で使ってますか? >mod_speedycgi だとマルチスレッド非対応ですが,speedy プロセス呼び出しなら無関係なんで >マルチスレッド化も可能ではあるんですが...... >>478 そっか、そうでしたね。 ってことは、再チャレンジすることもありうるのか。 でも、再チャレンジする場合、read.cgi で使用している外部関数が、 全部MT-safeじゃないと、いまいちなわけか。 >>480 APR 関数は基本的に,内部では Unsafe な関数の使用を避け (MT-)Safe になるよう 配慮されているため,APR 関数を使っているのならおおかた大丈夫かと思います. ただ,呼び出す関数が (MT-)Safe であっても,処理の流れなどに起因して マルチスレッド環境で問題が起こることもあり得るので(今回出てきた スタック上の巨大変数もしかり),その点が要注意ではありますが. #include <pthread.h> #include <stdio.h> int main() { size_t size; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); printf("%lu\n", (unsigned long)size); return 0; } ---------------------------------------------------------------------- ってのを tiger (FreeBSD 5.3R) 上でやってみたら,libpthread / libthr ともに 65536 (64kB) だそうです.そりゃはみ出しますね...... /* datを読むバッファ領域を、apr_pallocで動的に確保する */ ch2->BigBuffer = apr_palloc(r->pool, SZ_BIGBUF); にしたバージョンを、live22x2で試しました。 問題なさげ。 dso.2ch.netでも問題なければ、これで。 >>484 read.cgi ver 05.0.2.2 2005/12/10 ということで配布して20分ほど経ちましたが、 read.cgi が多い news19 / life7 / hobby あたりでも、問題なさげすね。 read.cの #defineLINK_URL_MAXLEN256 これ。なんか大きすぎない? 普通200以上超えるURLは無いと思うんだが。 ミスorz #define LINK_URL_MAXLEN 256 タブは無視されるのを忘れてたよママン で、今のソースもちと見てみましたが、 もっと大きな値になっているようです。 >>490 そうだな・・・CGIがあったよな・・・ぬるぽ >>491 手元にあるソースは狐の人が書き換える以前のものだからね・・・bbs.cgiスレも見たけどソースは非公開っぽいし。 公開すればもっと質の高い物になると思うよひろゆきタン >>488 まれにAAでも使う それより15個規制はテンプレ作るとき結構きついので可能な範囲で緩和して欲しい ■>>410 みたいに鯖移転前のスレは鯖移転だってことがわかるように書いたほうがいいんじゃないの 移転先で生きてるわけだし これだと普通の過去スレと見分けがつかない ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる