[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