2005.12.13

PEARのライブラリ

PHPを使ってる人には馴染み深い存在であるPEARライブラリ。今回は、その中のHTTP_Requestクラスの不具合と、その修正方法について記述します。

このHTTP_Requestクラスには、通常環境であればほぼ問題にならないようなある不具合が存在しています。その不具合とは、HTTPリクエストにたいする応答ヘッダーに記述されている「Content-Length」に対応していないという不具合です。

では、何でContent(内容)の受信を終了する判定になっているかというとSocketクラスのバッファ状態がEOFになるまで繰り返すという処理になってます。具体的なコードを書くことはできませんが、このあたりはソースを追っかけたら即分かると思います。

さて、この問題は一般的に使われているHTTPサーバーであれば、ほぼ問題は発生しないのですが、HTTPサーバーの仕様によっては、受信処理がネットワークタイムアウトまで終了しないという問題が発生してしまいます。

この問題を解決するには、Content-Length分だけ受信するようにすれば良いだけなので、修正自体はとても簡単です。

というか、なんでこんなところサボってるのか謎です。

以前、PEARのDBクラスでMySQLのSelectDBがクエリーを送信するたびに実行されてる件について調査したときも、クエリー実行時に必ずSelectDBするコードが紛れ込んでて辟易したのですが、今回も同じぐらい辟易しました。

というわけで、PEARライブラリ自体はとても有用なライブラリ群であるけれども、更に活用していくためには、せっかくのソース付きライブラリ(というか、ソース自体がライブラリ)なので気に入らない部分は自分で修正しちゃいましょうという話でした。

|

2005.09.07

ApacheのRewriteでdbタイプを指定するには?

以前ApacheのRewriteMapでprgモードを使ったという話を書いたのですが、元々はdbmモードを使いたかったのに、dbmモードだと正常にRewrite動作させられなかったので断念したという経緯があって、やむを得ずprgモードを利用していました。

んで、RewriteMapでprgモードを利用する場合、RewriteLockディレクティブをhttpd.confで指定しておかないといけません。でないと、複数起動したhttpdプロセスが同時にプログラムにアクセスして、全然違うRewrite結果を得てしまうという現象が発生します。

ですが、このRewriteLockの仕様がしょぼくて、内部的にはセマフォを使ってるのですがセマフォの作り方が「常に新しい名前で作成」なんです。

つまり、httpdが異常終了したときにセマフォオブジェクトが新しい名前で作成されてしまい、生き残ったhttpdとのロック機能が正常に働かなくなり、全然違うRewrite結果を出してしまうという現象が発生しました。

この現象から分かったことは、RewriteLockを使ったままでは異常時の再起動で使い物にならなくということです。そこで、もう一度dbmモードに挑戦することになりました。

dbmモードの作成に関しては、別の人にお願いしてる状態なのですが、やっぱり上手く行かないようです。仕様を探すのですが、Web上では発見することができません。仕方なくmod_rewrite.cを読むと、隠れ仕様が見つかりました。

dbmにはいくつかのdbタイプがあるのですが、mod_rewriteの仕様書ではdbmモードではdbタイプはndbmを使って、httpd.conf内では以下のような書き方をしろとなっています。

RewriteMap <map名> dbm:<path>
 例)
 RewriteMap hoge dbm:/path/hoge.db

ですが、ソースを読むとdbタイプはGDBM、SDBM、NDBM、DBの4つのタイプから選択できるようになってました。(apr_dbm.c内で発見)

dbタイプの指定の仕方は以下のとおりです。

RewriteMap <map名> dbm=<dbタイプ>:<path>
 例)
 RewriteMap hoge dbm=GDBM:/path/hoge.db

ちなみに、dbタイプを指定しなかった場合、defaultのdbタイプが使われるのですが、このデフォルトのdbタイプとはどのdbの事を指すのかというのもソースを覗き見ないと分かりませんでした。詳しく知りたい人はapr_dbm.cを見たら分かるのですが、私が見た感想としては「指定して置いた方が無難」です。(指定しなかった場合、Apacheのコンパイル結果に依存します。)

上記の情報は、どこを探しても日本語の情報は無かったので提供しておきます。(英語でも情報は見つからなかったのですが、英語の場合は見つけきれてないだけという可能性大。)

まあ、今回の調査でdbタイプが指定できるので、自分が使い慣れてるdbタイプを使えることが分かりました。こういう情報が欲しいんだよなぁ。サクっと見つかって欲しいのに…。

|

2005.07.14

ApacheのRewriteMap機能

仕事上の理由から、ApacheのRewriteMap機能を利用することになりました。あれこれ調査した結果、prgモードを使うことに。

んで、prgモードのサンプルってのがperlで書いてあったりして「perlは暗号にしか見えん!」状態な私には地獄な作業なのかと戦々恐々としてました。

で、ふと思いついた。

「あ、gccがあるじゃないか。つまり、C言語で書けばいいじゃないか。」

というわけで、C言語で書いてしまいました。

最初、全然仕様書を読まずにperlの暗号を解読するようにあれこれと作ってたのですが、1度は正常にマッピングされるものの、二度目からはされません。原因も良く分かりません。しょぼーん。

仕方ないので仕様書を読んでみると、毎回プロセス起動するわけじゃなかったようです。サクサク(?)と作り変えて難を逃れました。

作り終えて、横に居るリーダーが一言「もう、そうせいじさんしかメンテナンスできないね」。

これが一番ショックでした。

|

2005.06.09

MySQLの罠2

今度のMySQLの罠は超巨大な罠です。

以前の記事
で書いたカーディナリティがNULLな件についてですが、これがNULLだと二次インデックスが作り損なのは間違いありません。これは、MySQLのオプティマイザーが賢く動こうとして賢く動けてないだけなのですが、これを責めるのはあまりに酷でしょう。

では、このカーディナリティを更新し、正常に動作させるにはどうしたらよいかというと、「OPTIMIZE TABLE」なるSQLを実行すれば良いようです。ふむふむ、なるほど。

念のためOptimize Tableのリファレンスを確認すると、使用中はテーブルロックしてくれるようなので、安心設計です。

では、後は実行するだけです。ドキドキしながら、OptimizeTableを実行した結果は…。

テーブルインデックスが破壊されてしまいました!!!!!

というわけで、MySQLを使ってる皆さん。二次インデックスが利用されないからといって、Optimize Tableを使ってはいけません。でないと、破壊された場合に、サービスを一時停止してisamchkを別に実行する必要が出てきてしまいます。

あまりに大きな罠すぎて、最初何が起こったかわかりませんでした。この信頼性は、前使ってたDBISAMというファイル共有型のDBと何ら変わりが無いじゃないですか。せめてインデックスの再構築ぐらい、さくさく成功させてください…。

#念のため、ハードウェア障害とかじゃないです。サービス停止して、isamchkしたらちゃんと動くようになりましたので。

|

2005.05.31

PHPのしょぼ関数の続報

先日書いた記事 に関してなんだけど、よくよく考えると「型に縛られない素晴らしい言語なんだ!」って強調したかったのかもしれない。この関数の作成者は。

なんせ、一つの関数の戻り値がboolean型だったり、int型だったりできるんだもん!すごいじゃん!ってなもんだ。

だとしたら、完全な独り善がりだよね。プログラマは、そんな「型」なんてややこしいこと考えなくても使えることをPHPの利点だと思ってんのにさ。もっとシンプルに行こうよ。わざわざ戻り値の型を変更することないよ。めんどいし。

|

2005.05.30

MySQLの罠

MySQLのネタをいくつか書きましたが、MySQLの罠にはまってしまいました。リリース前で良かった。危ない危ない。

その罠とは、auto_incrementを指定しても、指定した項目を単独のUNIQUEインデックス(UNIQUEであればいいので、PRIMARYでもOKです)に指定しないと、最大値のレコードを削除したらインクリメント値が再利用されてしまうという罠です。

再利用されないのが常識かと思ってたのですが、違ったようです。まあ、マニュアル読んだら、ちゃんと書いてあるんですけどね。ローカルな仕様で悩むってのは、こういうことなんだなぁ。

|

PHPのしょーもない関数

array_searchという関数があるのですが、これの戻り値が問題なんです。失敗したときはFALSEを返して、成功したらインデックス値を返すらしい。

ということは、先頭が一致した場合は0じゃねーか(FALSEは内部的には0と同じ扱い)。

どうやって、見つかったか見つかってないかを判断するのか途方にくれて、結局別の関数を使って処理を進めちゃいました。

んで、それまで本とかWindowsヘルプファイルで関数確認してたんだけど、さっきWebのマニュアルを開いてみたら、比較演算子を変更したら良いらしい。

http://php.s3.to/man/function.array-search.html

最初からこっち見とけば良かった。

っちゅーか、この程度の関数なら自作したが早いよね。FALSEじゃなくて、-1を戻すようにすれば良いのに。型の概念が希薄な言語なんだから、せめて戻り値ぐらいは型を合わせておこうよ。関数の設計者は、何考えてたんだろうな。

|

2005.05.28

PHPのデバッグ

なんてデバッグのし辛い言語なんだ。

ステップ実行させてくれー。

|

2005.05.24

MySQLのインデックスについて その2

やっぱり、初心者だけの事はありました。

MySQLのインデックスを選択するオプティマイザが馬鹿なので、「MySQLうんこー」とか小学生並みの罵倒をしてたのですが、どうやらインデックスの作成方法かテーブルの作成方法か、MySQLの動作モードか、このどれかに問題がありそうです。

というのも、インデックスを使用するか使用しないかという選択は、統計情報を元にオプティマイザが判断を行うのですが、速いインデックスを選択してくれなかったテーブルのインデックス情報を見ると「Cardinality」がNULLになってました。

つまり、統計情報がこれっぽっちも存在してなかったことになります。

となると、正常な判断ができるわけもなく、MySQLのオプティマイザはなんとなくこっちかなって感じで遅い方を選択してるようです。

というわけで、インデックスに使用してる項目の性質などを考えたら、適切なインデックスを指示しつつSQL文を書いた方が良いようです。

というか、統計データをなんで取ってないんだろう…。

|

2005.05.21

RSSとinnerHTML

JavaScriptとRSSとinnerHTMLの組み合わせが凄すぎます。今、仕事でやってるプロジェクトが片付いたら、暇を作って私の書いてる日記やらブログやらの更新情報をトップページに載せる奴を組み込みます。

名づけて記述するブログを分散化することによる、負荷分散とリスク分散の仕組み。

って、そんなカッコイイもんじゃなくて、面白いぜーってやりたいだけです。いやー、innerHTMLの仕組みが凄すぎますね。ワクワクしてきました。

というわけで、全然PHPとは絡んでなさそうに見えますが、PHPもからませて楽しいことがやりたいだけです!初心者なりに楽しい事ができるといいなぁ。

[追記] http://homepage1.nifty.com/aoten/blog_group.html こんな感じで作りってみたい。

|

より以前の記事一覧