Subject: | Does not detect *all* WAIT locks in DB-Locks_0_4 |
- Platform: Solaris 5.8
- DB: Berkeley DB 4.2 with BerkeleyDB module 0.26
- Distribution Name: BerkeleyDB-Locks_0_4
I was hoping to use BerkeleyDB-Locks_0_4 in my implementation where there are multiple processes (Apache) using a BerkeleyDB. Every once in a while, when a process dies, it leaves behind a WAIT lock. However, this Locks package does not remove *all* WAIT locks. In some situations I can clearly see that there are locks (using the "db_stat -Co -h /tmp/bdb" command which displays locks in WAIT status) but this package does not see anything as being locked (neither the poll() nor the monitor() methods).
To reproduce this issue, I am attaching a test case (test4.pl) that is based mostly on the test.pl testcase that is distributed with the package. Basically, is is the same as test.pl except that the writer is focibly killed (kill -9) after it creates the write lock. This causes a WRITE lock to be left in WAIT state.
4 WRITE 1 WAIT /tmp/bdb/dbmfile.bdb page 1
This lock is killed by the parent process which repeatedly loops calling poll().
However, now the WRITE stays in PENDING state (since the process has been killed) and the reader goes into WAIT state (waiting for the write to finish).
4 WRITE 1 PENDING /tmp/bdb/dbmfile.bdb page 1
2 READ 1 WAIT /tmp/bdb/dbmfile.bdb page 1
So, there is a READ lock created in WAIT state and this READ is completely ignored by BerekeleyDB-Locks.
I really like this package and would like to use it. I would greatly appreciate it if someone could fix this issue or perhaps direct me on how to fix it.
Thanks!
use BerkeleyDB;
use BerkeleyDB::Locks;
use strict ;
my $flag1 = 'ok';
my $flag2 = 'ok';
my $env = new BerkeleyDB::Env
-Home => '/tmp/bdb',
-Flags => DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN;
if ( !fork ) {
my $env = new BerkeleyDB::Env
-Home => '/tmp/bdb',
-Flags => DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN;
## read lock2
my $db = tie my %db, 'BerkeleyDB::Hash',
-Env => $env,
-Flags => DB_CREATE,
-Filename => '/tmp/bdb/dbmfile.bdb',
;
local $SIG{ALRM} = sub { $flag2 = undef } ;
$db{test2} = 'failed' ;
#print STDERR "R2: db{test2} = " . $db{test2} . "\n";
print stderr "R2: Attempting read lock...\n" ;
my ( $k, $v ) ;
$k = "test2";
my $c = $db->db_cursor ;
$c->c_get( $k, $v, DB_FIRST ) ;
print STDERR "R2: Created lock\n";
alarm( 5 ) ;
while ( $flag2 ) {
sleep 1 ;
}
alarm( 0 ) ;
print STDERR "R2: Alarm - lock removed\n";
## don't know how to get this to display correctly...
print "R2: " . $db{test2} . "\n";
untie %db;
exit ;
}
my $writer2 = 0;
if ( !($writer2 = fork) ) {
my $env = new BerkeleyDB::Env
-Home => '/tmp/bdb',
#-Flags => DB_CREATE | DB_INIT_MPOOL | DB_INIT_CDB;
-Flags => DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN;
## write lock
my $db = tie my %db, 'BerkeleyDB::Hash',
-Env => $env,
-Flags => DB_CREATE,
-Filename => '/tmp/bdb/dbmfile.bdb',
;
sleep 1 ;
print STDERR "W2: attempting write lock...\n" ;
## this statement blocks
print STDERR "W2: db{test2} = " . $db{test2} . "\n";
$db{test2} = 'ok' ;
print STDERR "W2: db{test2} = " . $db{test2} . "\n";
untie %db;
exit;
}
sleep 1;
print STDERR "Killing writer2\n";
system("kill -9 $writer2");
sleep 2 ;
for (my $i = 0; $i < 10; $i++) {
print stderr " searching for locks...\n" ;
my $watch = new BerkeleyDB::Locks $env;
my @locks = $watch->poll();
if (scalar(@locks) > 0) {
print stderr sprintf " lock detected: %d\n", $locks[0] ;
#$db{test} = 100;
$watch->monitor() ;
## comment out the next line to force a test failure
push @locks, $watch->monitor() ;
#print $locks[0], $locks[2] ) ;
print stderr sprintf " lock released: %d\n", $locks[2] ;
}
sleep 2;
}
exit();