关于算法:为什么删除文件以便更快地删除它们很重要?

Why is it important to delete files in-order to remove them faster?

一段时间前,我了解到rsync删除文件的速度比许多其他工具快得多。

几天前,我在serverfault上看到了这个很好的答案,这解释了为什么rsync非常擅长删除文件。

从该答案中引用:

I revisited this today, because most filesystems store their directory
structures in a btree format, the order of which you delete files is
also important. One needs to avoid rebalancing the btree when you
perform the unlink. As such I added a sort before deletes occur.

您能解释一下删除文件是如何防止或减少btree重新平衡的数量的吗?

i expect the answer to show how deleting in order increase deletion speed,with details of what happens at btreelevel.编写rsync和其他程序(参见问题中的链接)的人使用这些知识创建更好的程序。我认为,对于其他程序员来说,能够更好地编写软件是很重要的。


这不重要,也不是B-树问题。这只是个巧合。

首先,这是非常依赖于实现的,并且非常依赖于ext3。这就是为什么我说它不重要(一般使用)。否则,请放置ext3标记或编辑摘要行。

其次,ext3不使用b-tree作为目录条目索引。它使用HtRead。htree类似于b-tree,但不同,不需要平衡。在fs/ext3/dir.c中搜索"htree"。

由于基于htree的索引,a)ext3的查找速度比ext2快,但b)readdir()按哈希值顺序返回条目。相对于文件创建时间或数据的物理布局,哈希值顺序是随机的。众所周知,随机访问要比旋转媒体上的顺序访问慢得多。

曹明明等于2005年为OLS发表的一篇关于ext3的论文。建议(强调我的):

to sort the directory entries returned by readdir() by inode number.

现在,转到rsync。rsync按文件名对文件进行排序。请参见flist.c::fsort()、flist.c::file_compare()和flist.c::f_name_cmp()。

我没有测试以下假设,因为我没有@mife得到43秒的数据集。但我认为,与readdir()返回的随机顺序相比,按名称排序更接近于最佳顺序。这就是为什么您在ext3上看到rsync更快的结果。如果用随机文件名生成1000000个文件,然后用rsync删除它们,会怎么样?你看到同样的结果了吗?


让我们假设您发布的答案是正确的,并且给定的文件系统确实将内容存储在平衡树中。平衡一棵树是一项非常昂贵的操作。保持树的"部分"平衡非常简单,因为当您允许树稍微不平衡时,您只需要担心在插入/删除点周围移动东西。然而,当讨论完全平衡的树时,当你移除一个给定的节点时,你可能会突然发现,这个节点的子节点可能属于树的完全相反的一侧,或者相反一侧的子节点已经成为根节点,它的所有子节点都需要向树上旋转。这要求您进行一系列的旋转,或者将所有项放入一个数组中,然后重新创建树。

1
2
3
            5
    3               7
2       4       6       8

现在把7取下来,简单点,对吗?

1
2
3
            5
    3               8
2       4       6

现在取下6,仍然很容易,是吗…?

1
2
3
            5
    3               8
2       4

现在移走8号,呃,哦

1
2
3
            5
    3              
2       4

使此树成为适当的平衡形式,如:

1
2
3
        4
    3       5
2

这是相当昂贵的,至少与我们所做的其他移除相比,并且随着我们树的深度的增加呈指数级恶化。在移除8之前,通过移除2和4,我们可以使这个过程更快(指数级)。尤其是如果我们的树有3层以上的深度。

不排序删除平均为O(k*log_i(n)^2)。n表示元素总数,k表示要删除的元素数,i表示允许给定节点的子节点数,log_i(n)表示深度,对于每个深度级别,我们四次增加操作数。

有一些排序帮助的删除平均为O(k*log_i(n)),但有时排序不能帮助您,您不得不删除一些需要重新平衡的内容。不过,最小化这是最佳的。

编辑:

另一种可能的树排序方案:

1
2
3
            8
    6               7  
1       2       3       4

在这种情况下完成最佳移除会更容易,因为我们可以利用我们对事物排序的知识。在任何一种情况下都是可能的,事实上两者都是相同的,在这一种情况下,逻辑只是稍微简单一点,因为对于给定的场景,排序更人性化。在任何一种情况下,顺序都被定义为"先删除最远的叶",在这种情况下,最远的叶也是最小的数字,这是一个我们可以利用的事实,使它更优化一点,但这一事实不一定是正确的文件系统示例(尽管它可能是)。


我不相信如果按顺序删除文件,B树重新平衡的数量会发生显著变化。不过,我相信,如果您这样做,对外部存储的不同搜索次数将显著减少。在任何时候,B-树中唯一需要访问的节点将是树的最右边界,而以随机顺序访问B-树中的每个叶块,每个文件的访问概率相同。


重新平衡B-树比B-树+实现便宜,这也是大多数文件系统和数据库索引实现使用它们的原因。

删除时有许多方法,这取决于删除方法在时间和重新平衡树的需要方面更有效。您还必须考虑节点的大小,因为节点可以存储的键数会影响重新平衡树的需要。一个大的节点大小只会对节点内的键重新排序,但是一个小的节点可能会多次使树重新平衡。

了解这一点的一个很好的资源是著名的CLR(ThomasCormen)书"算法导论"。


在托管大型目录的存储系统上,缓冲区缓存将处于压力之下,缓冲区可能会被回收。因此,如果删除的间隔是时间,那么在删除之间将btree放回核心缓存的磁盘读取次数可能很高。

如果对要删除的文件进行排序,则实际上是延迟了删除并将其聚在一起。这可能会产生副作用,即每个页面中的btree块会有更多的删除。如果有统计数据表明两个实验之间缓冲区缓存命中的是什么,那么就可以判断这个hypo是否是错误的。

但是,如果在删除期间缓冲区缓存没有压力,那么btree块可以留在核心中,那么我的假设是无效的。