8

我有一个包含十亿个文件的外部磁盘。如果我将外部磁盘安装在计算机 A 中,我的程序将扫描所有文件的路径并将文件的路径保存在数据库表中。之后,当我弹出外部磁盘时,这些数据仍将保留在表中。问题是,如果B机中的一些文件被删除了,我又把它挂载到A机上,我必须同步A机的数据库表。但是,我不想再扫描所有文件,因为它需要很多时间,浪费很多内存。有没有办法在不扫描所有文件的情况下更新数据库表,同时最大限度地减少使用的内存?

此外,就我而言,内存限制比时间更重要。这意味着我宁愿节省更多内存而不是节省更多时间。

我想我可以将文件切割成很多部分并使用一些特定的功能(可能是SHA1?)来检查该部分中的文件是否被删除。但是,我找不到将文件剪切到各个部分的方法。任何人都可以帮助我或给我更好的想法吗?

4

4 回答 4

1

如果您无法控制磁盘上的文件系统,您别无选择,只能扫描整个磁盘上的文件名。要列出已删除的文件,您可以执行以下操作:

update files in database: set "seen on this scan" to false
for each file on disk do:
    insert/update database, setting "seen on this scan" to true
done
deleted files = select from files where "seen on this scan" = false

数据库性能问题的解决方案可能是将文件名累积到某种列表中,并在达到 1000 个文件时进行批量插入/更新。

至于拥有 10 亿个文件的目录,您只需将列出文件的代码替换为包含 C 函数opendirreaddir. 如果我是你现在就不会太担心了。没有一个理智的人在一个目录中拥有 10 亿个文件,因为这种事情会削弱文件系统和常用的操作系统工具,因此风险很低,解决方案也很简单。

于 2012-05-21T07:28:48.470 回答
0

如果内存很重要,我会选择操作系统设施。

如果你有 ext4,我会假设你在 Unix 上(你可以在其他操作系统上安装 find,比如 Win)。如果是这种情况,您可以使用本机 find 命令(这将是最后一分钟,您当然可以记住上次扫描时间并将其修改为您喜欢的任何内容): find /directory_path -type f -mtime -1 -打印

当然你不会有删除。如果启发式算法对您有用,那么您可以创建一个线程,慢慢转到存储在数据库中的每个文件(无论您需要先显示什么,然后从新到旧显示)并检查它是否仍然在线。这不会消耗太多内存。我认为您无论如何都无法向用户显示十亿个文件。

于 2012-07-05T11:52:03.883 回答
0

您是否有删除发生时删除内容的列表(或更改任何删除过程以创建此内容)?如果是这样,您是否不能拥有一个带有时间戳的“我已被删除”列表,然后从该列表中选择项目以仅同步更改的内容?自然地,您仍然希望在服务器上缓慢同步某种批处理作业,但我认为这可以减少负载。

根据更改代码的内容,另一种选择可能是让该进程在删除时直接更新数据库(如果您有多个节点)。这将在系统中引入一些耦合,但将是最有效的方法。

在我看来,最好的方法是对已发生删除的消息传递的想法进行一些变化(即使这只是一个文件,您使用最近删除的文件列表写入某个位置),或者某种直接回调机制,或者通过代码或直接从删除过程中调整应用程序使用的持久数据存储。

即使说了这么多,您总是需要对索引进行某种索引同步或定期完整性检查,以确保所有内容都正确匹配。

您可以(如果您不必根据您拥有的文件数量来划分,我会感到震惊)将文件空间划分为多个文件夹,例如每个文件夹 5,000-10,000 个文件,然后创建一个简单的文件具有文件夹中所有文件名称的哈希值。这会捕获删除,但我仍然认为在删除发生时直接回调某种形式是一个更好的主意。如果你有一个包含所有这些东西的单一文件夹,那么创建一些东西将它分成单独的文件夹(我们在主文件夹下使用简单的数字,这样我们就可以继续下去了)应该会大大加快一切;即使您必须对所有新文件执行此操作并将旧文件原样保留,至少您可以停止文件检索的流血。

在我看来,由于您正在以编程方式控制文件的索引,因此当底层文件系统发生更改时,您确实应该以某种方式涉及(或通知)相同的程序,而不是允许更改发生并且然后查看所有内容以获取更新。自然地,为了捕捉这种通信中断的异常值,您还应该在其中有同步代码来实际检查文件系统中的内容并定期更新索引(尽管这可以并且可能应该分批处理到主应用程序)。

于 2012-07-05T11:21:21.103 回答
0

理论上,您可以通过检查目录上的“修改”时间戳来加快速度。如果目录没有被修改,那么您不需要检查该目录中的任何文件。不幸的是,您确实需要扫描可能的子目录,并且找到它们涉及扫描目录......除非您保存了目录树结构。

当然,这没有实际意义,因为您有一个包含十亿个文件的平面目录。


我想您正在组装内存中的所有文件路径,以便您可以在查询数据库之前对它们进行排序。(并且对它们进行排序是一个好主意......)但是还有一种替代内存排序的方法:

  1. 将文件路径写入文件。
  2. 使用外部排序实用程序将文件排序为主键顺序。
  3. 读取排序后的文件,并按关键顺序对数据库执行批量查询。

(您的光盘上真的有十亿个文件吗?这听起来对您的数据存储来说是个糟糕的设计......)

于 2012-05-21T07:00:03.707 回答