我一直在研究一些重复数据删除技术,这迫使我将文件系统用作哈希表。这导致使用几乎所有合理方法(例如,,,等)删除某些目录需要花费数小时rm -rf
的时间ls -f1 | xargs rm
。find -delete
在 Ext2/3/4 文件系统下,目录是一个包含从文件名到 inode 编号的哈希表的文件(在我的情况下,大约 60 MB!)据我了解,运行rm -rf
和朋友很慢,因为它遵循这种方法:
迭代目录文件中的哈希表。对于遇到的每个文件名-inode 对,原子地:
- 减少 inode 上的名称计数。
- 从哈希表中删除该条目。
(当文件/inode 的名称计数达到 0 并且没有打开文件描述符并指向这些 inode 的程序时,就会删除这些文件/inode。)
减少 inode 的名称计数很快。
删除文件(特别是小文件)也很快:只需在可用性表中将文件拥有的驱动器块指定为空闲即可。
据我所知,速度变慢是由于从哈希表中删除条目造成的。每次删除可能都有机会触发重新哈希,因为我观察到目录文件的大小随着文件被删除而减小。
我的要求有两个:
- 我的推理是否正确,是哈希表操作减慢了这个过程?
如果是,是否有一个工具可以执行以下操作(并且因此可能速度更快?)
- 减少目录文件中列出的每个 inode 的名称计数。
- 一次性删除整个目录的所有内容。
答案1
ext3/4 目录本身并不是哈希表。它实际上是一棵哈希树。也就是说,文件名被哈希化,哈希用作插入 b+ 树的索引。删除所有文件的最快方法是按 inode 编号对文件进行排序,因为这将最大限度地减少将 inode 从 inode 表拉入内存所需的磁盘寻道,以及在文件被释放时对 inode 表的更新。这还将倾向于按照文件的创建顺序删除文件,这将优化各种块和 inode 分配位图的更新方式。您可以做的另一件事是增加日志的大小(使用 tune2fs 删除日志,然后使用更大的日志大小重新创建它)。
最后,您应该记住,文件系统并未针对数据库进行优化。如果您想进行重复数据删除,您确实应该考虑使用数据库,而不是尝试使用 shell 脚本和使用目录作为快速而肮脏的数据库来破解它。正如您所发现的,这样做效果并不好……
答案2
删除整棵树是一项昂贵的操作,但有办法可以加快其速度。
您是否尝试过这个答案和这个答案?似乎是最快的,因为它优化了删除操作,而不是像、、...rsync
那样简单地遍历文件列表。rm
find
另外,你试过吗这选择?
编辑:
请注意:我还没有对这些命令进行过基准测试。
如果将来链接中断,我指的是命令:
rsync
前两个链接的命令:
mkdir blank
rsync -a --delete blank/ test/
第三个链接:“将它们移动到隐藏目录,然后在后台删除”:
mkdir ../.tmp_to_remove
mv -- * ../.tmp_to_remove
nohup rm -rf ../.tmp_to_remove &
正如该答案中所述,这种方法假设(即使删除非常昂贵)由于删除发生在另一棵树的后台,因此用户可能不关心实际成本。在我看来,只要您在删除操作发生之前不尝试关闭 bash/ssh 会话,情况就是如此。为了解决这个问题,我在命令nohup
中添加了rm
。
答案3
那么,miravalis 的答案中两种方法的组合怎么样?当你想“rm -rf deldir/*”时,请执行
mkdir .tmp1 .tmp2
mv deldir .tmp2/
nohup rsync -a --delete .tmp1/ .tmp2/ &
mkdir deldir