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/
http://qb5.2ch.net/test/read.cgi/operate/1129726127/79-80n これは LANG=ja_JP.SJIS で -c オプションを有効にした際の bbsd による html 生成では対応してますが,read.cgi でも同様の対応をすればいいのかな. まぁ少々面倒ではありますが. ドttp:// ドttps:// てtp:// ドttp:// ドttps:// てtp:// read.cgi ver 05.0.1.2 2005/10/29 #ifdef notdef ap_rprintf(r," <a href=\"http://info.2ch.net/test/tb.cgi?__mode=list&tb_id=%s \">関連ページ</a>\n",url) ; #endif >>383 もしまだ変わってないサーバがあったら、知らせてくださいです。 >>385 それは、管理人に直していただくということで。 │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ │ ≡ ('('('('A` ) │≡ 〜( ( ( ( 〜) │ ≡ ノノノノ ノ ├─┤ ├─┤ │ ↑↑↑↑ │ ├─┤ ├─┤ ││││ │ │ │ ├─┤ ││││ │ ├─┤ ├─┤ ││││ ├─┤ ├─┤ └─┘│││ │ ├─┤ └────┘││ │ │ └───────┘│ ↓ └──────────┘ ∩∧ ∧ おらっしゃあぁぁ!!! ヽ( ゚Д゚) \⊂\ O-、 )〜 ∪ スレッド表示の下部、 「掲示板に戻る」のリンクと「書き込む」ボタンの位置が近すぎて、 間違えて押しそうになります。 「書き込む」ボタンを違う場所に移動した方が良いのではないでしょうか? FireFoxだと特に近いです。 時々、コメントのない書き込みを見かけますが、 これが原因じゃないでしょうか。 >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) で確保すれば,リクエスト処理が完了した時点で自動解放されます. ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.0 2024/04/24 Walang Kapalit ★ | Donguri System Team 5ちゃんねる