【发布时间】:2014-06-18 11:38:05
【问题描述】:
问题
我正在使用 NetBSD 6.1、Perl v5.18.1 和 DB_File v1.818。如果我使用 each 遍历与 DB_File 相关的哈希并从哈希中删除每个项目,则并非所有项目都被删除。这是一个演示问题的脚本:
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{$_};
}
文档是怎么说的
我找不到任何明确说明通过each 迭代时删除并不总是有效的内容。
这是我能找到的:
-
如果 VAR 是一个并列变量或其他特殊变量,
foreach可能不会像您预期的那样。我不确定这是什么意思,但奇怪的是
foreach的情况是它确实起作用的地方。 -
任何插入到散列中的操作都可能改变顺序,任何删除操作都会改变,但
each或keys返回的最新键可以在不改变顺序的情况下被删除。对我来说,这意味着在迭代时
delete当前条目是安全的。 documentation for
DB_File在迭代时没有提到删除。
问题
是不是这个问题:
- 由NetBSD's Berkeley DB implementation 中的错误引起?
- 是由 DB_File 中的错误引起的?
-
each的已知限制? - 绑定哈希的已知限制?
- DB_File 绑定哈希的已知限制?
为什么键上的foreach 有效,而each 无效?
【问题讨论】:
-
“对我来说,这意味着在迭代时
delete当前条目是安全的。”对于哈希,是的。但是这里没有哈希。 Perl 的文档不能声明 DB_File 支持或不支持什么。 -
@ikegami:好的,这样就排除了“
each的已知限制”。对吗?