24 Stimmen

Wie kann man sicherstellen, dass alle Daten physisch auf die Festplatte geschrieben wurden?

Ich weiß, dass die Flush-Methode von .NET FileStream nur den aktuellen Puffer auf die Festplatte schreibt, aber abhängig vom Windows-Festplattentreiber und der Festplatten-Firmware ist dies keine Garantie dafür, dass die Daten tatsächlich physisch auf die Festplatte geschrieben werden.

Gibt es eine .NET- oder Win32-Methode, die mir diese Garantie geben kann? Wenn also eine Nanosekunde nach der Rückkehr des Aufrufs dieser Methode ein Stromausfall auftritt, kann ich dann immer noch sicher sein, dass alles in Ordnung ist?

18voto

jimvfr Punkte 353

Stefan S. sagte:

Ich verstehe, dass die Flush-Methode von .NET FileStream nur den aktuellen Puffer auf die Festplatte schreibt

Nein, .NET FileStream's Flush schreibt nur die .NET-Puffer in den OS-Cache, es flusht den OS-Cache nicht auf die Festplatte. Leider steht das nicht in der MSDN-Dokumentation zu dieser Klasse. Für .NET < 4.0, müssen Sie Flush + Win32's FlushFilebuffers aufrufen:

using System.Runtime.InteropServices;
. . .

// start of class:
[DllImport("kernel32", SetLastError=true)]
private static extern bool FlushFileBuffers(IntPtr handle);
. . .

stream.Flush();     // Flush .NET buffers to OS file cache.
#pragma warning disable 618,612 // disable stream.Handle deprecation warning.
if (!FlushFileBuffers(stream.Handle))   // Flush OS file cache to disk.
#pragma warning restore 618,612
{
  Int32 err = Marshal.GetLastWin32Error();
  throw new Win32Exception(err, "Win32 FlushFileBuffers returned error for " + stream.Name);
}

Für .NET 4.0 können Sie stattdessen die neue Methode flush(true) verwenden. Update vom 11.09.2012: MS-Fehlerbericht aquí sagt, dass es kaputt ist, dann behoben, aber sagt nicht, in welcher Version oder welchem Service Pack es behoben wurde! Klingt, als ob der Fehler auftrat, wenn der interne .NET FileStream-Puffer leer ist und Flush(true) nichts bewirkt?

9voto

Unter Windows finden Sie unter FlushFileBuffers (Win32 API).

0 Stimmen

Vielen Dank :) Ich habe schnell einen Leistungstest durchgeführt und FileStream.Flush() ist viel zu schnell, um wahr zu sein. FlushFileBuffers auf FileStream's SafeFileHandle ist so langsam wie ich es erwarten würde (100 mal langsamer als Flush() in meinem Test)

1 Stimmen

Ich habe festgestellt, dass der Aufruf von FlushFileBuffers eine Ausnahme verursachen kann ( stackoverflow.com/q/9195807/4540 ). Unter .NET 4 ist es einfacher und sicherer, einfach FileStream.Flush(true) aufzurufen, wie @jimvfr vorschlägt ( stackoverflow.com/a/3992428/4540 ).

0 Stimmen

Die Dateidaten, die im Dateisystem-Cache gepuffert sind, werden auf die Festplatte geschrieben. Diese Daten werden normalerweise abhängig von der Position des Schreibkopfes auf der Festplatte geschrieben. Ein Gigabyte an zwischengespeicherten Daten ist technisch möglich und kann eine ganze Weile dauern. Wenn dies für Sie wichtig ist, sollten Sie stattdessen die Option FileOptions.WriteThrough verwenden.

5voto

Marc Gravell Punkte 970173

Nun, Sie könnten die Datei schließen... das würde wahrscheinlich genügen. In Wirklichkeit haben HAL-Abstraktion, Virtualisierung und Festplattenhardware heute mehr Verarbeitungsleistung und Cache-Speicher als Computer wie vor ein paar Jahren, müssen Sie sich damit abfinden, dass Sie hoffen, dass die Festplatte ihre Aufgabe erfüllt.

Das transaktionale Dateisystem hat sich nie wirklich durchgesetzt ;-p Natürlich könnten Sie vielleicht eine Datenbank als Backend verwenden und das Transaktionssystem dieser Datenbank nutzen?

Nebenbei bemerkt: nicht alle Streams garantieren auch die Flush() - zum Beispiel, GZipStream usw. behalten einen Arbeitspuffer mit unbestätigten Daten auch nach einem Flush - der einzige Weg, ihn zum Flush zu bringen alles soll Close() es.

0 Stimmen

Technisch gesehen gibt es beim Schreiben in eine Datenbank keine Garantie dafür, dass bei einem Stromausfall oder einem anderen katastrophalen Fehler der Schreibvorgang nicht verloren geht oder die Datenbank auf irgendeine Weise beschädigt wird, obwohl die Wahrscheinlichkeit, dass er überlebt, weitaus größer ist als bei einem einfachen Schreibvorgang im Dateisystem.

1 Stimmen

Ja, aber Sie können "Als erledigt markieren" und "Hier sind die Ergebnisse" in dieselbe Transaktion einpacken

1 Stimmen

@cletus Wenn ein Datenbanksystem das nicht garantiert, dann ist es entweder kaputt (zumindest halte ich ein DBMS, das nicht ACID ist, für kaputt) oder es läuft auf einem kaputten System (Betriebssystem, Hardware, was auch immer).

3voto

dave Punkte 31

Ich habe bemerkt, dass die .NET 4 #Flush(true) nicht tatsächlich auf die Festplatte schreiben. Wir hatten seltsame Probleme mit beschädigten Daten, und ich fand dies Fehlerbericht auf der MS-Website:

Auf der Registerkarte "Details" des Fehlerberichts können Sie ein Testprogramm ausführen, das das Problem aufzeigt;

  1. Eine Reihe von Daten auf die Festplatte schreiben
  2. fs.Flush(true) . Dies dauert keine Zeit (viel schneller als auf die Festplatte geschrieben werden kann).
  3. Verwenden Sie die Win32-API FlushFileBuffers . Das dauert sehr lange.

Ich wechsle zum win32 FlushFileBuffers-Aufruf...

0 Stimmen

Fs.Flush(true) funktioniert bei mir einwandfrei. Windows 10 x64 Ersteller Update, .NET 4.5

0 Stimmen

@jjxtra: Haben Sie einen Test mit einem Netzwerkserver durchgeführt und den Stecker physisch gezogen?

0 Stimmen

@Joshua nein, nur mit lokalem Dateisystem getestet, kann also nicht für dieses Szenario sprechen

0voto

MSH Punkte 183

Die Dateidaten, die im Dateisystem-Cache gepuffert sind, werden auf die Festplatte geschrieben. Diese Daten werden normalerweise abhängig von der Position des Schreibkopfes auf der Festplatte geschrieben. Ein Gigabyte an zwischengespeicherten Daten ist technisch möglich und kann eine ganze Weile dauern. Wenn dies für Sie wichtig ist, sollten Sie die FileOptions.WriteThrough stattdessen die Option.

1 Stimmen

Auch dies hat sich als unwirksam erwiesen. Das Betriebssystem wird weiterhin im Cache gespeichert.

0 Stimmen

@trevster344, Haben Sie eine Quelle dafür?

0 Stimmen

@Matt FILE_FLAG_WRITE_THROUGH war früher bei SATA-Laufwerken defekt: disruptivesql.wordpress.com/2012/05/08/sata-und-durchschreiben Ich kenne den aktuellen Stand der Dinge nicht, aber ohne weitere Untersuchungen und Tests würde ich mich nicht darauf verlassen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X