Autor Beitrag
matthew77
Hält's aus hier
Beiträge: 15



BeitragVerfasst: Fr 06.01.17 01:58 
Hi Forum,
ich hoffe, einer von Euch kann mir bei diesem seltsamen Phänomen helfen: ich habe hier eine selbstgeschriebene Software (in Delphi geschrieben), die auf einem Industrie PC mit Windows7 Embedded läuft. Das Problem: die Bediener schalten schon mal ganz gerne den Strom ab ohne die Software zu beenden oder gar Windows herunterzufahren. Windows stört das auch nicht weiter, denn das C-Laufwerk ist gegen Änderungen durch den EWF geschützt.
Wenn in der Software auf "speichern" geklickt wird, werden ein paar Megabytes an Dateien vom Arbeitsverzeichnis in ein spezielles "Sortimenteverzeichnis" kopiert. Dieser Kopiervorgang dauert je nach verwendetem Medium (HDD oder SSD) zwischen 20ms und 800ms.
Und jetzt kommt mein Problem: auch wenn nach dem Speichern noch längere Zeit gewartet wird bevor der PC stromlos gemacht wird, sind die kopierten Dateien teilweise defekt. Bei einer Wartezeit unter 10 Sekunden sind die angeblich kopierten Dateien teilweise gar nicht vorhanden, bei unter 40 Sekunden sind sie zwar alle in Originalgröße da, aber leider nur mit Nullen gefüllt - und das ganze auf einer superschnellen SSD!!
Ich habe zum Kopieren der Dateien verschiedene Methoden ausprobiert, unter anderem mit Laden und Speichern als TMemoryStream oder auch die ShFileOperation - die Ergebnisse waren immer die gleichen. Das Problem tritt übrigens nicht auf, wenn ich meine Software via Taskmanager sofort nach dem Auslösen des Kopiervorgangs "abschieße". Es hat mit dem "stromlos-Machen" zu tun. In meiner Not habe ich schließlich noch einen Ansatz probiert, und zwar den Aufruf des Windows-eigenen Programms "xcopy". Dieser bietet mit dem Schalter "/J" die Möglichkeit ohne "E/A Buffer" zu kopieren. Genau das bringts dann tatsächlich: ich konnte mit der SSD die kritische Zeit der mit Nullen gefüllten Dateien auf ca. 5 Sekunden verringern. Das Problem: mit normaler HDD funktioniert es nicht so richtig. Da bekomme ich auf dem Industrie PCs so seltsame "BOX Exceptions".
Hat von Euch vielleicht noch einer eine Idee, wie man das Problem in den Griff kriegen könnte? Bin für jeden Tipp dankbar!
Übrigens: eine USV kommt als Lösung zunächst nicht in Frage. Außerdem interessant: die Laufwerksrichtlinie (Schreibcache an bzw. aus) macht leider auch keienen Unterschied...
Holgerx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 62
Erhaltene Danke: 27

Win95 - Win11 / MSServer2000 - MSServer2019
Delphi 6pro / XE4
BeitragVerfasst: Fr 06.01.17 06:40 
Geht es Dir darum, zu 'Wissen' ob der Schreibvorgang abgeschlossen und somit vollständig ist, damit eventuell die Folgeverarbeitung nicht an defekten Daten scheitert?
Oder Musst Du die Dateien vollständig fertig schreiben?

Generell: Strom Weg während des Schreibens -> Datei unvollständig oder Müll drinnen. Das ist, wie wenn Du am Telefonieren bist und jemand deinen Stecker zieht, dann bekommt dein Gegenüber auch nicht den Rest des Satzes mit und er kann dann raten, was Du ihm mitteilen wolltest.
Meistens wird beim Kopieren von Dateien auf dem Ziel die Datei bereits mit der Sollgröße angelegt und dann nur noch gefüllt.
Somit können da Nullen oder auch nur Müll (ehemalige Daten gelöschter Dateien) drinnen stehen, welcher bei abruptem Stromaus so verbleibt.


Wenn es um die Folgeverarbeitung geht, gibt es ein paar Möglichkeiten, welche darauf ausgerichtet sind, den Abbruch zu bemerken und z.B. bei Neustart des PCs diesen Schreibvorgang zu wiederholen:
- Speichern in einer temp-Datei mit Umbenennen. Erst nach dem Umbenennen ist die Datei vollständig.
- Ablegen einer kleine Statusdatei, welche nach dem Abschluss des großen Speicherns wieder gelöscht wird. Wenn diese verbleibt, ist die eigendliche Datei undefiniert.


Aber vielleicht solltest Du überlegen, dass Speichern neu zu organisieren!
Anstatt einmal ein paar Megabytes eventuell (vorab) ein paar Kilobytes (vielleicht zunächst als Temp-Dateien). Somit würde sich die Schreibzeit beim Ausschalten minimieren.
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6386
Erhaltene Danke: 146

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 06.01.17 08:31 
Wenn der Strom aus, kann nichts mehr geschrieben werden. Das ist sicher kein Punkt, über den man diskutieren muss.
Dass xcopy ohne EA-Buffer funktioniert, deutet darauf hin, dass das Problem das Caching ist.
Du hast zwar geschrieben, dass du das Laufwerks-Caching deaktiviert hast, aber es gibt zwei Caching-Bereiche. Zum einen den von Windows und dann noch den Buffer der Festplatte.
Bist du sicher, beide deaktiviert zu haben?

In Delphi gibt es noch den Befehl FlushFileBuffers. Ob der allerdings beide Bereiche betrifft, kann ich nicht sagen.

100%ig absichern kannst du einen Strom-Ausfall nicht.
Ich würde einen Thread (oder Timer) programmieren, der die Datei in bestimmten Intervallen in ein Sicherungs-Verzeichnis schreibt. Sollte dann durch einen Stromausfall die richtige Datei defekt sein, kannst du so auf einen Stand zurückgreifen, der kurz davor erstellt wurde. Idealerweise gibt es dann noch 2-3 Versionen der Datei, da das Schreib-Intervall natürlich auch zufällig mit dem Stromausfall zusammentreffen könnte.
user profile iconmatthew77 hat folgendes geschrieben Zum zitierten Posting springen:
Übrigens: eine USV kommt als Lösung zunächst nicht in Frage.

Ähm, warum nicht?
Bei richtiger Konfiguration, wäre das die sicherste Möglichkeit.
matthew77 Threadstarter
Hält's aus hier
Beiträge: 15



BeitragVerfasst: Fr 06.01.17 12:12 
Hallo Leute und vielen Dank für die schnellen Antworten! Der Tipp mit "FlushFileBuffers" hat mich auf die Fährte von dem Flag "FILE_FLAG_WRITE_THROUGH" im Operator "CreateFile" gebracht und damit funktioniert es genau wie ich will. Eigentlich wollte ich auch noch "
FILE_FLAG_NO_BUFFERING" verwenden aber das wäre dann wieder recht kompliziert geworden (wegen Sektorengröße ermitteln und so) und es funktioniert wie gesagt auch mit "FILE_FLAG_WRITE_THROUGH".

Schönen Tag noch!

Hier übrigens meine Kopierroutine in Delphicode:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
procedure CopyFileQuick(src: string; dest:string);
var
  FileSrc,   //Source file
  FileDest,   //Destination file
  ByteRead,  //Variable mit gelesene bytes
  SizeBuff: cardinal;
  Buff:array of byte;
begin
  SizeBuff := 64*1024//Buffer grösse 64 kb
  // laut Windows Doku sollten IMMER absolute Pfade genommen werden,
  // daher "ExpandFileName".
  // FILE_FLAG_WRITE_THROUGH macht übrigens den Unterschied, ob die Daten sofort
  // geschrieben werden oder erst nach ca. 40 Sekunden. 
  FileSrc  := CreateFile(PChar(ExpandFileName(src)),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING, 0,0);//Öffnen für lesen
  FileDest := CreateFile(PChar(ExpandFileName(dest)),GENERIC_WRITE,FILE_SHARE_WRITE,nil,CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH or FILE_ATTRIBUTE_NORMAL,0); //Öffnen für schreiben oder erstellen
  SetLength(Buff, SizeBuff);

  ByteRead:=$FFFFFFFF;
  while ByteRead>=SizeBuff do begin
    ReadFile  (FileSrc,  Buff[0], SizeBuff, ByteRead, nil);  //lesen im Buffer
    WriteFile (FileDest, Buff[0], ByteRead, ByteRead, nil); // Schreiben aus Buffer
  end;
  CloseHandle(FileSrc);
  CloseHandle(FileDest);
end;


Moderiert von user profile iconChristian S.: Delphi-Tags hinzugefügt
trm
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 491
Erhaltene Danke: 19

Windows 7x64
Delphi 7
BeitragVerfasst: Fr 13.01.17 00:50 
Hallo matthew77,

warum ist Deine Variante schneller als die shfileoperation? Hast Du eine Idee dazu?

_________________
In Erfurt gibt es eine Pension, in der es gemütlich ist, Google einfach nach Pension Fiege ;)
t.roller
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 118
Erhaltene Danke: 34



BeitragVerfasst: Mo 16.01.17 01:19 
Man sollte SIZEBUFFER (SizeBuff) noch grösser machen.
Wenn CRYSTALDISKINFO eine Puffergrösse von 32MB anzeigt, sollte man das nutzen.
Tests:
File: 500MB

SizeBuff := 64*1024; // 64kB
Time for creating Bigfile: 20,202 s
Speed per sec: 24.750.025 Bytes/sec
--
SizeBuff := 16*1024; // 16kB
Time for creating Bigfile: 24,425 s
Speed per sec: 20.470.830 Bytes/sec
--
SizeBuff := 32*1024*1024; // 32MB
Time for creating Bigfile: 5,155 s
Speed per sec: 96.993.207 Bytes/sec
--
SizeBuff := 64*1024*1024; // 64MB
Time for creating Bigfile: 5,051 s
Speed per sec: 98.990.297 Bytes/sec
--
USB3.0-SSD
SizeBuff := 64*1024*1024; // 64MB
Time for creating Bigfile: 2,763 s
Speed per sec: 180.962.721 Bytes/sec

Für diesen Beitrag haben gedankt: matthew77
matthew77 Threadstarter
Hält's aus hier
Beiträge: 15



BeitragVerfasst: Mo 16.01.17 10:21 
Hallo Troller und danke für den guten Hinweis. Mir geht es bei der ganzen Sache gar nicht wirklich um Performance sondern in erster Linie um die Sicherheit, dass die Daten beim plötzlichen Ausschalten eine Sekunde nach Aufruf des Speichern-Befehls (sind wie gesagt nur wenige MB) auch wirklich alles an Ort und Stelle ist und das macht die Routine so schon verdammt gut.
@trm: keine Ahnung ob das wirklich schneller ist aber ich kann das tolle "FILE_FLAG_WRITE_THROUGH" nutzen und das ist es was mir die Sicherheit bringt. Übrigens habe ich den Verdacht, dass die Probleme mit dem stark verzögerten physikalischen Schreiben mit Windows 7 (evtl. sogar nur Win7 Embedded) zusammenhängen. Früher hatten wir XP Embedded und hatten sowas nicht (zumindest nicht so häufig wie jetzt). Kann aber auch Zufall sein...