perl-embperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From RobertCZ <>
Subject Re: mdat/postgres - major perfomance problem?
Date Sat, 24 Jul 2004 08:00:30 GMT
Angus Lees wrote:

>At Tue, 13 Jul 2004 12:30:42 +0200, RobertCZ  wrote:
>>Gerald Richter wrote:
>>>> I tried to play with it and it seems that Postgres as a store does
>>>>To me it looks like only one Apache child is working and other are
>>>>just waiting for session commit.
>>>Mmmh, yes this seems to be the case.
>>>I am not sure how select for update works, for the other storages the
>>>locking works the way, that multiple pages can read at the same time, only
>>>if one page writes it tries to get an exclusive lock. So just do write only
>>>at the end of the page, normaly solves this locking problem.
>If thats what every other storage does, then every other storage has a
>pretty severe race condition.  This is fine if the data you are
>storing in %mdat (or %udat) isn't dependent on what the previous %mdat
>data was (eg: storing "the last visitor" is ok, a page counter is not ok).
>The problem is that perl cannot know when fetching the session data,
>whether you are intending to modify it or not.  It seems the Postgres
>backend is taking the conservative approach, unlike every other
>Apache::Session store (and against the behaviour described in the
>Apache::Session docs).

Well, Apache::Session docs say:

> If you retrieve an existing session, Session immediately restores the 
> object from storage [....] also obtains an non-exclusive lock on the 
> session.


> By default, most Apache::Session implementations only do locking to 
> prevent data corruption. The locking scheme does not provide 
> transactional consistency, such as you might get from a relational 
> database. If you desire transactional consistency, you must provide 
> the Transaction argument with a true value when you tie the session 
> hash. For example:
> tie %s, 'Apache::Session::File', $id {
>    Directory     => '/tmp/sessions',
>    LockDirectory => '/var/lock/sessions',
>    Transaction   => 1
> };
> Note that the Transaction argument has no practical effect on the 
> MySQL and Postgres implementations. The MySQL implementation only 
> supports exclusive locking, and the Postgres implementation uses the 
> transaction features of that database.

I believe that using simple read locks is plain stupid for %mdat because 
it works in most simple cases only, eg your 'last-visitor' example. Even 
in %udat you can get quite easy two childs writing to the same session, 
it is enough if user just clicks faster then backend processes requests 
(think of page with frames or long processing or SOAP etc). And when 
some updates are lost and the last child wins, your application is f* up.

I propose

- use write lock for %udat and %mdat as DEFAULT ( Transaction => 1 ) and 
saying that very loudly in the docs
- reverse %mdat back to the per-module behaviour or remove it completely
- maybe add %adat for application data that would be just a simple alias 
to some per-app global hash (and warn %adat will not survive apache 
restart, unlike udat/mdat)


>>>>PS. When I try to empty %mdat, maybe in base.html like
>>>>   delete $mdat{$_} foreach keys %mdat;
>>>>   %mdat = ();
>>>>it dumps empty session as expected. Now I comment out those delete
>>>>lines and reload and %mdat has the same content as before delete.
>>>>What's wrong?
>Deleting all keys like this also deletes _session_id.  Its very silly,
>but it seems the only place Apache::Session stores the session_id is
>actually in $self->{data}->{_session_id}.
>In lieu of anyone actually fixing this Apache::Session stupidity - you
>will have to do something like this instead:
>  [-  delete $mdat{$_} foreach grep !/^_/, keys %mdat  -]

Ups. I should have thought of this... :-( Thanks, Angus.

View raw message