Norbert: mehrere Benutzer - eine Datei - was kann passieren ?

Hallo Leute !

Ich werde mich möglichst kurz halten - ich bin das erste mal hier - SelfHTML kenne ich schon länger - nun bin ich gerade dabei in Perl einzusteigen - Basiswissen in rund 15 Programmiersprachen sollten für die Logik reichen - Syntax wird auch schön langsam verständlich.
Nun meine Frage(n):
Ich habe vor wenigen Tagen dieses Forum durchblättert und dabei über das Problem von möglichem Datenverlust bei mehreren gleichzeitigen Zugriffen auf eine Datei gelesen. Bis zu diesem Zeitpunkt habe ich mir eigentlich auch noch keine Gedanken darüber gemacht und eigentlich vermutet, dass das Betriebssystem dies koordiniert - aber nun möchte ich doch vorbeugend Infos einholen.
Ich bin gerade dabei, ein Progrämmchen für eine interaktive Linksammlung zu schreiben (vorerst einfaches hinzufügen von Zeilen). Dazu lese ich die ursprüngliche Datei (xx.htm) zur Gänze ein und schreibe diese Zeilen mit einigen neuen in eine weitere Datei (xx.tmp). Am Ende benenne ich diese Datei dann wieder um (xx.tmp > xx.htm). Kann es bei mehreren gleichzeitigen Schreib- und/oder Lesezugriffen zu Problemen (=Datenverlust) kommen ???

Vielen Dank im voraus und herzliche Grüsse aus Wien,

Norbert  =:-)

  1. Problem von möglichem Datenverlust bei mehreren gleichzeitigen Zugriffen auf eine Datei gelesen. Bis zu diesem Zeitpunkt habe ich mir eigentlich auch noch keine Gedanken darüber gemacht und eigentlich vermutet, dass das Betriebssystem dies koordiniert.

    Tja, Mitte der 80er war ich mal Administrator auf einem Host. Da ging das. (Insbesondere mit verschiedenen Öffnungsmodi, welche parallele Zugriffe erlaubten oder auch nicht - sogar Sperren einzelner Datensätze ging ... BS2000 war wunderbar.)

    Warte noch 10-20 Jahre, dann können die PCs und Workstations das *vielleicht* auch wieder ... :-(

    Dazu lese ich die ursprüngliche Datei (xx.htm) zur Gänze ein und schreibe diese Zeilen mit einigen neuen in eine weitere Datei (xx.tmp). Am Ende benenne ich diese Datei dann wieder um (xx.tmp > xx.htm). Kann es bei mehreren gleichzeitigen Schreib- und/oder Lesezugriffen zu Problemen (=Datenverlust) kommen ???

    Die Idee mit dem Umbenennen ist schon mal sehr gut.
    Was Du aber nicht verhinderst, das ist, daß zwei quasi-gleichzeitig startende Programme simultan die Daten einlesen, in zwei verschiedene temporäre Dateien ihr Ergebnis schreiben und nacheinander die Umbenennung durchführen. Die Ergebnisse des ersten Programms gehen dabei verloren.

    Synchronisation ist eine Sache für sich ... der Trick wäre, daß das zweite Programm merkt, daß das erste arbeitet. Das geht aber nur mit einer unteilbaren Operation, die das Semaphor sowohl abfragt als auch setzt.
    (Das Posten in unser Forum zeigt sporadisch Symptome genau eines solchen Problems: Zwei Leute überschreiben einander ihre Postings, weil sie dieselbe "Nummer gezogen" haben, aus der später ihr Dateiname bestimmt wird. Falls Dir jemals eine Diskrepanz zwischen Überschrift eines Postings in der Hauptdatei und Inhalt des Postings in der Posting-Datei auffällt: *Das* ist es, was dann passiert.)

    Du könntest die Gefahr weiter reduzieren, indem das Programm schon *vor* dem Lesen der Datei diese ebenfalls umbenennt (xx_read.tmp). Das ist etwas, was das zweite Programm nicht gleichzeitig ebenfalls tun kann - *das* sollte das Betriebssystem in der Tat synchronisieren. Das zweite Programm braucht dann halt eine Fehlerbehandlungsroutine, weil sein Umbenennungsversuch schiefgeht.

    1. »»Die Ergebnisse des ersten Programms gehen dabei verloren.

      Ist in meinem Fall nicht so schlimm - ist ja nur eine Linklist  :-)

      Du könntest die Gefahr weiter reduzieren, indem das Programm schon *vor* dem Lesen der Datei diese ebenfalls umbenennt (xx_read.tmp). Das ist etwas, was das zweite Programm nicht gleichzeitig ebenfalls tun kann - *das* sollte das Betriebssystem in der Tat synchronisieren. Das zweite Programm braucht dann halt eine Fehlerbehandlungsroutine, weil sein Umbenennungsversuch schiefgeht.

      Dies werd ich beherzigen und sage tausend Dank - ist echt ein tolles Forum - positives Erlebnis beim ersten Mal.

      Ich hoffe, hier auch mal jemandem helfen zu können - mal schauen...

      Danke nochmal

      Norbert

    2. Darf ich dir, da ich erst anfange, mich mit CGI, usw. zu beschäftigen, noch eine kurze Frage stellen?

      Kann eigentlich jeder in mein cgi-bin schauen und meine Files (bzw. sogar deren Inhalt) betrachten? Oder warum gibts im Forum diese vielen Einträge mit .htaccess, etc.?

      Danke im voraus,

      Norbert

      1. Hallo Norbert,

        Kann eigentlich jeder in mein cgi-bin schauen und meine Files (bzw. sogar deren Inhalt) betrachten? Oder warum gibts im Forum diese vielen Einträge mit .htaccess, etc.?

        wenn der Server richtig konfiguriert ist (so wie man's normalerweise macht :)
        kann man per Webbrowser nix im cgi-bin sehen, da man mit einem
        Fehler abgewiesen wird (so von wegen Zugriff Verboten und so).
        Die .htaccess braucht man, um in Verzeihnissen in denen normale
        Webseiten liegen die Zugangsmöglichkeiten zu regeln. Man kann
        aber auch noch einige andere teile der Serverkonfiguration damit
        überschreiben. Weiteres dazu findest du in der Apache Doku.
        Wenn du zu Hause keinen laufen hast, kann ich sie dir gerne
        mal zum Offlinelesen schicken.

        CYa
        GONZO

  2. Hallo Norbert !

    Kann es bei mehreren gleichzeitigen Schreib- und/oder Lesezugriffen zu Problemen (=Datenverlust) kommen ???

    Oh ja, aus eigener leidiger Erfahrung kann ich berichten, daß mir aus diesem Grunde bereits einmal mein komplettes Guestbook gelöscht wurde *schluchz* und ein anderes mal zerschoss es mir ein Forum in unserem firmeneigenen Intranet.

    Unter http://www.xwolf.com/faq/cgitutor4.html führt Wolfgang Wiese eine Methode auf die Files vor gemeinsamen (schreibendem) Zugriff schützt. Und, soweit ich mich recht erinnere, verwendet Markus Wolf in seinen Scripten auf http://www.perl-archiv.de/ teilweise eine klitzekleine Subroutine, die ebendieses bewerkstelligt.

    (..) herzliche Grüsse aus Wien

    Schöne Grüsse zurück von Köln
    Pepe

    1. »»http://www.xwolf.com/faq/cgitutor4.html

      Vielen Dank - URL bereits gespeichert - implementiert wirds morgen ...

      Norbert

  3. Hallo Norbert,

    Ich habe vor wenigen Tagen dieses Forum durchblättert und dabei über das Problem von möglichem Datenverlust bei mehreren gleichzeitigen Zugriffen auf eine Datei gelesen. Bis zu diesem Zeitpunkt habe ich mir eigentlich auch noch keine Gedanken darüber gemacht und eigentlich vermutet, dass das Betriebssystem dies koordiniert - aber nun möchte ich doch vorbeugend Infos einholen.

    Es gibt in Perl die Funktion flock(), die da gute Dienste leisten kann. Die Funktion regelt, wie andere Prozesse auf eine Datei zugreifen koennen, waehrend das aktuelle Script die Datei geoeffnet hat. Bei Betriebssystemen allerdings, die keinen Zugriffsschutz für geoeffnete Dateien implementiert haben, fuehrt die Anwendung dieser Funktion zu einem Fehler, so etwa auch bei Windows 95/98.

    Erwartet als Parameter:
    1. das Handle des Ein-/Ausgabekanals der geöffneten Datei.
    2. die Nummer einer Lock-Operation - erlaubt sind die Nummern 1, 2, 4 und 8:
    Nummer 1 bedeutet shared (Datei ausdruecklich mit anderen Prozessen teilen),
    Nummer 2 bedeutet exclusive (Normalfall - keinem anderen Prozess irgendeinen Zugriff auf die Datei erlauben),
    Nummer 4 bedeutet non-blocking (Datei nicht voellig blockieren - zum Beispiel lesenden Zugriff anderer Prozesse zulassen),
    Nummer 8 bedeutet unlock (Zugriffsschutz ausdruecklich wieder aufheben).

    und mal ein Beispiel - keine Ahnung, ob das so korrekt angewendet ist

    #!/usr/bin/perl

    open(LOGFILE, "</web/logs/access.log");
    flock(LOGFILE, 1);

    sub Lesen {
    seek(LOGFILE,0,0);
    @Zeilen = <LOGFILE>
    $Anzahl = 0;
    foreach(@Zeilen) { $Anzahl++; }
    }

    print "Content-type: text/html\n\n";
    print "<html><head><title>Testausgabe</title>\n";
    print "</head><body>\n";
    &Lesen;
    print "<p>Die Logdatei hat im Augenblick $Anzahl Zeilen</p>\n";

    angenommen, hier passiert etwas Zeitaufwendiges,

    und derweil greift ein anderer Prozess auf test.txt zu

    &Lesen;
    print "<p>Die Logdatei hat jetzt $Anzahl Zeilen</p>\n";
    print "</body></html>\n";

    flock(LOGFILE, 8);
    close(LOGFILE);

    viele Gruesse
      Stefan Muenz

    1. Hallo!

      1. das Handle des Ein-/Ausgabekanals der geöffneten Datei.
      2. die Nummer einer Lock-Operation - erlaubt sind die Nummern 1, 2, 4 und 8:
        Nummer 1 bedeutet shared (Datei ausdruecklich mit anderen Prozessen teilen),
        Nummer 2 bedeutet exclusive (Normalfall - keinem anderen Prozess irgendeinen Zugriff auf die Datei erlauben),
        Nummer 4 bedeutet non-blocking (Datei nicht voellig blockieren - zum Beispiel lesenden Zugriff anderer Prozesse zulassen),
        Nummer 8 bedeutet unlock (Zugriffsschutz ausdruecklich wieder aufheben).

      Das ist falsch! RFTM "perldoc -f flock". Zitat:

      OPERATION is one of LOCK_SH, LOCK_EX, or LOCK_UN, possibly combined with
      LOCK_NB.  These constants are traditionally valued 1, 2, 8 and 4, but
      you can use the symbolic names if import them from the Fcntl module,
      either individually, or as a group using the ':flock' tag.  LOCK_SH
      requests a shared lock, LOCK_EX requests an exclusive lock, and LOCK_UN
      releases a previously requested lock.  If LOCK_NB is added to LOCK_SH or
      LOCK_EX then flock() will return immediately rather than blocking
      waiting for the lock (check the return status to see if you got it).

      flock(LOGFILE, 8);
      close(LOGFILE);

      close impliziert ein unlock. Es ist aus gewissen Gruenden mehr als ratsam, dass flock(LOGFILE, 8) wegzulassen.

      Viele Grüße,
      Daniel Bradler

      1. Hallo Daniel

        Das ist falsch! RFTM "perldoc -f flock". Zitat:

        Hab' ich wohl, allein mir fehlt die Gruetze ;-)
        Ich bin halt immer eher fuer die nachvollziehbaren und verstaendlichen Loesungen. Und in dem Buch "CGI Programming" von Shishir Grundavaram fand ich auf S.123f.:

        "You simply call flock and pass the name of the file handle like this:
        flock(FILE,2);
        This call grants you the exclusive right to use the file."
        ...
        "When you're finished with the file, issue the following call:
        flock(FILE,8);"

        Kann also nicht ganz verkehrt sein, es so zu machen. Und wenn du anderer Ansicht bist bzw. begruenden kannst, was daran falsch ist, dann waere es fein, wenn du das tun wuerdest!

        viele Gruesse
          Stefan Muenz

        1. Hallo Stefan,

          Das ist falsch! RFTM "perldoc -f flock". Zitat:

          Hab' ich wohl, allein mir fehlt die Gruetze ;-)

          Du hast da etwas bei LOCK_SH und LOCK_NB durcheinander geworfen. Auf mangelnde Gruetze wuerde ich aber noch nicht schliessen wollen :-)

          Ich bin halt immer eher fuer die nachvollziehbaren und verstaendlichen Loesungen. Und in dem Buch "CGI Programming" von Shishir Grundavaram fand ich auf S.123f.:

          "You simply call flock and pass the name of the file handle like this:
          flock(FILE,2);
          This call grants you the exclusive right to use the file."
          ...
          "When you're finished with the file, issue the following call:
          flock(FILE,8);"

          Kann also nicht ganz verkehrt sein, es so zu machen. Und wenn du anderer Ansicht bist bzw. begruenden kannst, was daran falsch ist, dann waere es fein, wenn du das tun wuerdest!

          Ganz verkehrt ist es auch nicht. Aber aus zwei Gründen sollte man es der Einfachheit halber weglassen:

          1. Es ist unnötig, da ein close wie bereits gesagt ein Lock impliziert. Man kann sich also Code sparen.

          2. Kann es Probleme bei älteren Perl-Interpretern geben, nämlich dann wenn die Ausgabe gepuffert ist. Zum Zeitpunkt des unlocks muß das File nämlich noch gar nicht komplett geschrieben sein. Dies ist es erst beim close. Also: Ein explizites Unlock macht es nötig, den Schreibbuffer zu flushen (bei neueren Perlversionen geschieht das wohl automatisch) - oder eben nur close benutzen.

          Das Thema wurde etliche Male in de.comp.lang.perl.misc behandelt. Bei deja.com läßt's sich nachlesen.

          Viele Grüße,
          Daniel Bradler

      2. Hi!

        close impliziert ein unlock. Es ist aus gewissen Gruenden mehr als ratsam, dass flock(LOGFILE, 8) wegzulassen.

        Sagst Du uns auch, aus *welchen* Gruenden?

        Calocybe

  4. xallo forumers

    wieso mit Fachbegriffen und inkompatiblen Implementierungen herumfuchteln, wenn es doch saueinfach geht? <g>

    Programmablauf der entsprechenden Perl-Datei:

    -----
    1. Überprüfen, ob tmp-Datei existiert. Wenn nicht, weitermachen, sonst Warteschleife mit wiederholter Überprüfung.
    2. SOFORT die Umbenenn-Aktion starten, damit die tmp auch SOFORT vorhanden ist.
    ...
    100. Die tmp-Datei KOPIEREN!
    101. Wenn Vorgang beendet, tmp-Datei löschen.
    -----

    ich hoffe es hilft beim Implementieren <g>

    bis nextens
    xitnalta