Seite 1 von 3

Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mo, 31. Jan 2022 20:42
von ramses
Hallo zusammen

ich habe eine neue Funktion erstellt. Diese nutzt intensiv die Low-Level File Funktionen FOpen() FRead() FWrite() FSeek() FClose() in mehreren unterschiedlichen Threads im selben Programm auf lokale Dateien auf einem Server 2019.

Thread1 öffnet, schreibt in die Datei und schliesst die Datei sofort im Intervall von 1-5 Sek. Dieser Thread ist der einzige der in die Datei SCHREIBT.

Thread2....X öffnen, lesen und schliessen die Datei auch sofort.

Obwohl alles eigentlich perfekt funktionert kommt es sehr häufig, vorallem wenn mehrere Threads lesen, zum Fehler "Interne Datenstrukturen zerstört" in irgend einem Thread der wird dann neu gestartet. Dennoch arbeitet das Programm nicht mehr korrekt "frisst" Speicher und muss zwingend neu gestartet werden.

Kennt jemand die mögliche Ursache? Abhilfe? Sind die Low-Level Funktionen überhaupt für obige Aufgabe geeignet?

Das merkwürde dabei ist: Lässt Thread1 (der Schreibende) die Datei durchgehend geöffnet ist das Problem nicht vorhanden. Die anderen Threads können Stresstest mässig auf der Datei rummachen, nichts geschieht. Schliesst auch Thread1 die Datei dauerts oft nur Sekunden bis zum Crash.


Leider sind die Windows API Funktionen aus dem Kernel nicht so ganz einfach zu nutzen ... das wäre ein Versuch wert ...

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 12:27
von Lewi
Hallo Carlo,
das Problem liegt im konkurrierenden Schreiben in eine Datei oder beim Lesen von Daten aus einer Datei, die gerade beschrieben wird. Eine zu beschreibende Datei muss im mit dem Parameter -w aufgerufen werden. Betriebssystemsseitig führt es dann zu Problemen, wenn von mehreren Threads versucht wird, gleichzeitig in diese Datei schreiben.

Ein Lösungsansatz wäre, das Schreiben in einem separaten Thread (Wright-Thread) auszulagern, der andere Threads (die nur lesenden Zugriff auf die zu beschreibene Datei haben) über die Signal()-Methode mitteilt, ob ein Schreiben in die Datei aktuell möglich ist. Falls nicht, solange zu warten, bis vom „Write-Thread“ das „ok“ kommt. Über die ::cargo Instanz-Variable könnte die zu schreibenden Daten eines Threads an den Wright-Thread weiter gereicht werden.

Mann konnte über die Signal()-Mehode auch lesende Threads mitteilen, das aktuell ein "Write" ausgeführt. Solange dies der Fall, sollte auch ein lesender Zugriff unterbunden werden.
Viele Grüße
Olaf

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 12:51
von ramses
Hallo Olaf

Das ist bereits beinahe so wie du schreibst.

Thread 1 öffnet als einiger die Datei für Lesen und Schreiben und ist SYSTEMWEIT die EINZIGE Funktion welche die Datei R/W öffnet und in diese schreibt. Alle der so benutzen Dateien werden im voraus in voller Länge ( 700 MB pro Datei) mit dem benötigten Dateiinhalt (Raster) generiert und vorbereitet. Die Dateilänge ändert danach nie mehr. Es werden vom Thread 1 nur noch bestimmte Positionen überschieben.

ALLE anderen Funktionen und Operation öffnen die Datei nur Lesend ein Schreibzugriff kann absolut ausgeschlossen werden.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 13:01
von Lewi
Wird die Datei nach dem Schreiben geschlossen?

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 13:12
von Lewi
Ein fWrite() schreibt die Daten nicht auf den Datenträger sondern in einen Puffer. Erst mit einem fclose(nFileHandle) werden die Puffer physikalisch auf den Datenträger geschrieben.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 13:19
von ramses
Hallo Lewi

nein die Datei wird nach dem Schreiben nicht geschlossen, wenn Sie geschlossen wird treten sofort die Probleme auf.

Die anderen Threads mit eigenen Filehandles sehen aber mit fread() die änderungen sofort.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 13:22
von Lewi
Das ist eben das Problem. Die geänderten Daten befinden sich ohne flcose() eben nicht auf dem Datenträger.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 13:27
von ramses
Lewi hat geschrieben: Mi, 02. Feb 2022 13:22 Das ist eben das Problem. Die geänderten Daten befinden sich ohne flcose() eben nicht auf dem Datenträger.
Ja aber das Problem dabei ist dass die XBase APP crasht, sobald ich jeweils nach dem Schreiben die Datei mit fclose() schliesse dann treten die Probleme auf, der crash kommt jeweils schon nach Sekunden ..... Sobald nicht nur geschrieben sondern auch gelesen wird.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 13:41
von Lewi
Kannst Du auschließen, das während eines Lesevorgangs gleichzeitig geschrieben wird? Meines Erachtens solltes Du dem Write-Thread nach dem Schreiben ein fClose() ausführen um die Daten physikalisch wegzuschreiben.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 14:06
von ramses
Lewi hat geschrieben: Mi, 02. Feb 2022 13:41 Kannst Du auschließen, das während eines Lesevorgangs gleichzeitig geschrieben wird?
Nein, das kann ich nicht.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 14:10
von Lewi
Dann wirst Du wohl das Lesen einer Datei zum Zeitpunkt des Schreibens ( mit fclose() ) unterbinden müssen.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 14:33
von ramses
Nicht mal das geht!

Jetzt habe ich versucht die Datei Exclusive zu öffnen, so kann nur 1 Prozess mit der Datei was tun, die anderen müssen in einer "Sleep" Schlaufe bis zum fclose() des Vorgängers warten, das tun Sie auch, aber nicht mal das hilft.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 14:36
von Lewi
Was gibt den Flcose() an Bytes zurück? Deckt sich das mit den fWrite() geschrieben Bytes?

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 15:05
von ramses
fClose() nur .t. zurück.

fWrite() gibt jeweils korrekte Werte zurück.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 15:11
von Marcus Herz
Ich hoff, du verwendest SYNC Methoden beim Schreiben , öffnen und lesen...
"Interne Datenstrukturen zerstört"
Das heisst, der Xbase Speicher ist kaputt, Speichervariablen zeigen auf einen flaschen/ungültigen Speicher. Evtl. in dem Fall alle nicht mehr benötigten Variablen explizit auf NIL setzen.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 15:39
von ramses
Hallo Marcus

Ja, ich habe es auch mit einer Sync Methoden versucht. Keine änderung.

Das verrückte ist ja: Lasse ich den Handle des Schreibenden Threads offen funktioniert alles einwandfrei. Schreiben und Lesen. Über Tage.

***
Schliesse ich nach jedem Schreiben (alle 1-2 Sekunden) den fürs schreiben genutzten Handle funktionert das Schreiben in sich einwandfrei.
Dies solange keine lesenden Zugriffe kommen.
Kommen diese dazu, lesende Zugriffe (5-10 pro/Sek.) über fopen() --- fclose() krachts, meist schon nach Sekunden.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 15:52
von Jan
Carlo,

kannst Du da ein Sample schreiben, mit dem das reproduzierbar so läuft? Dann mal an Alaska schicken.

Jan

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 16:10
von Marcus Herz
- man kann nicht ausschliessen, dass das ein Problem mit dem Windows Datei Cache ist. Aber mir fällt auch nichts ein, wie man das eingrenzen könnte

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 16:39
von ramses
Ach Jan

das habe ich doch auch schon versucht.

Ein kleines Testprogramm zu schreiben das den Fehler provoziert.

Leider gelingt mir dies nicht. Das kleine Testprogramm läuft mit einer kleinen Datei ohne SYNC oder weiteres absolut Problemlos.
Also muss es mit irgenwas, einer Einstellung oder Zusatz DLL wie L&L PDF-Tools oder sonstigem zusammenhängen das mithilt den Fehler zu erzeugen.

Nur mit was? Ich tappe völlig im Dunkeln.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Mi, 02. Feb 2022 20:56
von Marcus Herz
Zusatz DLL wie L&L PDF-Tools
Da klingelts bei mir.
- Ich würde so vorgehen:
- es hängt wahrscheinlich gar nicht mit f-F<unktionen zusammen.
- Mach doch eine Kopie der Datei und lass die Lesevorgänge auf die Kopie los, dann kann man ausschliessen, dass es mit f Funktione zusammenhängt. Möcht drauf wetten, dass nicht.
- Datenstruktur korrupt: ich tippe auf die DLLs, die irgendwie in den Threads hängen bleiben. Hier hilft viuelleicht schon mal, alles auf NIL zu setzen, wenn der Thread geschlossen wird.
- Hier würde ich das mal ohne die AUfrufe der DLLs laufen lasen, auf der gleiche F Datei. Wahrscheinlich kommt dann kein Fehler.
- Welche der beiden DLLs jetzt der Verursacher ist, vielleicht kann man das mal nur mit der einne, dann der anderen laufen lassen, das Ergebnis muss ja nicht sinnvoll sein, es müssen nur die Module geladen werden, ein paar Aufrufe und Thread wiedder schiiessen.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Do, 03. Feb 2022 7:10
von ramses
Hallo Marcus

danke für die Tips.

Ich denke auch dass es nicht die f-- Funktionen sind sondern eine kombination mehrere Punkte welche die f-- Funktionen stören.
Inzwischen habe ich auch noch direkt mit den File Funktionen aus der Kernel32 API versucht.

Der schreibende Thread und die zugehörigen Hilfs-Threads sowie auch alle darin enthaltenen Klassen und zusatz DLL's werden nie geschlossen alles läuft hier in Schlaufen und fragt mit den Zusatz DLL's über deren spezifische Kommunikations Protokolle über diverse verschiedene Schnittstellen die dazu gehörigen diversen Geräte ab und verteilt auch neue Werte. Das hat alles schon lange einwandfrei funktioniert ABER mit schreiben in eine DBF
Nun musste ich für eine Aufgabe was ändern und dachte zur Platz und Zeitoptimierung wäre ein Biräres File besser, war es auch, doppelt so schnell, halber Platz Verbrauch auf Platte, funktionierte auch ... solange der Schreibende Thread das File nicht schliesst.

Habe mich gestern Abend noch mit Kumpels getroffen und gequatscht, da meinte einer: Du bist ja immer der mit dem Spruch: Ändere kein laufendes System ... was tust du denn jetzt???

Nach längerem überlegen (ohne Wein) baue nun alles auf die vorherige, jahrelang bewährte, Variante mit dem Schreiben in die DBF zurück. Besser die Wochen Arbeit abschreiben als noch lange nach der Ursache zu suchen um dann rauszufinden dass es an der DLL XY liegt die speziell Entwickelt wurde und nicht so einfach zu ersetzten ist .........

Es ist zwar aus meiner Sicht unbefiedigend die Ursache nicht gefunden zu haben und zu kennen aber der Kunde bekommt sein Ding und ich darf aus dem Büro hinaus und für einige Zeit wieder auf die Strasse ...

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Sa, 05. Feb 2022 1:32
von Lewi
Hallo,
da ich die letzten Tage sehr “bussy“ war, möchte jetzt an dieser Stelle meine Sicht der Fehler-Ursache aufzeigen.

fwrite() schreibt die Daten nicht direkt auf die Festplatte sondern in einen vom OS verwalteten Prozess-Warteschlange. Es kann auch sein sein, dass xBase diesen internen Prozess-Buffer selbst verwaltet. Aber auch dann, hat letztendlich das xBase-Laufzeitsystem keinen Einfluss darauf, wann die Daten aus dem Puffer physikalisch auf dem Datenträger geschrieben werden. Der Write-Aufruf wird lediglich als Prozess initialisiert und in die Prozess-Warteschlange angehängt und irgendwann abgearbeitet.

Das File-Handle selbst hat wiederum ein eigenen System-Buffer.

fClose() als Low-Level Funktion schließt die Datei, veranlasst aber nicht das Schreiben . Es obliegt dem OS, wann die Daten geschrieben werden.
Die Datenschreibintegrität wird manchmal auch als Write through to disk on disk on flush bezeichnet. Dies kann mit fwite() und fclose() nicht sichergestellt werden. Erst wenn der Schreib-Prozess abgearbeitet worden ist, wenn alle system-internen Daten-Puffer gelöscht.

Auch wenn untermittelbar nach einem fclose() mit fOpen() und fread() auf die Datei lesend zugegriffen wird, könnte der write()-Befehl innerhalb der Prozess-Warteschlange noch nicht abgearbeitet worden sein. Eine Verzögerung der physikalischen Speicherung von Daten kann bei Windows und Linux beobachtet werden. Deutlich wird dies insbesondere bei USB-Laufwerken.

Hochsprachen wie C, Python oder PHP 8.1 stellen die Funktion fsync(nHandle) bereit. Die Funktion versucht, Änderungen auf den Datenträger zu übertragen. Anschließend werden alle internen Puffer geleert.
Ich denke, man hat bewusst den Sync-Befehl nicht im Zuge von fWrite() implementiert, weil es zu Lasten der Performance geht.
In PHP sieht das z.B. so aus:

Code: Alles auswählen

function writeInTestFile() {
    $success = false;
    $file = fopen('test.txt', 'wb');
    $data = "Hello\nthis is a test!";
    if (fwrite($file, $data) !== false) {
        $success = fsync($file); 
    }
    fclose($file);
    return $success;
}
Das irgendwelche ausgestiegenen DLL’s bei einem Thead als Ursache in Frage kommen, halte ich für unwahrscheinlich, wenn der Fehler ansonsten auch ohne Fremd-DLL’s reproduziert werden kann. Der Zugriff über fopen() und fread() führt zu Fehlermeldungen, weil sie wohl auf die internen Buffer zugreifen, diese aber noch mit alten Daten gefüllt sind. Diese Buffer werden in der Regel mit Zeiger-Arithmetriken verwaltet und führen dann in das Speicherstellen-Nirvana bzw. verweisen auf eine Speicherstelle, die nicht angelegt werden kann. Aber sind meinerseits nur Vermutungen.

Wenn ich mich recht erinnere, gibt es in xBase++ den fsync() -Befehl nicht. Dieser sollte m.E. von ALASKA dringend implementiert werden.
Da ich nicht mehr mit xbase++ programmiere, juckt mich allerdings dieser Umstand nicht. 😉

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Sa, 05. Feb 2022 9:33
von georg
Hallo, Lewi -

interessante Darstellung, danke!

Unter Windows gibt es den Befehl fflush (https://docs.microsoft.com/de-de/cpp/c- ... w=msvc-170), den man eigentlich recht einfach abbilden könnte, und der anscheinend mit dem gleichen Dateihandle arbeitet, das auch in Xbase++ zur Verfügung steht.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Sa, 05. Feb 2022 10:02
von Herbert
Abgeleiteet aus dieser interessanten Darstellung fragt sich, warum im gegebenen Beispiel mit Dateien gearbeitet wird.
Falls der Dateiinhalt nicht enorm ist und der Inhalt fassbar ist, dann könnte besser der gesamte Inhalt in eine SQL-TAbelle gelegt werden. Dadurch wäre das korrekte Zugreifen gewährleistet.

Re: Low Level File I/O --> Interne Datenstrukturen zerstört

Verfasst: Sa, 05. Feb 2022 11:53
von mikehoffmann
Hallo Ramses,
ich glaube nicht, dass das Problem im Xbase zu suchen ist. Die F-Funktionen werden bestimmt direkt weiterrufen in die API-Funktionen und auch gleich das Ergebnis abliefern. Ich selber verwende die Dinger normalerweise nicht, weil man da so gut wie nix angeben kann, was man selber gerne machen würde und was man anderen Dateizugreifern gestatten möchte. Und asynchroner I/O ist auch nicht möglich. Ich nutze daher die API-Funkionen und das funktioniert eimandfrei, wie man in Franken sagt.
Allerdings ist auch nicht auszuschließen, dass die Xbase-Funktionen doch nicht ganz astrein sind. Auch bei den Zugriffen auf die Debe-Äffchen und Ente-Ixen fängt Xbase nicht alle Dramen sauber ab, was tatsächlich zum plötzlichen Kindstot führt.
Wenn Du ein Progrämmsche schreibst, das den Fehler reproduziert, dann hole ich die Abgreifklemmen (DllCall-Hooks) raus und wir schauen nach, was im Souterrain passiert.
Viele Grüße
Michael