Skip Menu |

This queue is for tickets about the Apache-Session CPAN distribution.

Report information
The Basics
Id: 7072
Status: resolved
Priority: 0/
Queue: Apache-Session

People
Owner: CHORNY [...] cpan.org
Requestors: sink [...] limey.net
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 1.6
Fixed in: 1.82_03



Subject: Apache::Session::Lock::Flock unlocks transactional sessions!
On Solaris and Linux (and probably everywhere with flock) getting a Read lock when a Write lock is being held downgrades the write lock to a read lock. Apache::Session gets a write lock when it ties the session hash (if the Transaction option is used) then when the restore happens it unconditionally acquires a read lock. This downgrades the lock and basically removes the transaction-ness... My handler differentiates page requests to the main pages that change the state from page requests to ancillary objects (images, incudes, etc.). The main pages get the state with Transaction set (to block subsequent requests) and the ancillary requests don't. However all requests (used to) update the session object with the last access time so we can time out stale sessions and force re-authentication. So imagine this scenario with requests W and R to the same session: 1 Request W which will change the session state 2 W ties the session with Transaction set 3 W gets the session starts processing 4 Request R comes in which won't write anything important to state 5 R ties the session without Transaction set 6 R gets the session and starts processing 7 W finishes processing and writes out 8 R finishes processing and writes out Now the final state will not reflect W's changes! This is not a hypothetical scenario, it has been happening to us. It was tough one to track down.
[BBENNETT - Fri Jul 23 09:52:15 2004]: Show quoted text
> This is not a hypothetical scenario, it has been happening to us. It > was tough one to track down.
Just to chime in, exactly the same thing happened to me yesterday. It took most of the day to figure out what was happening. I wish I'd seen this bug beforehand. :) As to how to fix it, I'm not entirely sure. I think that the problem seems to arise from the fact that in read locks and write locks have no bearing on each other. Perhaps the locking semantics need altering such that a write lock is considered a superset of a read lock, so that if you ask for a write lock and a read lock is already present, then the request is ignored. Attached is a patch that implements this. It passes all the tests, but I'm not 100% sure it's the right way to do things, because it changes the locking semantics relative to other locking modules. If you like the patch, I'll attempt to knock up some tests for it. :)
diff -ruN Apache-Session-1.70_01.orig/Session/Lock/File.pm Apache-Session-1.70_01/Session/Lock/File.pm --- Apache-Session-1.70_01.orig/Session/Lock/File.pm Tue Feb 24 19:27:20 2004 +++ Apache-Session-1.70_01/Session/Lock/File.pm Sat Sep 11 16:13:19 2004 @@ -29,7 +29,7 @@ my $self = shift; my $session = shift; - return if $self->{read}; + return if $self->{read} || $self->{write}; if (!$self->{opened}) { my $fh = Symbol::gensym(); @@ -67,40 +67,13 @@ flock($self->{fh}, LOCK_EX); $self->{write} = 1; + $self->{read} = 1; } -sub release_read_lock { - my $self = shift; - my $session = shift; - - die unless $self->{read}; - - if (!$self->{write}) { - flock($self->{fh}, LOCK_UN); - close $self->{fh} || die $!; - $self->{opened} = 0; - } - - $self->{read} = 0; -} - -sub release_write_lock { - my $self = shift; - my $session = shift; - - die unless $self->{write}; - - if ($self->{read}) { - flock($self->{fh}, LOCK_SH); - } - else { - flock($self->{fh}, LOCK_UN); - close $self->{fh} || die $!; - $self->{opened} = 0; - } - - $self->{write} = 0; -} +# flock(2) doesn't support holding a read and write lock simultaneously, +# so there is no need for individual functions. +*release_read_lock = \&release_all_locks; +*release_write_lock = \&release_all_locks; sub release_all_locks { my $self = shift; @@ -185,6 +158,21 @@ =head1 NOTES +=over 4 + +=item * + +Acquiring a read lock whilst a write lock is held will do nothing. +Acquiring a write lock whilst a read lock is held will upgrade from a +read lock to a write lock. + +=item * + +There is no difference between releasing a read lock and releasing a +write lock, since flock(2) cannot support both at once. + +=item * + This module does not unlink temporary files, because it interferes with proper locking. THis can cause problems on certain systems (Linux) whose file systems (ext2) do not perform well with lots of files in one directory. To prevent this @@ -196,6 +184,8 @@ my $l = new Apache::Session::Lock::File; $l->clean('/var/lock/sessions', 3600) #remove files older than 1 hour + +=back =head1 AUTHOR
RT-Send-CC: SEMANTICO [...] cpan.org
Canged -- Alexandr Ciornii, http://chorny.net
RT-Send-CC: SEMANTICO [...] cpan.org
Now will not relock if write lock is on. Fixed in 1.82_03. -- Alexandr Ciornii, http://chorny.net