我一直在使用BerkeleyDB有一些問題。我有相同代碼的多個實例指向單個數據庫文件存儲庫,並且一切運行良好5-32小時,然後突然間出現死鎖。在執行db_get或db_put或遊標創建調用之前,命令會提示停止。所以我只是要求正確的方式來處理這些電話。這裏是我的總體佈局:用Perl訪問BerkeleyDB的正確方法是什麼?
這是怎樣的環境和DB創建:
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";
這個代碼的單個實例運行,去一個網站,網址保存到另一個實例解析(我有的標誌設置,使得當一個被鎖定的每DB被鎖定):
$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',然後對其執行操作,然後將數據庫條目完全移到另一個數據庫中從無序刪除並存儲在另一個DB):
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:具體而言,該問題發生在Windows 2003服務器上(1.5 GB RAM,不知道這是很重要的)。我可以在Windows 7機器上運行這整個設置(4GB RAM)。我也開始使用印刷出來的鎖統計如下:
添加此標誌,以環境創造:
-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
怎麼會出現這些死鎖和他們怎麼解決的? (代碼的所有部分仍在運行)。在這種情況下究竟是一個死鎖?
對於Mutex的工作,特別是與伯克利有關的工作,我有點困惑,你能舉一個例子說明如何使用Mutex將項目放入數據庫?它如何防止其他進程訪問數據庫? – 2011-05-02 21:03:53
這是windows所具有的「事物」,機器上任何進程中的任何線程都可以嘗試鎖定。 wait()調用會阻塞,直到線程鎖定。然後,您將完成所有數據庫訪問,而不是我的sleep()調用。基本上,你做的是鎖定而不是BDB。嘗試運行上面的腳本的幾個進程,看看它是如何工作的。 – Alex 2011-05-02 23:35:00