У меня были некоторые проблемы с использованием 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?
ОБНОВЛЕНИЕ : Точнее говоря, проблема возникает на сервере Windows 2003 (1,5 ГБ ОЗУ, не уверен, если это важно). Я могу запустить всю эту настройку на моем компьютере с Windows 7 (4 ГБ ОЗУ). Я также начал распечатывать статистику блокировки, используя следующее:
Добавление этого флага в среду создания:
-MsgFile => "$dbFolder/lockData.txt"
И затем вызывать это каждые 60 секунд:
my $status = $env->lock_stat_print();
print "Status:$status:\n";
Статус всегда возвращается как 0, что является успехом. Вот последний статистический отчет:
29 Last allocated locker ID
0x7fffffff Current maximum unused locker ID
5 Number of lock modes
1000 Maximum number of locks possible
1000 Maximum number of lockers possible
1000 Maximum number of lock objects possible
40 Number of lock object partitions
24 Number of current locks
42 Maximum number of locks at any one time
5 Maximum number of locks in any one bucket
0 Maximum number of locks stolen by for an empty partition
0 Maximum number of locks stolen for any one partition
29 Number of current lockers
29 Maximum number of lockers at any one time
6 Number of current lock objects
13 Maximum number of lock objects at any one time
1 Maximum number of lock objects in any one bucket
0 Maximum number of objects stolen by for an empty partition
0 Maximum number of objects stolen for any one partition
3121958 Total number of locks requested
3121926 Total number of locks released
0 Total number of locks upgraded
24 Total number of locks downgraded
9310 Lock requests not available due to conflicts, for which we waited
0 Lock requests not available due to conflicts, for which we did not wait
8 Number of deadlocks
1000000 Lock timeout value
0 Number of locks that have timed out
1000000 Transaction timeout value
0 Number of transactions that have timed out
792KB The size of the lock region
59 The number of partition locks that required waiting (0%)
46 The maximum number of times any partition lock was waited for (0%)
0 The number of object queue operations that required waiting (0%)
27 The number of locker allocations that required waiting (0%)
0 The number of region locks that required waiting (0%)
1 Maximum hash bucket length
Из которых я опасаюсь этого:
8 Number of deadlocks
Как возникли эти тупики и как они были устранены? (все части кода все еще работают). Что такое тупик, в данном случае?