2009-10-26 57 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也可能支持這一點。

在沒有直接支持的情況下,我認爲硬鏈接,移動,刪除選項是最好的。