You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Todd Finney <tf...@boygenius.com> on 2007/01/30 22:47:58 UTC

Apache::Session::MySQL, light/heavy proxy, wedging

I'm having a problem with Apache::Session::MySQL and mod_proxy, and I can't 
seem to wrap my head around what's going on.

I have two servers running in the light/heavy configuration as outlined in 
the guide.   Both servers are 1.3.34.  On the lightweight server, my proxy 
section looks like this:

----
RewriteEngine on
RewriteRule ^/images - [L]
RewriteRule .(css|ico)$ - [L]
RewriteRule .swf$ - [L]
RewriteRule ^.(.*) http://192.168.0.4:8080/$1 [P]
----

On the heavy server, I'm running ePerl with a PerlHeaderParserHandler that 
is essentially just a wrapper for Apache::Session::MySQL

----
PerlHeaderParserHandler BoyGenius::AccessManagement::SessionTestTwo

<FilesMatch "\.phtml$">
        SetHandler perl-script
        PerlHandler Apache::ePerl
</FilesMatch>
-----

I have a big complicated handler that does all kinds of fancy crap, but in 
the interest of nailing down the problem I've replaced it with one that was 
pretty much cut and pasted from the Apache::Session perldoc:

----
package BoyGenius::AccessManagement::SessionTestTwo;

use Apache::Session::MySQL;
use Apache;

use strict;

sub handler {
     my $r = shift;

     #read in the cookie if this is an old session
     my $cookie = $r->header_in('Cookie');
     $cookie =~ s/SESSION_ID=(\w*)/$1/;

     #create a session object based on the cookie we got from the browser,
     #or a new session if we got no cookie

     my %session;
     tie %session, 'Apache::Session::MySQL', $cookie, {
         DataSource => 'dbi:mysql:boygenius', #these arguments are
         UserName   => 'nobody',         #required when using
         Password   => 'XXXXXXXXX',           #MySQL.pm
         LockDataSource => 'dbi:mysql:boygenius',
         LockUserName   => 'nobody',
         LockPassword   => 'XXXXXXXXX'
         };

     $r->pnotes('SESSION_ID', $session{_session_id});

     #Might be a new session, so lets give them their cookie back
     my $session_cookie = "SESSION_ID=$session{_session_id};";
     $r->header_out("Set-Cookie" => $session_cookie);
}

1;
----

The problem I'm having is with this line:

     $r->pnotes('SESSION_ID', $session{_session_id});

When this line is in there, I see the following behavior:

- When I fire up a new browser and access http://192.168.0.4/, the browser 
hangs.  In my bigger fancier handler with more detailed logging, it seems 
to hang right before the session tie.

- When I fire up a new browser and access http://192.168.0.4/index.phtml, 
the page comes up as it should.

- When I fire up a new browser and access http://192.168.0.4:8080/, the 
page comes up as it should.

- When I fire up a new browser and access either 
http://192.168.0.4/index.phtml or http://192.168.0.4:8080/, and then access 
http://192.169.0.4/, the page comes up fine.

- When I fire up a new browser and access http://192.168.0.4/ and then 
access either http://192.168.0.4/index.phtml or http://192.168.0.4:8080/, 
none of the pages will come up.

I've replicated this on two different setups, and it acts the same everywhere.

index.phtml has nothing but straight html in it, if that matters.

I'm not even going to attempt to guess what's going on here, but I could 
really use a smack with the clue brick.

thanks!







Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Jonathan Vanasco <jv...@2xlp.com>.
On Jan 30, 2007, at 6:44 PM, Todd Finney wrote:

> The bigger, fancier test case checks all of that.

ok.  great.   sorry for assuming you didn't have that already -- just  
have to be sure.

> What I posted was a simplified test case, in order to demonstrate  
> the problem in as few lines of code as possible.  I even used as a  
> base a code section that should be "known good", as it appears in  
> the perldoc for the manual.  I thought that I made this pretty  
> clear, I'll try harder next time.

well, you said fancy crap.  i didn't know what kind of fancy crap.

> Problems such as Apache::Session timing out are unlikely to be the  
> culprit, as the problem is reliably reproducible under narrow,  
> specific circumstances as outlined in my original message.   
> Sessions created under the successful cases never fail, and  
> sessions created under the failure cases never succeed.  Removing  
> the single line in question causes all requests to succeed.

honestly, you'd be surprised.  i've seen tons of odd issues with it.

there's definitely an issue with the tied variable then.  i've had  
that happen before.  i can't seem to remember what the issue was.

I'm going through the old listserv articles right now

this *might* give you some ideas
	http://www.issociate.de/board/post/309410/ 
Apache::Session::MySQL_lock_troubles.html

a bunch of the '(X-No-Archive: yes)' deleted posts in that are from  
you :)

i remember debugging Apache::Session::MySQL at some point myself ,  
and that gave solved some issues.  I can't seem to remember where the  
issue was.  I do recall having the same problem as you at some point  
though :(

// Jonathan Vanasco

| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
- - - - - - - - - - - - - - - - - - -
| SyndiClick.com
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
- - - - - - - - - - - - - - - - - - -
|      FindMeOn.com - The cure for Multiple Web Personality Disorder
|      Web Identity Management and 3D Social Networking
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
- - - - - - - - - - - - - - - - - - -
|      RoadSound.com - Tools For Bands, Stuff For Fans
|      Collaborative Online Management And Syndication Tools
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
- - - - - - - - - - - - - - - - - - -



Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Todd Finney <tf...@boygenius.com>.
At 05:52 PM 1/30/2007 -0500, Jonathan Vanasco wrote:
>my gut feeling is that you're having an error that deals with valid /
>invalid / new session ids.  but it could really be anything - maybe
>you're having connectivity issues with apache::session (timing out ?
>are you using apache::dbi ? etc )

The bigger, fancier test case checks all of that.

----
        my %session = ();
         $log->info("AccessManagement::Session: tying session");
         eval {
             tie %session, 'Apache::Session::MySQL',$session_id, {
                 DataSource=>'dbi:mysql:boygenius',
                 UserName=>'nobody',
                 Password=>'XXXXXXXX',
                 LockDataSource=>'dbi:mysql:boygenius',
                 LockUserName=>'nobody',
                 LockPassword=>'XXXXXXXX',
             };
         };
         if ($@) {
             $log->info('AccessManagement::Session: '.$@);
             undef $session_id;
             tie %session, 'Apache::Session::MySQL',$session_id, {
                 DataSource=>'dbi:mysql:boygenius',
                 UserName=>'nobody',
                 Password=>'XXXXXXXX',
                 LockDataSource=>'dbi:mysql:boygenius',
                 LockUserName=>'nobody',
                 LockPassword=>'XXXXXXXX',
             };
             $log->info('AccessManagement::Session: New Session Created 
Successfully.');
         }
         $log->info('AccessManagement::Session: session id: '.$session_id);

----

It wedges at "AccessManagement::Session: tying session"

What I posted was a simplified test case, in order to demonstrate the 
problem in as few lines of code as possible.  I even used as a base a code 
section that should be "known good", as it appears in the perldoc for the 
manual.  I thought that I made this pretty clear, I'll try harder next time.

Problems such as Apache::Session timing out are unlikely to be the culprit, 
as the problem is reliably reproducible under narrow, specific 
circumstances as outlined in my original message.  Sessions created under 
the successful cases never fail, and sessions created under the failure 
cases never succeed.  Removing the single line in question causes all 
requests to succeed.

>just as an example, in my session class i do:

Yea, thanks.

>anyways, you shouldn't be writing new code for 1.3.x  unless you're
>stuck supporting a legacy app.

And thanks again.






Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Perrin Harkins <ph...@gmail.com>.
On 1/31/07, Todd Finney <tf...@boygenius.com> wrote:
> I can set it up so that it does the copy->save to pnotes dance for every
> one of the variables, except perhaps for the actual session handle, which
> is stuck into pnotes('SESSION_HANDLE').

If you really need to keep a ref to $session like that, then you
definitely have to use the is_initial_req approach or turn off the
exclusive locking.

- Perrin

Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Todd Finney <tf...@boygenius.com>.
At 09:36 AM 1/31/2007 -0500, Perrin Harkins wrote:
>On 1/31/07, Todd Finney <tf...@boygenius.com> wrote:
>>It's responsible for making sure that the client has a session, and it
>>takes any of the values in the session and stores them in pnotes.
>
>Are you sure that you had removed all of these when you did the test
>of copying the session_id, and it still had the same problem?

Now that you mention it, I'm fairly certain that I didn't.  That stab was 
before I moved to the test case, which means that all of that stuff would 
have still been in there.  Damn my damnable dumbassery.

I can set it up so that it does the copy->save to pnotes dance for every 
one of the variables, except perhaps for the actual session handle, which 
is stuck into pnotes('SESSION_HANDLE').

It would appear the using is_initial_req is the best possible solution to 
all of this.







Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Perrin Harkins <ph...@gmail.com>.
On 1/31/07, Todd Finney <tf...@boygenius.com> wrote:
> It's responsible for making sure that the client has a session, and it
> takes any of the values in the session and stores them in pnotes.

Are you sure that you had removed all of these when you did the test
of copying the session_id, and it still had the same problem?

- Perrin

Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Todd Finney <tf...@boygenius.com>.
At 08:29 AM 1/31/2007 -0500, Perrin Harkins wrote:
>On 1/31/07, Todd Finney <tf...@boygenius.com> wrote:
>>Wouldn't throwing a
>>         return DECLINED unless $r->is_initial_req;
>>at the top of the handler fix the problem, in that case?
>
>Probably, if you don't actually need this handler to run for the final
>URI.  What's the purpose of the handler?

It's responsible for making sure that the client has a session, and it 
takes any of the values in the session and stores them in pnotes.

There's an authentication handler further down the line that uses some of 
those values (if they exist) to determine whether or not the user has 
permission to access the resource.  That returns OK unless 
is_initial_request, though, so I don't think that a change made in 
Session.pm will affect that.

I've gone ahead and added that line, we'll see how it works out.

Thanks for your help, Perrin and Jonathan, I really appreciate it.


Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by to...@tuxteam.de.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Wed, Jan 31, 2007 at 08:29:55AM -0500, Perrin Harkins wrote:
> On 1/31/07, Todd Finney <tf...@boygenius.com> wrote:
> >Wouldn't throwing a
> >
> >         return DECLINED unless $r->is_initial_req;
> >
> >at the top of the handler fix the problem, in that case?
> 
> Probably, if you don't actually need this handler to run for the final
> URI.  What's the purpose of the handler?
> 
> >That occurred to me, and one of the first things that I tried was something
> >like this:
> >
> >         my $temp_session=$session{_session_id};
> >         $r->pnotes('SESSION_ID', $temp_session);
> >
> >It didn't change anything
> 
> It was worth a shot.  I really thought that would do it though.

If I understood that correctly (which I might quite well not!), if
pnotes takes a ref to whatever is put in, it'll take a ref to the
$session this way too. Maybe you want to put the _session_id in there
(but then, you'll have to cope with the case that the corresponding
session might disapper -- kind of a weak reference).

Regards
- -- tomás
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFFwX7KBcgs9XrR2kYRAkBCAJ9+0KGWQrStyS/igg3VEk6E46+TbgCfSQcy
YeCsiFXgo5swBMGtJ+7vgL0=
=PKFS
-----END PGP SIGNATURE-----


Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Perrin Harkins <ph...@gmail.com>.
On 1/31/07, Todd Finney <tf...@boygenius.com> wrote:
> Wouldn't throwing a
>
>          return DECLINED unless $r->is_initial_req;
>
> at the top of the handler fix the problem, in that case?

Probably, if you don't actually need this handler to run for the final
URI.  What's the purpose of the handler?

> That occurred to me, and one of the first things that I tried was something
> like this:
>
>          my $temp_session=$session{_session_id};
>          $r->pnotes('SESSION_ID', $temp_session);
>
> It didn't change anything

It was worth a shot.  I really thought that would do it though.  Maybe
in your real code there's some additional line that keeps $session
from going out of scope.  You could explicitly undef it at the end of
your HeaderParserHandler if that's the case.

- Perrin

Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Todd Finney <tf...@boygenius.com>.
At 12:30 AM 1/31/2007 -0500, Perrin Harkins wrote:
>As for what's going wrong, my guess is that it has to do with the
>internal redirects that happen when you access / as opposed to
>/index.phtml.  You are trying to open the session in the
>HeaderParserHandler phase, so it's going to open a session, then do an
>internal redirect, and try to open the same session again, effectively
>deadlocking.

Wouldn't throwing a

         return DECLINED unless $r->is_initial_req;

at the top of the handler fix the problem, in that case?

>That's a 2.0 doc, but it applies to 1.0 as well: pnotes() increases
>the reference count to $session rather than copying it, so it doesn't
>get destroyed until after the internal redirect has completed and
>pnotes gets torn down.  If you use a temporary variable to hold the
>_session_id key, this will not happen and that may fix your problem.

That occurred to me, and one of the first things that I tried was something 
like this:

         my $temp_session=$session{_session_id};
         $r->pnotes('SESSION_ID', $temp_session);

It didn't change anything, so I decided that either (a) that wasn't the 
problem, or (b) after years of doing this I *still* don't fundamentally 
understand references.  Either conclusion made me uncomfortable, so I went 
looking for other potential solutions.



Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Perrin Harkins <ph...@gmail.com>.
On 1/30/07, Todd Finney <tf...@boygenius.com> wrote:
> The sessions are modified on every request, to set a last_access time, and
> they're modified on login to set an authentication token.  I can't think of
> circumstances under which two different requests would attempt to modify a
> given session at the same time.

The biggest risks are things like multiple windows, AJAX calls, or
some kind of auth handler that needs to load the session for every
image request.

> As much as I'd really like to understand what's actually happening here,
> I'll switch to A::S::Lock::Null if you think that's the best bet.

For many people it is, but I can't say for certain if it is for you.
There may be a simpler solution.  See below.

> I don't
> see an example in the Apache::Session docs for switching the locking class,
> though - may I have a pointer?

You can either use Apache::Session::Flex or make your own
Apache::Session::MySQL.  Open up Apache::Session::MySQL and look at
the code.  It's nothing more than a config file.  If you copy it,
change the name (and package), and change the name of the locking
class, that will work.

As for what's going wrong, my guess is that it has to do with the
internal redirects that happen when you access / as opposed to
/index.phtml.  You are trying to open the session in the
HeaderParserHandler phase, so it's going to open a session, then do an
internal redirect, and try to open the same session again, effectively
deadlocking.

But why does that $r->pnotes call make all the difference?  Because
pnotes() is special, as described here:
http://perl.apache.org/docs/2.0/api/Apache2/RequestUtil.html#C_pnotes_

That's a 2.0 doc, but it applies to 1.0 as well: pnotes() increases
the reference count to $session rather than copying it, so it doesn't
get destroyed until after the internal redirect has completed and
pnotes gets torn down.  If you use a temporary variable to hold the
_session_id key, this will not happen and that may fix your problem.

I could rant about all the things that bother me about
Apache::Session, but the bottom line is what works for you.  Try the
suggestions here and good luck.

- Perrin

Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Todd Finney <tf...@boygenius.com>.
At 08:57 PM 1/30/2007 -0500, Perrin Harkins wrote:
>Before I spend too much time analyzing your symptoms, are you sure
>that your application requires excusive locks on sessions?  If not,
>you can use Apache::Session::Lock::Null for your locking class.

Eminently reasonable.

>The difference is that without exclusive locks
>you can get lost updates if a user tries to modify a session from two
>separate requests simultaneously.  (Not usually an issue, but it can
>be for certain kinds of applications.)

The sessions are modified on every request, to set a last_access time, and 
they're modified on login to set an authentication token.  I can't think of 
circumstances under which two different requests would attempt to modify a 
given session at the same time.

As much as I'd really like to understand what's actually happening here, 
I'll switch to A::S::Lock::Null if you think that's the best bet.  I don't 
see an example in the Apache::Session docs for switching the locking class, 
though - may I have a pointer?

thanks!



Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Perrin Harkins <ph...@gmail.com>.
On 1/30/07, Todd Finney <tf...@boygenius.com> wrote:
> - When I fire up a new browser and access http://192.168.0.4/, the browser
> hangs.  In my bigger fancier handler with more detailed logging, it seems
> to hang right before the session tie.

Any time that Apache::Session hangs, it's because of the excusive
locking that it does.  It tries to get a lock when you call tie(), and
if another session object with the same ID is already holding that
lock, it will hang.  A glance at your problem description makes it
sound like there could be internal redirects happening, while the
parent request holds onto its session and lock, causing a hang.

Before I spend too much time analyzing your symptoms, are you sure
that your application requires excusive locks on sessions?  If not,
you can use Apache::Session::Lock::Null for your locking class.  You
will not get any data corruption because MySQL already insures that
updates are atomic.  The difference is that without exclusive locks
you can get lost updates if a user tries to modify a session from two
separate requests simultaneously.  (Not usually an issue, but it can
be for certain kinds of applications.)

- Perrin

Re: Apache::Session::MySQL, light/heavy proxy, wedging

Posted by Jonathan Vanasco <jv...@2xlp.com>.
On Jan 30, 2007, at 4:47 PM, Todd Finney wrote:

> I have two servers running in the light/heavy configuration as  
> outlined in the guide.   Both servers are 1.3.34.  On the  
> lightweight server, my proxy section looks like this:

first off, you should be running 2.0.x by now

try this:

>     my %session;
	eval {
> 	    tie %session, 'Apache::Session::MySQL', $cookie, {
> 	        DataSource => 'dbi:mysql:boygenius', #these arguments are
> 	        UserName   => 'nobody',         #required when using
> 	        Password   => 'XXXXXXXXX',           #MySQL.pm
> 	        LockDataSource => 'dbi:mysql:boygenius',
> 	        LockUserName   => 'nobody',
> 	        LockPassword   => 'XXXXXXXXX'
> 	        };
	};
	if ( $@ ) {
		print STDERR "\n ERROR TIE -> $@ ";
	}

> I'm not even going to attempt to guess what's going on here, but I  
> could really use a smack with the clue brick.

my gut feeling is that you're having an error that deals with valid /  
invalid / new session ids.  but it could really be anything - maybe  
you're having connectivity issues with apache::session (timing out ?  
are you using apache::dbi ? etc )

just as an example, in my session class i do:

	is there a cookie ?  if so, is the session id in a valid format  .   
if so, is it a valid session.
	no session id ?  then i need a session new.  can i crete a new  
session ?  yes ? awesome.  no ? log an error and do something for  
unsupported sessions ( ie , send a notifier to the daemon that will  
email me if it gets more  than 10 of those in an hour and regardless-  
redirect the user to a "system error" page )

anyways, you shouldn't be writing new code for 1.3.x  unless you're  
stuck supporting a legacy app.

// Jonathan Vanasco

| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
- - - - - - - - - - - - - - - - - - -
| SyndiClick.com
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
- - - - - - - - - - - - - - - - - - -
|      FindMeOn.com - The cure for Multiple Web Personality Disorder
|      Web Identity Management and 3D Social Networking
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
- - - - - - - - - - - - - - - - - - -
|      RoadSound.com - Tools For Bands, Stuff For Fans
|      Collaborative Online Management And Syndication Tools
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
- - - - - - - - - - - - - - - - - - -