問題
NetBSD 6.1、Perl v5.18.1、および DB_File v1.818 を使用しています。を使用して DB_File-tied ハッシュを反復処理し、each
ハッシュから各アイテムを削除すると、すべてのアイテムが削除されるわけではありません。問題を示すスクリプトを次に示します。
use strict;
use warnings;
use DB_File;
my $dbfile = "/tmp/foo.db";
! -f $dbfile or unlink($dbfile) or die("unable to delete $dbfile");
my %db;
tie(%db, "DB_File", "/tmp/foo.db", O_RDWR|O_CREAT, 0644);
# add some random records
my @chars = ("0".."9", "a".."f");
for (1..10) {
my ($key, $val);
$key .= $chars[rand(@chars)] for 1..10;
$val .= $chars[rand(@chars)] for 1..32;
$db{$key} = $val;
}
# this doesn't delete everything from the database!
keys(%db); # reset the iterator
while (my ($key, $val) = each(%db)) {
delete $db{$key};
}
foreach (keys(%db)) {
print("\$db{$_} = $db{$_}\n");
}
untie(%db);
実行すると、10 件のレコードのうち 4 件 (場合によっては 5 件) が削除されません。
$db{4a8e5792e0} = 7a4d078a3f0f3cba750cb395fcc3343d
$db{d28e8cb226} = 17af1122f0b94113416693b1c4165954
$db{a3ae4e2e24} = 3c15270cf16601722bd8106b1727dbc2
$db{886c469eb4} = f1496f83f7866d09c9e28aae8e1b62e6
$db{2c53ebd993} = facfe8228240878aac825de4d97ca22b
Linux (Ubuntu 14.04) システムでスクリプトを実行すると、常に機能します (すべてのレコードが削除されます)。
キーのループに切り替えると、foreach
NetBSD と Linux の両方で機能します。
# this always works
foreach (keys(%db)) {
delete $db{$_};
}
ドキュメントの内容
via の反復中に削除することが常に機能するとは限らないことを明確に示しているものを見つけることができeach
ませんでした。
これが私が見つけたものです:
のドキュメントに
foreach
は次のように書かれています:foreach
VAR が同順位またはその他の特殊な変数である場合、期待どおりの結果が得られない可能性があります。これが何を意味するのかはわかりませんが、奇妙なことに、それが機能する場合
foreach
です。のドキュメントに
each
は次のように書かれています:ハッシュへの挿入は、削除と同様に順序
each
をkeys
変更する可能性があります。私にとって、これ
delete
は、反復中に現在のエントリに対して安全であることを意味します。のドキュメントに
DB_File
は、反復中の削除については言及されていません。
質問
この問題はありますか:
- NetBSD の Berkeley DB 実装のバグが原因ですか?
- DB_File のバグが原因ですか?
- の既知の制限
each
? - 結合されたハッシュの既知の制限?
- DB_File 結合ハッシュの既知の制限?
foreach
キーが機能each
しないのに機能するのはなぜですか?