2009-10-26 61 views
5

我试图一次性删除10000个文件,原子化地或者全部需要立即删除,或者全部需要保留。大量文件的原子删除

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

压缩不起作用,因为1)我不知道哪些文件需要删除,以及2)需要频繁编辑这些文件。

有什么可以帮助降低I/O成本吗?任何平台都可以做到。

编辑:让我们假设停电可能随时发生。

回答

13

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

  1. 写出一个记录到一个特殊的文件(通常称为“日志”),列出您要删除的文件。
  2. 一旦这个记录被安全地写入,确保你的应用程序的行为就像文件实际上已被删除一样。
  3. 稍后,开始除去交易记录中指定的文件。
  4. 删除所有文件后,删除交易记录。

请注意,在步骤(1)之后的任何时候,您都可以重新启动应用程序,并且它将继续删除逻辑删除的文件,直到它们最终全部消失。

请注意,你不应该追求这个道路很远:否则你开始重新实现一个真正的交易系统。但是,如果您只需要几个简单的交易,那么您可以接受自己的方法。

+1

+1:标记为删除;停止使用。此后可以随时进行物理删除。 – 2009-10-26 00:49:28

+0

如果发生导致其中一个文件被取消删除的事情,如其中一个正在被另一个进程使用,该怎么办?你可以等待它被释放,但这可能需要一段时间。如果不是所有东西都可以被删除,你将如何回滚? – Kibbee 2009-10-26 00:56:28

+0

这正是我所需要的。 “为什么我没有想到这个?”+1。 – 2009-10-26 00:58:48

2

而不是移动文件,使符号链接进入临时目录。如果事情没有问题,请删除这些文件。或者,只需在某处制作一个文件列表,然后删除它们。

5

我认为你真正想要的是能够进行交易。由于光盘一次只能写入一个扇区,因此一次只能删除一个文件。您需要的是能够回滚以前的删除,如果其中一个删除没有成功发生。像这样的任务通常是为数据库保留的。您的文件系统是否可以执行交易取决于您正在使用的文件系统和操作系统。 Windows Vista上的NTFS支持Transactional NTFS。我不太确定它是如何工作的,但它可能有用。

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

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

6

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

如果您可以将文件移动到单个目录中,那么您可以重命名该目录以将其作为真正的原子操作方式取而代之,然后稍后以较慢的非重复操作删除文件(和目录)原子时尚。

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

+0

为什么你认为移动比删除便宜? – 2009-10-26 00:41:59

+0

由于我不知道提前知道哪些文件会被删除,所以这种方法比我的一个重命名目录更昂贵。这将是很好,但。 – 2009-10-26 00:54:13

+2

@ralu:所有交易系统所做的事情都是在做任何不可逆转的事情之前,记录其意图并确定和协调不回头的问题。我试图调用一种交易方法来删除文件。它有更多的开销,而不是仅仅消除'unlink(2)',但这是交易的价格。不过,我应该这么说。 – DigitalRoss 2009-10-26 01:48:11

1

我认为copy-and-then-delete方法几乎是执行此操作的标准方法。你知道一个事实,你不能容忍额外的I/O?

我不会指望自己在文件系统中导出,但我会想象任何执行事务的实现都需要首先尝试执行所有需要的操作,然后它需要返回并提交那些行动。 I.E.你不能避免执行更多的I/O而不是非原子操作。

1

您是否有抽象层(例如数据库)来获取文件? (如果你的软件直接进入文件系统,那么我的建议不适用)。

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

当然这个建议在开盘即被一定的成本文件的打开/关闭,但可以节省你在创建符号链接等一些I/O

2

你不能只是建立路径名来删除列表中,写这个列出文件to_be_deleted.log,确保该文件已经命中磁盘(fsync()),然后开始执行删除操作。所有删除操作完成后,请删除to_be_deleted.log事务日志。

当您启动应用程序时,应检查是否存在to_be_deleted.log,如果存在,则重播该文件中的删除(忽略“不存在”错误)。

1

在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); 
1

基本问题的答案是 “否”。更复杂的答案是,这需要文件系统的支持,而且很少有文件系统支持这种支持。显然NT有一个交易型FS,它支持这一点。 BtrFS for Linux也可能支持这一点。

在没有直接支持的情况下,我认为硬链接,移动,删除选项是最好的。