2009-10-26 11 views
5

Ich versuche, 10000 Dateien gleichzeitig zu löschen, z. Entweder müssen alle auf einmal gelöscht werden, oder alle müssen an ihrem Platz bleiben.Atomic delete für große Mengen von Dateien

Natürlich ist die offensichtliche Antwort, alle Dateien in ein temporäres Verzeichnis zu verschieben und es bei Erfolg rekursiv zu löschen, aber das verdoppelt die erforderliche Anzahl von E/A.

Komprimierung funktioniert nicht, weil 1) Ich weiß nicht, welche Dateien gelöscht werden müssen, und 2) die Dateien müssen häufig bearbeitet werden.

Gibt es etwas, das die I/O-Kosten senken kann? Jede Plattform wird es tun.

EDIT: Nehmen wir an, ein Stromausfall kann jederzeit passieren.

Antwort

13

Kibbee ist richtig: Sie suchen nach einer Transaktion. Sie müssen jedoch nicht auf Datenbanken oder spezielle Dateisystemfunktionen angewiesen sein, wenn Sie dies nicht möchten. Die Essenz einer Transaktion lautet wie folgt:

  • Schreiben Sie einen Datensatz in eine spezielle Datei (häufig als "Protokoll" bezeichnet), die die Dateien auflistet, die Sie entfernen werden.
  • Sobald dieser Datensatz sicher geschrieben ist, stellen Sie sicher, dass Ihre Anwendung so funktioniert, als ob die Dateien tatsächlich entfernt wurden.
  • Später entfernen Sie die Dateien, die im Transaktionsdatensatz benannt sind.
  • Nachdem alle Dateien entfernt wurden, löschen Sie den Transaktionsdatensatz.
  • Beachten Sie, dass Sie jederzeit nach Schritt (1) Ihre Anwendung neu starten können und die logisch gelöschten Dateien weiterhin entfernen, bis sie endgültig verschwunden sind.

    Bitte beachten Sie, dass Sie diesen Pfad nicht sehr weit verfolgen sollten: Sie fangen damit an, ein reales Transaktionssystem neu zu implementieren. Wenn Sie jedoch nur wenige einfache Transaktionen benötigen, ist der Roll-On-Own-Ansatz möglicherweise akzeptabel.

    +1

    +1: Markieren zum Löschen; Hör auf zu benutzen. Ein physisches Löschen kann jederzeit danach erfolgen. –

    +0

    Was passiert, wenn etwas passiert, was dazu führt, dass eine der Dateien nicht löschbar ist, so wie eine von ihnen von einem anderen Prozess verwendet wird? Du könntest einfach darauf warten, dass es freigegeben wird, aber das könnte eine Weile dauern. Wie würden Sie zurückrollen, wenn nicht alles gelöscht werden könnte? – Kibbee

    +0

    Genau das brauche ich. +1 für "Warum habe ich nicht daran gedacht?" –

    2

    Anstatt die Dateien zu verschieben, erstellen Sie symbolische Verknüpfungen in das temporäre Verzeichnis. Wenn alles in Ordnung ist, löschen Sie die Dateien. Oder machen Sie einfach eine Liste der Dateien irgendwo und löschen Sie sie dann.

    5

    Ich denke, was Sie wirklich suchen, ist die Möglichkeit, eine Transaktion zu haben. Da die Disc nur jeweils einen Sektor schreiben kann, können Sie die Dateien nur einzeln löschen. Was Sie brauchen, ist die Möglichkeit, die vorherigen Löschungen rückgängig zu machen, wenn eine der Löschungen nicht erfolgreich durchgeführt wird. Aufgaben wie diese sind normalerweise für Datenbanken reserviert. Ob Ihr Dateisystem Transaktionen ausführen kann, hängt davon ab, welches Dateisystem und Betriebssystem Sie verwenden. NTFS unter Windows Vista unterstützt Transactional NTFS. Ich bin mir nicht sicher, wie es funktioniert, aber es könnte nützlich sein.

    Auch gibt es etwas namens shadow copy für Windows, die in der Linux-Welt ein LVM Snapshot genannt wird. Grundsätzlich ist es eine Momentaufnahme der Scheibe zu einem Zeitpunkt. Sie können einen Snapshot direkt vor dem Löschen erstellen, und wenn es nicht erfolgreich ist, kopieren Sie die Dateien aus dem Snapshot zurück. Ich habe Schattenkopien mit WMI in VBScript erstellt, ich bin sicher, dass ähnliche Apis auch für C/C++ existieren.

    Eine Sache über Shadow Copy und LVM Snapsots. Die Arbeit an der gesamten Partition. Sie können also keinen Snapshot eines einzelnen Verzeichnisses erstellen. Das Erstellen eines Snapshots der gesamten Festplatte dauert jedoch nur ein paar Sekunden. Sie würden also einen Schnappschuss machen. Löschen Sie die Dateien, und kopieren Sie die Dateien anschließend aus dem Snapshot, wenn sie nicht funktionieren. Dies wäre langsam, aber abhängig davon, wie oft Sie einen Rollback planen, könnte dies akzeptabel sein. Die andere Idee wäre, den gesamten Snapshot wiederherzustellen. Dies kann oder kann nicht gut sein, da alle Änderungen auf der gesamten Festplatte zurückgesetzt werden. Nicht gut, wenn sich Ihr Betriebssystem oder andere wichtige Dateien dort befinden. Wenn diese Partition nur die Dateien enthält, die Sie löschen möchten, ist die Wiederherstellung des gesamten Snapshots möglicherweise einfacher und schneller.

    6

    Ein * nix, das Verschieben von Dateien innerhalb eines einzelnen Dateisystems ist eine sehr kostengünstige Operation. Es funktioniert, indem eine feste Verbindung zu dem neuen Namen hergestellt und dann die ursprüngliche Datei entfernt wird. Es ändert nicht einmal die Dateizeiten.

    Wenn Sie die Dateien in ein einzelnes Verzeichnis verschieben könnten, könnten Sie dieses Verzeichnis umbenennen, um es als echte atomare Operation zu umgehen, und dann die Dateien (und das Verzeichnis) später in einer langsameren, nicht atomare Mode.

    Sind Sie sicher, dass Sie nicht nur eine Datenbank haben wollen? Sie alle verfügen über eine Transaktion Commit und Rollback eingebaut.

    +0

    Warum denken Sie, Umzug ist billiger als löschen? –

    +0

    Da ich nicht im Voraus weiß, welche Dateien gelöscht werden, ist dieser Ansatz immer noch teurer als meins durch ein Umbenennungsverzeichnis. Es wäre aber nett. –

    +2

    @ralu: Alle Transaktionssysteme tun die Absicht aufzeichnen und identifizieren und koordinieren den Punkt, an dem keine Rückkehr stattfindet, bevor etwas getan wird, was nicht rückgängig gemacht werden kann. Ich habe versucht, einen Transaktionsansatz zum Löschen von Dateien aufzurufen. Es hat mehr Overhead als nur mit "unlink (2)" zu chippen, aber das ist der Preis für eine Transaktion. Ich hätte es wahrscheinlich auch gesagt. – DigitalRoss

    1

    Ich denke, die Kopie-und-dann-löschen-Methode ist so ziemlich der Standard Weg, dies zu tun. Wissen Sie, dass Sie die zusätzliche I/O nicht tolerieren können?

    Ich würde mich nicht zu einem Export bei Dateisystemen zählen, aber ich würde mir vorstellen, dass jede Implementierung für die Durchführung einer Transaktion zuerst alle gewünschten Aktionen ausführen müsste, und dann müsste sie zurückgehen und committen diese Aktionen. I.E. Sie können nicht vermeiden, mehr I/O durchzuführen, als dies nicht atomar zu tun.

    1

    Haben Sie eine Abstraktionsschicht (z. B. eine Datenbank), um die Dateien zu erreichen? (Wenn Ihre Software direkt in das Dateisystem geht, gilt mein Vorschlag nicht).

    Wenn die Bedingung "richtig" ist, um die Dateien zu löschen, ändern Sie den Status auf "gelöscht" in Ihrer Abstraktionsschicht und beginnen einen Hintergrundjob, um sie wirklich aus dem Dateisystem zu löschen.

    Natürlich ist dieser Vorschlag bei Öffnen/Schließen der Dateien eine gewisse Kosten mit sich bringt, sondern erspart Ihnen einige I/O auf Symlink Schöpfung usw.

    2

    Könnten Sie nicht nur die Liste der Pfadnamen bauen diese zu löschen, schreiben Liste in eine Datei , stellen Sie sicher, dass die Datei die Festplatte (fsync()) getroffen hat, dann starten Sie die Löschvorgänge. Nachdem alle Löschungen durchgeführt wurden, entfernen Sie das Transaktionslog .

    Wenn Sie die Anwendung starten, sollte es auf das Vorhandensein von prüfen, und wenn es dort ist, wiederholen Sie die Löschungen in dieser Datei (ignorieren "nicht existiert" Fehler).

    1

    Unter Windows Vista oder höher, sollten Transactional NTFS tun, was Sie brauchen:

    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

    Die grundlegende Antwort auf Ihre Frage "Nein" ist. Die komplexere Antwort ist, dass dies Unterstützung vom Dateisystem benötigt und sehr wenige Dateisysteme da draußen diese Art von Unterstützung haben. Anscheinend hat NT einen transaktionalen FS, der dies unterstützt. Es ist möglich, dass BtrFS für Linux dies auch unterstützt.

    In Ermangelung direkter Unterstützung, denke ich, dass die Option Hardlink, Move, Remove ist die beste, die Sie bekommen werden.

    Verwandte Themen