2004年12月26日
Class::DBIとApache::ReloadでInternal Server Error
mod_perlで動作するアプリケーションを開発する場合、更新されたモジュールをリロードしてくれるApache::Reloadのようなモジュールを利用するのが一般的だと思いますが、Apache::Reloadが有効になっている状態でClass::DBIを継承したモジュールを更新すると以下のようなエラーメッセージをはいてInternal Server Errorになるという現象に悩んでました。
[Sun Dec 26 20:06:02 2004] [error] Can't use an undefined value as a HASH reference at /usr/local/perl-5.8.5/lib/site_perl/5.8.5/Class/DBI/Relationship/HasMany.pm line 51.\n Compilation failed in require at /usr/local/perl-5.8.5/lib/site_perl/5.8.5/Apache/Reload.pm line 140.\n
そこで少し調べてみると、Re: Apache::Reload and CDBI won't play togetherに次のような記述が。
Class::DBI prevents you from overwriting already declared methods. To fix this, you would need to hack Apache::Reload to clear the symbol table of your package just before reloading it, or hack Class::DBI to ignore overwriting subs.
Class::DBIはすでに宣言されているメソッドの上書きをさせないのが原因で、これを回避するには、リロードされる前にシンボルテーブルをクリアするようにApache::Reloadをhackするか、上書きを無視するようにClass::DBIをhackしろということのようです。
そこで今回は開発環境でしか使わないApache::Reloadをhackし、パッチを書いてみました。(Class::DBIに比べてApache::Reloadはコードの量が少ないのでhackが簡単。)
--- Reload.pm.orig 2004-12-26 19:35:31.000000000 +0900
+++ Reload.pm 2004-12-26 20:22:40.000000000 +0900
@@ -122,6 +122,14 @@
}
if ($mtime > $Stat{$file}) {
+ my $package = $key;
+ $package =~ s/\//::/g;
+ $package =~ s/\.pm$//;
+ if ( UNIVERSAL::isa($package, 'Class::DBI') ){
+ no strict 'refs';
+ warn "Apache::Reload: clear the symbol table of $package\n" if $DEBUG;
+ %{"$package\::"} = ();
+ }
delete $INC{$key};
# warn "Reloading $key\n";
if (my $symref = $UndefFields{$key}) {
Continuing the discussion...
このエントリーのトラックバックURL:
http://hori-uchi.com/mt/trackback/248
