Как правильно получить доступ к BerkeleyDB с помощью Perl?

У меня возникли некоторые проблемы с использованием BerkeleyDB. У меня есть несколько экземпляров одного и того же кода, указывающего на один репозиторий файлов БД, и все работает нормально в течение 5-32 часов, а затем внезапно возникает тупик. Командные запросы останавливаются прямо перед выполнением вызова db_get или db_put или создания курсора. Так что я' m просто спрашивает, как правильно обрабатывать эти вызовы. Вот мой общий макет:

Вот как создаются среда и базы данных:

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

Как возникли эти тупиковые ситуации и как они были разрешены? (все части кода все еще работают). Что такое тупик в данном случае?

6
задан VolatileRig 1 May 2011 в 22:38
поделиться