我在使用 BerkeleyDB 时遇到了一些问题。我有相同代码的多个实例指向单个数据库文件存储库,并且一切正常运行 5-32 小时,然后突然出现死锁。命令提示符会在执行 db_get 或 db_put 或游标创建调用之前停止。所以我只是询问处理这些电话的正确方法。这是我的总体布局:
这是环境和数据库的创建方式:
my $env = new BerkeleyDB::Env (
-Home => "$dbFolder\\" ,
-Flags => DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL)
or die "cannot open environment: $BerkeleyDB::Error\n";
my $unsortedHash = BerkeleyDB::Hash->new (
-Filename => "$dbFolder/Unsorted.db",
-Flags => DB_CREATE,
-Env => $env
) or die "couldn't create: $!, $BerkeleyDB::Error.\n";
此代码的单个实例运行,转到站点并保存要由另一个实例解析的 URL(我设置了标志,以便在锁定一个数据库时每个数据库都被锁定):
$lk = $unsortedHash->cds_lock();
while(@urlsToAdd){
my $currUrl = shift @urlsToAdd;
$unsortedHash->db_put($currUrl, '0');
}
$lk->cds_unlock();
它定期检查是否有一定数量的项目处于未排序状态:
$refer = $unsortedHash->db_stat();
$elements = $refer->{'hash_ndata'};
在将任何元素添加到任何数据库之前,它首先检查所有数据库以查看该元素是否已经存在:
if ($unsortedHash->db_get($search, $value) == 0){
$value = "1:$value";
}elsif ($badHash->db_get($search, $value) == 0){
$value = "2:$value";
....
下一个代码紧随其后,它的许多实例都是并行运行的。首先,它获取未排序的下一个项目(没有繁忙值“1”),然后将该值设置为繁忙“1”,然后对其执行某些操作,然后将数据库条目完全移动到另一个数据库(它是从未排序中删除并存储在另一个数据库中):
my $pageUrl = '';
my $busy = '1';
my $curs;
my $lk = $unsortedHash->cds_lock(); #lock, change status to 1, unlock
########## GET AN ELEMENT FROM THE UNSORTED HASH #######
while(1){
$busy = '1';
$curs = $unsortedHash->db_cursor();
while ($busy){
$curs->c_get($pageUrl, $busy, DB_NEXT);
print "$pageUrl:$busy:\n";
if ($pageUrl eq ''){
$busy = 0;
}
}
$curs->c_close();
$curs = undef;
if ($pageUrl eq ''){
print "Database empty. Sleeping...\n";
$lk->cds_unlock();
sleep(30);
$lk = $unsortedHash->cds_lock();
}else{
last;
}
}
####### MAKE THE ELEMENT 'BUSY' AND DOWNLOAD IT
$unsortedHash->db_put($pageUrl, '1');
$lk->cds_unlock();
$lk = undef;
在其他所有地方,如果我在任何数据库上调用 db_put 或 db_del,它都会被锁包裹起来,如下所示:
print "\n\nBad.\n\n";
$lk = $badHash->cds_lock();
$badHash->db_put($pageUrl, '0');
$unsortedHash->db_del($pageUrl);
$lk->cds_unlock();
$lk = undef;
但是,我的 db_get 命令是自由浮动的,没有锁,因为我认为读取不需要锁。
我已经检查了这段代码一百万次,算法是无懈可击的。所以我只是想知道我是否执行了错误的任何部分,使用了错误的锁等等。或者是否有更好的方法来防止 BerkeleyDB 和 Strawberry Perl 发生死锁(甚至诊断死锁)?
UPDATE