Re: apache:session and mod perl

2005-01-03 Thread Perrin Harkins
On Fri, 2004-12-31 at 09:51 -0800, Chris Ochs wrote:
> A deadlock happens when you have an updater that acquires a write
> lock, but it's waiting for the first updater that is also in a SELECT
> FOR UPDATE but has not yet acquired a write lock.

There is no such thing as a write lock for the Postgres subclass.  It
grabs a lock when you materialize the session and doesn't give it up or
try to get another one until the session object is DESTROYed.

> The first updater
> can't finish because it can't acquire a write lock that the second
> updater has already obtained, and the second updater can't update
> until the first one finishes, which it can't.

Only one can get a lock on a particular session at once, which is by
design.  There is no deadlock though, since only a single lock is
involved here.

> A workable hack would probably be to have Apache::Session::Lock::File
> always set Transaction to 1 if the backend store was postgres.

You *really* should not need Apache::Session::Lock::File with Postgres
if you are not doing anything crazy with Postgres isolation levels and
transactions.  I regret bringing it up now.  You need to back up and
figure out what's going wrong with your Postgres stuff.  Are you doing
commits on this same database handle that would cause the lock to be
released too early?

Going back to an earlier mail:
> If it is a scoping issue it's probably in one of the Apache::Session
> modules

I think someone would have found that by now.

> The session is kept in a
> global request object I use for all variables that need to be passed
> around.  In the cleanup handler I untie the session and undefined the
> request object, and log it all with log4perl.

That should work, but no other request will be able to read the same
session until your cleanup handler has run.

> I just figured that File locking wasn't supported or tested
> with the Postgresql backend store

It's not.

> > I put some loggin into apache::session::lock::file, and then switched
> > between using apache::session::file and apache::session::flex with
> > postgres and Lock set to File.

Can you try it with just Postgres?

- Perrin



-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Re: apache:session and mod perl

2004-12-31 Thread Chris Ochs
I know what's happening now, it dawned on me after I wrote this last night.  

A deadlock happens when you have an updater that acquires a write
lock, but it's waiting for the first updater that is also in a SELECT
FOR UPDATE but has not yet acquired a write lock.  The first updater
can't finish because it can't acquire a write lock that the second
updater has already obtained, and the second updater can't update
until the first one finishes, which it can't.

Which also explains why Apache::Session::Flex doesn't list File as one
of the supported Lock options.

A workable hack would probably be to have Apache::Session::Lock::File
always set Transaction to 1 if the backend store was postgres.

Chris


On Thu, 30 Dec 2004 23:41:16 -0800, Chris Ochs <[EMAIL PROTECTED]> wrote:
> > > I tried setting Lock to File instead of Null, but there is some sort
> > > of contention issue because after the first request all other requests
> > > hang like they are waiting for a lock to be release.
> >
> > This usually means you have a scoping bug in your code.  If the session
> > object never goes out of scope, it will not release the lock.
> 
> I put some loggin into apache::session::lock::file, and then switched
> between using apache::session::file and apache::session::flex with
> postgres and Lock set to File.
> With postgres it calls acquire_read lock a bunch of times in a row
> with an acquire_write_lock thrown in and then something blocks.  Using
> apache::session::file it alternates correctly and doesn't do that.
> There has to be some logic in apache::session that is different than
> apache::session::file.
> 
> Here is a log when using apache::session::file.  I put the pid in front.
> 
> 96836 acquire_read_lock
> 96836 acquire_write_lock
> 96836 release_all_lock
> 96836 DESTROY
> 96836 release_all_lock
> 96822 acquire_read_lock
> 96822 acquire_write_lock
> 96822 release_all_lock
> 96822 DESTROY
> 96822 release_all_lock
> 96836 acquire_read_lock
> 96836 acquire_write_lock
> 96836 release_all_lock
> 96836 DESTROY
> 96836 release_all_lock
> 
> Here is a log using flex with postgres and Lock set to File.
> 96824 acquire_read_lock
> 96834 acquire_read_lock
> 96826 acquire_read_lock
> 96824 acquire_write_lock
> 96822 acquire_read_lock
> 
> I'm not sure exactly what pages were being called in the log snippets
> above, but this pattern is always the same.
> 
> Chris
>

-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Re: apache:session and mod perl

2004-12-30 Thread Chris Ochs
> > I tried setting Lock to File instead of Null, but there is some sort
> > of contention issue because after the first request all other requests
> > hang like they are waiting for a lock to be release.
> 
> This usually means you have a scoping bug in your code.  If the session
> object never goes out of scope, it will not release the lock.

I put some loggin into apache::session::lock::file, and then switched
between using apache::session::file and apache::session::flex with
postgres and Lock set to File.
With postgres it calls acquire_read lock a bunch of times in a row
with an acquire_write_lock thrown in and then something blocks.  Using
apache::session::file it alternates correctly and doesn't do that. 
There has to be some logic in apache::session that is different than
apache::session::file.

Here is a log when using apache::session::file.  I put the pid in front.

96836 acquire_read_lock
96836 acquire_write_lock
96836 release_all_lock
96836 DESTROY
96836 release_all_lock
96822 acquire_read_lock
96822 acquire_write_lock
96822 release_all_lock
96822 DESTROY
96822 release_all_lock
96836 acquire_read_lock
96836 acquire_write_lock
96836 release_all_lock
96836 DESTROY
96836 release_all_lock

Here is a log using flex with postgres and Lock set to File.
96824 acquire_read_lock
96834 acquire_read_lock
96826 acquire_read_lock
96824 acquire_write_lock
96822 acquire_read_lock


I'm not sure exactly what pages were being called in the log snippets
above, but this pattern is always the same.

Chris

-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Re: apache:session and mod perl

2004-12-30 Thread Chris Ochs
> 
> > I tried setting Lock to File instead of Null, but there is some sort
> > of contention issue because after the first request all other requests
> > hang like they are waiting for a lock to be release.
> 
> This usually means you have a scoping bug in your code.  If the session
> object never goes out of scope, it will not release the lock.
> 
If it is a scoping issue it's probably in one of the Apache::Session
modules, or maybe I'm not supplying all the necessary parameters when
using File locking with Postgresql.  Literally all I did is change
Lock to File instead of Null and that's it.  The session is kept in a
global request object I use for all variables that need to be passed
around.  In the cleanup handler I untie the session and undefined the
request object, and log it all with log4perl.  If there were scoping
issues with the global request object, it would show up all over the
place.  I just figured that File locking wasn't supported or tested
with the Postgresql backend store, so I didn't spend any more time on
it.


> Yes, you should not need anything more than the Postgres locking.
> 
> > I use the default isolation in postgresql.
> 
> Then it really should be shielding you from this problem.  Make sure your
> scoping is correct (you could throw a warn into the A::S DESTROY() sub to
> make sure it is getting called) and make sure you are issuing a commit
> somewhere in there to save your changes.

SELECT FOR UPDATE doesn't block reads.

I put in the File backend store with the Transaction argument and it
puts an exclusive lock on reads, which makes everything work as I
wanted it to.  Now I will go back and look closer at Apache::Session
and see if the File locking is supported for the Postgresql store.

Chris

-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Re: apache:session and mod perl

2004-12-30 Thread Perrin Harkins
Chris Ochs said:
> I have found three things that need to be worked around like this in
> order to use this approach.  One is frames like you said, the other is
> not pulling in stylesheets via an href, and the other is making sure
> images are not loaded through mod perl.   If I do all of that I don't
> have any problems.  I still don't like it, but it might be our only
> option.

It's not your only option, but you really don't want to be pulling in
sessions for things like CSS and images, or serving them through mod_perl.

> I tried setting Lock to File instead of Null, but there is some sort
> of contention issue because after the first request all other requests
> hang like they are waiting for a lock to be release.

This usually means you have a scoping bug in your code.  If the session
object never goes out of scope, it will not release the lock.

> Also, I found out through further testing that Apache::Session doesn't
> do exclusive locking on read, only write.

Apache::Session::Store::Postgres uses an exclusive lock via SELECT FOR
UPDATE, and it grabs the lock when you load the session.  Other subclasses
behave differently.  I don't believe the "Transaction" option has any
effect on the Postgres subclass.

> And that also
> means that there isn't any need for additional locking with postgresql
> because using SELECT FOR UPDATE basically does the same thing as the
> file locking.

Yes, you should not need anything more than the Postgres locking.

> I use the default isolation in postgresql.

Then it really should be shielding you from this problem.  Make sure your
scoping is correct (you could throw a warn into the A::S DESTROY() sub to
make sure it is getting called) and make sure you are issuing a commit
somewhere in there to save your changes.

- Perrin


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Re: apache:session and mod perl

2004-12-30 Thread Chris Ochs
> So you have a lost update problem.  There is probably a way to structure
> things to avoid this (maybe not using sessions for it), but some form of
> mutually exclusive locking would fix it, at the expense of making your
> site slower, since each frame will have to wait for its turn.  You might
> try to make your code avoid loading sessions in frames where they are not
> absolutely needed.

I have found three things that need to be worked around like this in
order to use this approach.  One is frames like you said, the other is
not pulling in stylesheets via an href, and the other is making sure
images are not loaded through mod perl.   If I do all of that I don't
have any problems.  I still don't like it, but it might be our only
option.


> The thing that makes the difference here is really the locking module.
> Take a look at the code inside Apache::Session::Postgres.  It uses the
> Null locking module because Postgres is supposed to handle the locking.
> You could have it use the locking from the file-based or MySQL-based
> sessions if you wanted to.  Apache::Session::Flex makes this easy to
> specify.

I tried setting Lock to File instead of Null, but there is some sort
of contention issue because after the first request all other requests
hang like they are waiting for a lock to be release.  I did preload
Apache::Session:Lock::File.

Also, I found out through further testing that Apache::Session doesn't
do exclusive locking on read, only write.  Which is what I would
expect actually after thinking about it for a minute.  And that also
means that there isn't any need for additional locking with postgresql
because using SELECT FOR UPDATE basically does the same thing as the
file locking.

> You're allowing dirty reads?  That's not the normal isolation level for
> Postgres.  That is likely the source of your problems.  Can you change
> that to the default level, or is there something else that will break?
> 

No, my mistake I was using the wrong terminology.  I use the default
isolation in postgresql.

-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Re: apache:session and mod perl

2004-12-30 Thread Perrin Harkins
Chris Ochs said:
> The issue I am having is that the postgresql store doesn't do any
> locking

It should.  It uses "SELECT FOR UPDATE" which grabs an exclusive lock on
the row in question until a commit is issued.  A::S doesn't issue the
commit, so you have to do that yourself.  Have you been messing with
isolation levels in a way that would defeat the SELECT FOR UPDATE read
lock?

> What is happening is when a page that is loaded loads other pages
> (such as a frameset), sometimes the request for the first page doesn't
> finish before the other requests have already read the session data.

This can be a problem with multiple browser windows, fast reloads, etc. 
Even without frames, you always have to expect concurrent access.

> It goes like this.
>
> - Request 1 fetches session
> - Request 2 fetches session
> - Request 1 changes some session information
> - Request 1 writes out session info
> - Request 2 writes out session info
>
> In our case a flag stating whether a user is logged in or not is
> stored in the session.  If Request 1 logs out a user, Request 2 flags
> the user as logged in again when it writes out the session data.

So you have a lost update problem.  There is probably a way to structure
things to avoid this (maybe not using sessions for it), but some form of
mutually exclusive locking would fix it, at the expense of making your
site slower, since each frame will have to wait for its turn.  You might
try to make your code avoid loading sessions in frames where they are not
absolutely needed.

> Solutions I have thought of so far include..
>
> 1. Switch back to file based sessions, not what I want.

The thing that makes the difference here is really the locking module. 
Take a look at the code inside Apache::Session::Postgres.  It uses the
Null locking module because Postgres is supposed to handle the locking. 
You could have it use the locking from the file-based or MySQL-based
sessions if you wanted to.  Apache::Session::Flex makes this easy to
specify.

> 2. Keep a separate pool of cached connections just for the session
> database, and have those connections use a transaction isolation level
> that guarantees no dirty reads.

You're allowing dirty reads?  That's not the normal isolation level for
Postgres.  That is likely the source of your problems.  Can you change
that to the default level, or is there something else that will break?

- Perrin


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Re: apache:session and mod perl

2004-12-30 Thread Chris Ochs
On Thu, 30 Dec 2004 10:00:32 +0200, Octavian Rasnita <[EMAIL PROTECTED]> wrote:
> If this happens only in pages with frames, try creating a page without
> frames.

Umm no, I want a solution not a work around.  This application is used
by a lot of people on a lot of different sites with the file backend
store.  I'll go back to that if I have to.

-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html



Re: apache:session and mod perl

2004-12-29 Thread Octavian Rasnita
If this happens only in pages with frames, try creating a page without
frames.

Teddy

- Original Message - 
From: "Chris Ochs" <[EMAIL PROTECTED]>
To: 
Sent: Thursday, December 30, 2004 9:42 AM
Subject: apache:session and mod perl


This question could go to one of several different lists, but I
thought this might be a good place to start.

I have an application based on mod perl and the Template Toolkit.  For
session tracking I am using Apache::Session with the postgresql
backend store.

The issue I am having is that the postgresql store doesn't do any
locking, which is causing some requests to read bad data, but I really
want to keep the database as the backend store because it will scale a
lot better if we need to have multiple servers access the same session
data.

What is happening is when a page that is loaded loads other pages
(such as a frameset), sometimes the request for the first page doesn't


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html