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
> >>SELECT ... FOR UPDATE,
> >>
> >>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).

Removing the "FOR UPDATE" phrase from Apache/Session/Store/Postgres.pm
should make Postgres behave in the same way as other stores - with the
same race.  Btw I notice that the Oracle store also uses FOR UPDATE.

(SELECT ... FOR UPDATE takes a write lock on the selected rows until
the end of the current transaction)

> [...] postgres indeed does wait for first select for update to
> finnish - however only if it's in explicit transaction so one has to
> call BEGIN before and be in the AutoCommit => 0 mode

Yes, AutoCommit => 1 makes "the end of the current transaction" occur
immediately, dropping the FOR UPDATE locks after the SELECT is completed.

> I'd love to use %mdat for all kind of neat trick namely for inter-user 
> sql query caching, inter-user application locking (so 2 users don't edit 
> the same record on the same web form etc), maybe track currectly 
> connected users etcetcetc but this locking thing has to be fixed

For some of these cases (particularly caching), I think %mdat is the
wrong place to store them.  IMO, you're better off simply storing them
as perl "globals" in a perl namespace of your choosing - no locking,
no contention, no delay in retrieval.  For things like prepared DBI
statement handles, these can't be stored outside the perl process (in
%mdat) anyway.

> I guess only real way to fix this problem is patch Apache::Session and 
> Embperl to support read-only sessions, but that would be quit a lot of 
> patching.

Perhaps we could just reduce the impact by having a "per file data"
hash again?  Then contention would only occur if multiple requests
used the same embperl file, rather than every request for the same
application.

> >>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  -]

-- 
 - Gus

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to