You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by "Christopher H. Laco" <cl...@chrislaco.com> on 2005/10/02 20:31:27 UTC

GlobaRequest, restart_count, and RequestUtil

I'm somewhat confused on how to write perl module code that DTRT when 
it's loaded under MP2 when using PerlModule/PerlLoadModule.

Initially, I started out with this code:

> $value = Apache2::RequestUtil->request->dir_config($key) ||

Of course, this failed under MP2 and caused apache to issue the "Global 
request not available" error.

Next I checked the restart count:

> if (Apache2::ServerUtil::restart_count() == 1) {
> 	$value = Apache2::ServerUtil->server->dir_config($key) || $ENV{$key}
> 	|| $default;
> } else {
> 	$value = Apache2::RequestUtil->request->dir_config($key) ||
> 	$ENV{$key} || $default;
> };

Curiously enough, this got rid of the error, but apache simply didn't 
spawn child processes and appeared to start, but didn't. It issued no 
errors or segfaults in any logs.

If I wrapped Apache::RequestUtil->request in eval, the server started. 
I'm not sure if that's a bug or a feature? Shouldn't it have died with 
the "Global request not available"

> if (Apache2::ServerUtil::restart_count() == 1) {
> 	$value = Apache2::ServerUtil->server->dir_config($key) || $ENV{$key}
> 	|| $default;
> } else {
> 	eval{
>		$value = Apache2::RequestUtil->server->dir_config($key) ||
> 		$ENV{$key} || $default;
 >	};
> };

Now, I reread the docs, and realized that I need to be checking for 
restart_count of >= 1. Now I'm confused. If the restart_count == 1, that 
means we're restarting. Does that count get propogated to the child 
processes when they're spawned?

Just because the count is >=1, how does the same code know during a 
request that even though restart_count>=1 that we're not restarting; but 
we're serving a request instead?

Or, is restart_count simply a way to determine that we're in the root 
main process, and when the child process listeners are created, their 
restart_count == 0?

I'm just trying to write code in a config reader that reads 
server->dir_config when it's loaded into apache, and request->dir_config 
when it is called during requests.

-=Chris

Re: GlobaRequest, restart_count, and RequestUtil

Posted by "Christopher H. Laco" <cl...@chrislaco.com>.
Michael Peters wrote:
> 
> Christopher H. Laco wrote:
> 
> 
>>>>use Data::UUID;
> 
> 
> I know this isn't what you're looking for since it doesn't answer the
> question you have, but just out of curiosity why do you need Data::UUID?
> Would something like mod_unique_id work better?
> 
> http://httpd.apache.org/docs/1.3/mod/mod_unique_id.html
> http://httpd.apache.org/docs/2.0/mod/mod_unique_id.html
> 
> It even works well in clusters because it take hostnames into
> consideration. And no stray temp files :)
> 

I use uuid generators in the core modules, which operate outside of any 
web serving mechanism.

Once I found the workaround to keep things from segfaulting, I also 
added support for APR::UUID, so it's even more of a non-issue. :-)

-=Chris

Re: GlobaRequest, restart_count, and RequestUtil

Posted by Michael Peters <mp...@plusthree.com>.

Christopher H. Laco wrote:

>>> use Data::UUID;

I know this isn't what you're looking for since it doesn't answer the
question you have, but just out of curiosity why do you need Data::UUID?
Would something like mod_unique_id work better?

http://httpd.apache.org/docs/1.3/mod/mod_unique_id.html
http://httpd.apache.org/docs/2.0/mod/mod_unique_id.html

It even works well in clusters because it take hostnames into
consideration. And no stray temp files :)

-- 
Michael Peters
Developer
Plus Three, LP


Re: GlobaRequest, restart_count, and RequestUtil

Posted by "Christopher H. Laco" <cl...@chrislaco.com>.
Christopher H. Laco wrote:
> Christopher H. Laco wrote:
> 
>> No love. This block segfaults my apache2/mp2:
>>
>>>     if (exists $ENV{MOD_PERL_API_VERSION} && 
>>> $ENV{MOD_PERL_API_VERSION} == 2) {
>>>         require Apache2::RequestRec;
>>>         require Apache2::RequestUtil;
>>>         require Apache2::RequestIO;
>>>         require Apache2::ServerUtil;
>>>
>>>         my $c = eval {Apache2::RequestUtil->request} || 
>>> Apache2::ServerUtil->server;
>>>
>>>         if ($c) {
>>>             $value = $c->dir_config($key) || $ENV{$key} || $default;
>>>         };
>>>     } elsif ($ENV{MOD_PERL}) {
>>
>>
>>
>> Commenting out the eval line lets the server run fine and dandy. :-(
>>
>> -=Chris
> 
> 
> Oh geez. I think I found the most obscure bug ever. :-/
> I'm working on narrowing down the code to a test case. In a nutshell of 
> seudo code, it looks like this:
> 
>>
>> $ rm -rf /var/tmp/.*
>>
>> use Data::UUID;
>> use Apache2::RequestRec;
>> use Apache2::RequestUtil;
>> use Apache2::RequestIO;
>> use Apache2::ServerRec;
>> use Apache2::ServerUtil;
>>
>> my $ug = Data::UUID->new;
>> my $uuid = $ug->create;
>> print $ug->to_string($uuid);
> 
> 
> 
> There is some variance in there.
> 
> If I simply 'require' instead of 'use' all of the Apache2 modules, all 
> works fine, unless I call ->dir_config, then it goes boom.
> 
> It only happens on the first call to Data::UUID, where it creates two 
> state files in /var/tmp. Every request after that initial segfault works 
> just dandy. On the segfaulted run, it creates the first file, and dies 
> on creating the second. If I run the code again, it creates the second 
> and goes just dandy.... only if I use the Apache modules, or 'require' 
> them and call dir_config.
> 
> If I take the apache2 modules out of the picture and clean /var/tmp, the 
>  first call to Data::UUID succeeds , it creates both files in temp, and 
> there are no segfaults.
> 
> Like I said, the strangest damn thing I've ever seen.
> 
> More to come when I get a specific narrowed test case and a ktrace for it.
> 
> -=Chris
> 
> 

Just as a followup to this. I found a workaround, but that doesn't 
really make any sense either. If I moved the require block outside of 
the sub, the segfault never happens on the first Data::UUID->new with 
the Apache2: modules loaded...

> require Apache2::RequestRec;
> require Apache2::RequestUtil;
> require Apache2::RequestIO;
> require Apache2::ServerUtil;
> 
> 
> if (exists $ENV{MOD_PERL_API_VERSION} && $ENV{MOD_PERL_API_VERSION} == 2) {
>     my $c = eval {Apache2::RequestUtil->request} || Apache2::ServerUtil->server;
> 
> if ($c) {
>     $value = $c->dir_config($key) || $ENV{$key} || $default;};
> } elsif ($ENV{MOD_PERL}) { 


That doesn't make a bit of sense to me, but after 5 days of headaches, 
I'll take it.

-=Chris




Re: GlobaRequest, restart_count, and RequestUtil

Posted by "Christopher H. Laco" <cl...@chrislaco.com>.
Christopher H. Laco wrote:
> No love. This block segfaults my apache2/mp2:
> 
>>     if (exists $ENV{MOD_PERL_API_VERSION} && 
>> $ENV{MOD_PERL_API_VERSION} == 2) {
>>         require Apache2::RequestRec;
>>         require Apache2::RequestUtil;
>>         require Apache2::RequestIO;
>>         require Apache2::ServerUtil;
>>
>>         my $c = eval {Apache2::RequestUtil->request} || 
>> Apache2::ServerUtil->server;
>>
>>         if ($c) {
>>             $value = $c->dir_config($key) || $ENV{$key} || $default;
>>         };
>>     } elsif ($ENV{MOD_PERL}) {
> 
> 
> Commenting out the eval line lets the server run fine and dandy. :-(
> 
> -=Chris

Oh geez. I think I found the most obscure bug ever. :-/
I'm working on narrowing down the code to a test case. In a nutshell of 
seudo code, it looks like this:
> 
> $ rm -rf /var/tmp/.*
> 
> use Data::UUID;
> use Apache2::RequestRec;
> use Apache2::RequestUtil;
> use Apache2::RequestIO;
> use Apache2::ServerRec;
> use Apache2::ServerUtil;
> 
> my $ug = Data::UUID->new;
> my $uuid = $ug->create;
> print $ug->to_string($uuid);


There is some variance in there.

If I simply 'require' instead of 'use' all of the Apache2 modules, all 
works fine, unless I call ->dir_config, then it goes boom.

It only happens on the first call to Data::UUID, where it creates two 
state files in /var/tmp. Every request after that initial segfault works 
just dandy. On the segfaulted run, it creates the first file, and dies 
on creating the second. If I run the code again, it creates the second 
and goes just dandy.... only if I use the Apache modules, or 'require' 
them and call dir_config.

If I take the apache2 modules out of the picture and clean /var/tmp, the 
  first call to Data::UUID succeeds , it creates both files in temp, and 
there are no segfaults.

Like I said, the strangest damn thing I've ever seen.

More to come when I get a specific narrowed test case and a ktrace for it.

-=Chris



Re: GlobaRequest, restart_count, and RequestUtil

Posted by "Christopher H. Laco" <cl...@chrislaco.com>.
Geoffrey Young wrote:
>>I'm just trying to write code in a config reader that reads
>>server->dir_config when it's loaded into apache, and request->dir_config
>>when it is called during requests.
> 
> 
> all your other questions aside for the moment, I don't understand from where
> you might be trying to do that.
> 
>   My::Package;
> 
>   # this code executes on server startup when using PerlModule
> 
>   sub handler {
>     # this code executes on each request
>   }
> 
> if you're worried about the server part being called when the module is
> being loaded initially during a request (say, if someone didn't use
> PerlModule) then something like this might work
> 
>   my $r_or_s = eval { Apache2::RequestUtil->request } ||
>                       Apache2::ServerUtil->server;
> 
>   my $value = $r_or_s->dir_config($key) || $ENV{$key} || $default;
> 
> or somesuch.

No love. This block segfaults my apache2/mp2:

>     if (exists $ENV{MOD_PERL_API_VERSION} && $ENV{MOD_PERL_API_VERSION} == 2) {
>         require Apache2::RequestRec;
>         require Apache2::RequestUtil;
>         require Apache2::RequestIO;
>         require Apache2::ServerUtil;
> 
>         my $c = eval {Apache2::RequestUtil->request} || Apache2::ServerUtil->server;
> 
>         if ($c) {
>             $value = $c->dir_config($key) || $ENV{$key} || $default;
>         };
>     } elsif ($ENV{MOD_PERL}) {

Commenting out the eval line lets the server run fine and dandy. :-(

-=Chris

Re: GlobaRequest, restart_count, and RequestUtil

Posted by "Christopher H. Laco" <cl...@chrislaco.com>.
Geoffrey Young wrote:
[snip]
> if you're worried about the server part being called when the module is
> being loaded initially during a request (say, if someone didn't use
> PerlModule) then something like this might work
> 
>   my $r_or_s = eval { Apache2::RequestUtil->request } ||
>                       Apache2::ServerUtil->server;
> 
>   my $value = $r_or_s->dir_config($key) || $ENV{$key} || $default;
> 
> or somesuch.

That'll do the trick. I was just to do it the hard way (by checking if 
we're starting) rather than just letting eval handle the failures.

Thanks Geoff,
-=Chris

Re: GlobaRequest, restart_count, and RequestUtil

Posted by Geoffrey Young <ge...@modperlcookbook.org>.
> I'm just trying to write code in a config reader that reads
> server->dir_config when it's loaded into apache, and request->dir_config
> when it is called during requests.

all your other questions aside for the moment, I don't understand from where
you might be trying to do that.

  My::Package;

  # this code executes on server startup when using PerlModule

  sub handler {
    # this code executes on each request
  }

if you're worried about the server part being called when the module is
being loaded initially during a request (say, if someone didn't use
PerlModule) then something like this might work

  my $r_or_s = eval { Apache2::RequestUtil->request } ||
                      Apache2::ServerUtil->server;

  my $value = $r_or_s->dir_config($key) || $ENV{$key} || $default;

or somesuch.

keep in mind that $s->dir_config won't contain the results of a
per-directory merge, while $r->dir_config will.  so $value might be
different depending on whether you use $r or $s, even during request time.

if that's not what you mean, then under what circumstances might you want to
call the exact same block of code where it may or may not be during a
request?  that might help us focus on what you need to do a bit better.

HTH

--Geoff