代码之家  ›  专栏  ›  技术社区  ›  György Andrasek

大量文件的原子删除

  •  5
  • György Andrasek  · 技术社区  · 16 年前

    我正在尝试一次删除10000多个文件,例如,要么所有文件都需要立即删除,要么所有文件都需要保留。

    当然,显而易见的答案是将所有文件移动到一个临时目录中,并在成功时递归删除它,但这会使所需的I/O量增加一倍。

    压缩不起作用,因为1)我不知道哪些文件需要删除,2)文件需要经常编辑。

    编辑:假设停电随时都可能发生。

    9 回复  |  直到 16 年前
        1
  •  13
  •   Dale Hagglund    16 年前

    Kibbee是正确的:您正在寻找交易。但是,如果您不想依赖数据库或特殊的文件系统功能,则无需依赖它们。交易的本质是:

    1. 安全写入此记录后,请确保应用程序的行为与文件实际已被删除一样。
    2. 稍后,开始删除事务记录中命名的文件。
    3. 删除所有文件后,删除事务记录。

    请注意,您不应该走得太远:否则您将开始重新实现一个真正的事务系统。然而,如果您只需要很少几个简单的事务,那么滚动您自己的方法可能是可以接受的。

        2
  •  6
  •   DigitalRoss    16 年前

    在*nix上,在单个文件系统中移动文件是一种成本非常低的操作,它通过硬链接到新名称,然后断开原始文件的链接来工作。它甚至不会更改任何文件时间。

    你确定你不只是想要一个数据库吗?它们都内置了事务提交和回滚功能。

        3
  •  5
  •   Kibbee    16 年前

    Transactional NTFS . 我不太确定它是如何工作的,但它可能是有用的。

    还有一种叫做 shadow copy 对于Windows,在Linux世界中被称为 LVM Snapshot . 基本上,它是光盘在某个时间点的快照。您可以在执行删除操作之前直接拍摄快照,如果未能成功,请将文件从快照中复制回来。我在VBScript中使用WMI创建了卷影副本,我确信C/C++中也存在类似的API。

    关于卷影复制和LVM Snapsots的一件事。整个分区的工作。因此,您不能仅拍摄单个目录的快照。但是,拍摄整个磁盘的快照只需几秒钟。所以你要拍一张快照。删除文件,如果不成功,请将文件从快照中复制回来。这会很慢,但取决于您计划回滚的频率,这可能是可以接受的。另一个想法是恢复整个快照。这可能好,也可能不好,因为它会回滚整个磁盘上的所有更改。如果您的操作系统或其他重要文件位于那里,则不太好。如果此分区仅包含要删除的文件,则恢复整个快照可能更容易、更快。

        4
  •  2
  •   user181548 user181548    16 年前

        5
  •  2
  •   caf    16 年前

    难道你不能建立一个要删除的路径名列表,把这个列表写到一个文件中吗 to_be_deleted.log ,确保文件已命中磁盘( fsync() ),然后开始执行删除操作。完成所有删除后,删除 事务日志。

    启动应用程序时,它应该检查是否存在 将被删除。日志 ,如果存在,则重播该文件中的删除(忽略“不存在”错误)。

        6
  •  2
  •   Omnifarious    16 年前

    你的问题的基本答案是“不”。更复杂的答案是,这需要文件系统的支持,很少有文件系统有这种支持。显然NT有一个事务FS,它确实支持这一点。Linux的BtrFS也可能支持这一点。

        7
  •  1
  •   jthg    16 年前

    我认为复制然后删除方法是实现这一点的标准方法。你知道你不能容忍额外的I/O吗?

    我不认为自己是文件系统的导出者,但我认为执行事务的任何实现都需要首先尝试执行所有所需的操作,然后需要返回并提交这些操作。也就是说,您无法避免执行比非原子方式更多的I/O。

        8
  •  1
  •   jldupont    16 年前

    您是否有用于访问文件的抽象层(如数据库)(如果您的软件直接进入文件系统,则我的建议不适用)。

    如果删除文件的条件是“正确的”,则在抽象层中将状态更改为“已删除”,并开始后台作业,以便“真正”从文件系统中删除文件。

    当然,此方案在打开/关闭文件时会产生一定的成本,但在创建符号链接等方面会为您节省一些I/O。

        9
  •  1
  •   bdonlan    16 年前

    在Windows Vista或更新版本上, Transactional NTFS

    HANDLE txn = CreateTransaction(NULL, 0, 0, 0, 0, NULL /* or timeout */, TEXT("Deleting stuff"));
    if (txn == INVALID_HANDLE_VALUE) {
      /* explode */
    }
    if (!DeleteFileTransacted(filename, txn)) {
      RollbackTransaction(txn); // You saw nothing.
      CloseHandle(txn);
      die_horribly();
    }
    if (!CommitTransaction(txn)) {
      CloseHandle(txn);
      die_horribly();
    }
    CloseHandle(txn);