Erik Wagner: Testcode läuft nicht (flock-betreffend)... *kopfzerbrech*!

Hi!
Ich mach mich gerade daran in alle funktionen, die auf eine Datei zugreifen, lock-Routinen unter Verwendung von flock() einzubauen, dazu hab ich erstmal mit nem kleinen Testcode angefangen, aber irgendwie läufts nicht!
hier erstmal der Code:

open(COUNTER, "<../html/count.txt");
flock(COUNTER, 2);

$result = open(TESTFILE, ">../html/count.txt");
close(TESTFILE);
print $result;

close(COUNTER);
exit(0);

So, wenn ich das bisher alles richtig verstanden habe, liefert open(), wenn es auf eine mit LOCK_EX geflockte Datei stößt, FALSE zurück.
Das müsste doch eigentlich bedeuten, daß diese Zeile:

$result = open(TESTFILE, ">../html/count.txt");

dann verursachen müsste, daß in $result "0" drinsteht! Tut es aber nicht, sondern "1" und die Datei count.txt ist zum Schluss natürlich lehr.

Das ganze wird auf einem Linux-Server ausgeführt. Also entweder ich habe flock() nicht nicht ganz geblickt, oder... kann mir jemand helfen?

Seaz, Erik

  1. hi,

    soweit ich weiß ist flock lediglich eine freiwillige kontrolle.
    wenn du dann eine datei öffnest solltest du das so machen:
    open (blahblah)
    flock (blahblah, 1)
    mache irgendwas mit blahblah
    close (blahblah)

    an der flock stelle wird er dann merken "ah, ich hab keine berechtigung zum lesen" und das file nicht öffnen oder so..
    wie das ganze im einzelnen funzt weiß ich leider auch nicht, jedenfalls geht das so.

    danny

    1. wenn du dann eine datei öffnest solltest du das so machen:
      open (blahblah)
      flock (blahblah, 1)
      mache irgendwas mit blahblah
      close (blahblah)
      an der flock stelle wird er dann merken "ah, ich hab keine berechtigung zum lesen" und das file nicht öffnen oder so..

      Das ist doch das Problem, daß die flock-stelle erst kommt, NACHDEM die Datei bereits geöffnet wurde! Uns sobald ich eine Datei zum schreiben öffne is der Inhalt bereits weg! Was ich bräuchte ist etwas, um VOR dem Öffnen einer Datei zu prüfen ob diese geflockt ist!

      1. Hallo.

        Wenn eine mit flock gesperrte Datei nochmal gesperrt werden soll, wartet der zweite Prozess solange, bis die Daatei entsperrt wurde (passiert mit entspr. flock-Aufruf, close oder Script-Ende).
        Es gibt  - glaube ich - auch einen non-blocking-Mode, mit dem flock dann false zurückliefert, was der Prozess dann entspr. behandeln sollte. (Wenn das nicht geschieht, wird ganz normal weitergemacht und die Datei könnte zerschrotet werden, trotz flock).

        $result = open(TESTFILE, ">../html/count.txt");
        dann verursachen müsste, daß in $result "0" drinsteht! Tut es aber nicht, sondern "1" und die Datei count.txt ist zum Schluss natürlich lehr.

        Klar, das eigentliche Datei öffnen geht erst mal. Egal ob die Datei "geflockt" ist.

        Das ist doch das Problem, daß die flock-stelle erst kommt, NACHDEM die Datei bereits geöffnet wurde! Uns sobald ich eine Datei zum schreiben öffne is der Inhalt bereits weg! Was ich bräuchte ist etwas, um VOR dem Öffnen einer Datei zu prüfen ob diese geflockt ist!

        Das gibt es so in Perl leider nicht wirklich. Du könntest zwar spez. locking-Dateien anlegen (s. Archiv), aber das ist so eine Sache.
        Am besten wäre wohl:

        open (DATEI, "+<".$dateiname) die "Datei nicht geoeffnet! $!";
        flock (DATEI, $modus);
        seek (DATEI, 0,0);

        Damit wird die Datei zum Lesen und Schreiben geöffnet, aber nicht neu angelegt.
        (Script ungetestet, könnte auch "+>" sein)

        fs

        1. Erstmal danke für die Hilfe, aber es funktioniert alles nicht, weil es alles aus dem selben Prozess kommt. Ich hab jetzt mal was anderes gemacht und zwar 2 kleine Perlscripts. Das eine wartet mit sleep() nach dem öffnen und flocken der Datei ein paar Sekunden, daß zweite nicht! Ich starte beide fast gleichzeitig und nun hab ich den Fall, daß das passiert was eigentlich sein soll, nämlich das open() auf eine geflockte Datei stößt und solange wartet bis die Datei wieder freigegeben wurde.

          Mit anderen Worten stimmt das:

          Klar, das eigentliche Datei öffnen geht erst mal. Egal ob die Datei "geflockt" ist.

          nicht ganz...

          Naja, aber abgesehen davon, wenn das immer so wunderbar läuft, daß open() solange wartet bis die geflockte Datei freigegeben ist, ist ja alles ok, nur sehe ich dann so keine Möglichkeit ein timeout für open() festzusetzen...?

          ciao, Erik

          1. Naja, aber abgesehen davon, wenn das immer so wunderbar läuft, daß open() solange wartet bis die geflockte Datei freigegeben ist, ist ja alles ok, nur sehe ich dann so keine Möglichkeit ein timeout für open() festzusetzen...?

            Noch einmal zum Mitschreiben: flock ist ein "advisory lock". Du kannst eíne so gelockte Datei ohne Probleme oeffnen. open nimmt keine Ruecksicht darauf, ob eine Datei gelockt ist oder nicht.

            Peter

            1. Noch einmal zum Mitschreiben: flock ist ein "advisory lock". Du kannst eíne so gelockte Datei ohne Probleme oeffnen. open nimmt keine Ruecksicht darauf, ob eine Datei gelockt ist oder nicht.

              Hmm... das würde aber meinen gestrigen Beobachtungen wiedersprechen:

              Ich habe ein Script A welches eine Datei öffnet, flockt, mit sleep() 7 Sekunden wartet und die Datei dann wieder schließt!

              Dann habe ich ein Script B welches die SELBE Datei auch öffnet, flockt und sie sofort wieder schließt!

              Dann hatte ich 2 Browserfenster offen das eine mit Script A, daß andere mit Script B. Ich starte nun Script A einfach so, es dauert 7 Sekunden, dann ist das Script fertig. Ich starte das Script B, ist SOFORT fertig. Nun ich starte ich Script A, 1 Sekunde später starte ich Script B und Script B (welches ja sofort fertig sein sollte) wird auch erst dann fertig, wenn Script A fertig ist. Folglich hat open() darauf gewartet, daß die Datei freigegeben ist! Um dies zu testen habe ich den flock()-Vefehl aus Script A mal rausgenommen und siehe da, obwohl Script A die Datei noch geöffnet hatte war Script B wieder sofort fertig (hat also diesmal nicht gewartet.)

              Das open() solange wartet bis eine Datei freigegeben ist, steht übrigens auch im CGI-Tutorial und XWolf.com unter folgender URL:

              http://cgi.xwolf.com/faq/cgitutor4.shtml

              Zitat: "Wird eine Datei zum Schreiben geöffnet wird die Datei gelockt. Dies hat zur Folge, daß kein anderer Lesender oder Schreibender Prozess auf diese Datei zugreifen kann; Trifft ein open() auf eine gelockte Datei, wartet dieses so lange, bis die Datei geunlockt wurde und öffnet erst dann die Datei."

              Was ist denn nun richtig? Ich kann mir irgendwie nicht vorstellen, daß open() sich nicht um das flock() schert, weil flock() ja sonst völlig sinnlos wäre, da man ja nicht VOR dem Öffnen der Datei prüfen kann ob eine Datei geflockt ist (hat man mir jedenfalls gesagt) und wenn ich dann einfach eine Datei zum schreiben öffne, die geflockt ist und open() sich nicht drum kümmert, ist der Inhalt ja bereits nach dem öffnen weg, was bringt es mir also, wenn ich dann NACH dem open() prüfe ob die Datei geflockt ist???

              1. Hmm... das würde aber meinen gestrigen Beobachtungen wiedersprechen:

                Nein, Du interpretierst nur falsch!

                Ich habe ein Script A welches eine Datei öffnet, flockt, mit sleep() 7 Sekunden wartet und die Datei dann wieder schließt!

                Dann habe ich ein Script B welches die SELBE Datei auch öffnet, flockt und sie sofort wieder schließt!

                Dann hatte ich 2 Browserfenster offen das eine mit Script A, daß andere mit Script B. Ich starte nun Script A einfach so, es dauert 7 Sekunden, dann ist das Script fertig. Ich starte das Script B, ist SOFORT fertig. Nun ich starte ich Script A, 1 Sekunde später starte ich Script B und Script B (welches ja sofort fertig sein sollte) wird auch erst dann fertig, wenn Script A fertig ist. Folglich hat open() darauf gewartet, daß die Datei freigegeben ist!

                Trugschluss: flock hat gewartet.

                Um dies zu testen habe ich den flock()-Vefehl aus Script A mal rausgenommen und siehe da, obwohl Script A die Datei noch geöffnet hatte war Script B wieder sofort fertig (hat also diesmal nicht gewartet.)

                http://cgi.xwolf.com/faq/cgitutor4.shtml

                Zitat: "Wird eine Datei zum Schreiben geöffnet wird die Datei gelockt. Dies hat zur Folge, daß kein anderer Lesender oder Schreibender Prozess auf diese Datei zugreifen kann; Trifft ein open() auf eine gelockte Datei, wartet dieses so lange, bis die Datei geunlockt wurde und öffnet erst dann die Datei."

                Definitiv falsch. Der Autor hat offensichtlich keine Ahnung von der Materie, wenn er soetwas schreibt. RTFM: "man flock" oder deutlicher "perldoc perlopentut":

                File locking does not lock out another process that would
                       like to do I/O.  A file lock only locks out others trying
                       to get a lock, not processes trying to do I/O.  Because
                       locks are advisory, if one process uses locking and
                       another doesn't, all bets are off.

                flock ist eindeutig advisory und ein open stoert sich nicht daran. Wenn Du es immer noch nicht glauben willst, hier zwei Skripte:

                --------------------------------------------
                #!/usr/local/bin/perl

                script1.pl

                open S1, ">>/tmp/test" or die "/tmp/test";
                flock S1, 2;
                sleep 200;
                close S1;
                print "script1.pl: close() ausgefuehrt\n";
                ---------------------------------------------
                #!/usr/local/bin/perl

                script2.pl

                ++$;

                open S1, ">>/tmp/test" or die "/tmp/test";
                print "geoeffnet!\n";
                flock S1, 2;
                print "flock() beendet!\n";
                close S1;
                ---------------------------------------------

                Zur script1.pl auf der Kommandozeile starten mit:
                script1.pl &

                Dann script2.pl aufrufen. Sieh und staune!

                Was ist denn nun richtig? Ich kann mir irgendwie nicht vorstellen, daß open() sich nicht um das flock() schert, weil flock() ja sonst völlig sinnlos wäre, da man ja nicht VOR dem Öffnen der Datei prüfen kann ob eine Datei geflockt ist (hat man mir jedenfalls gesagt)

                Du brauchst das nicht zu pruefen. Und ob Du es dir vorstellen kannst oder nicht, flock ist dennoch sinnvoll.

                und wenn ich dann einfach eine Datei zum schreiben öffne, die geflockt ist und open() sich nicht drum kümmert, ist der Inhalt ja bereits nach dem öffnen weg, was bringt es mir also, wenn ich dann NACH dem open() prüfe ob die Datei geflockt ist???

                Wenn Du zum Ueberschreiben oeffnest, wird ueberschrieben. Wenn Du nicht zum Ueberschreiben oeffnest, wird nicht ueberschrieben. Oeffne deine Dateien also im anfuegend oder zum gleichzeitigen Lese- und Schreibzugriff (Stichwort '+<').

                Peter

                1. Jo, jetzt hab ichs verstanden, da hat der Kerl von Xwolf offensichtlich Blödsinn getextet, aber mir passt das alles irgendwie nicht so recht, ich glaube ich mach das ganze Fileflocking doch über flock-Dateien nach Cheatah's Methode a la datei.flock und das die Datei gelockt ist drückt sich dann einfach dadurch aus, daß die Datei nicht existiert! Dürfte einen ähnlichen Sicherheitsgrad wie flock() bieten...

                  Trotzdem Danke für die Aufklärung...

                  1. Jo, jetzt hab ichs verstanden, da hat der Kerl von Xwolf offensichtlich Blödsinn getextet, aber mir passt das alles irgendwie nicht so recht, ich glaube ich mach das ganze Fileflocking doch über flock-Dateien nach Cheatah's Methode a la datei.flock und das die Datei gelockt ist drückt sich dann einfach dadurch aus, daß die Datei nicht existiert! Dürfte einen ähnlichen Sicherheitsgrad wie flock() bieten...

                    Ich kenne Cheatah's Methode nicht. Wenn es etwas in der Art wie

                    while (-e 'datei.flock') {
                      sleep 1;
                    }
                    open LOCK, ">datei.flock";
                    close LOCK;
                    ...
                    unlink "datei.flock"

                    ist, dann ist flock auf jeden Fall vorzuziehen. Testen und Anlegen von datei.flock sind hier nicht atomar, daher kann es immer noch zu gleichzeitigen Zugriffen kommen. Das laesst sich vielleicht umgehen in dem man es so macht:

                    while (!mkdir '.lock') {
                      sleep 1;  # oder select oder sonstwas
                    }

                    Wenn die Datei bei einem unerwartetem Abbruch des Programm nicht geloescht wird, wird es natuerlich auch problematisch.

                    Soetwas ist ein Notnagel fuer Leute, die alberne Betriebssysteme einsetzen. Wenn flock() zur Verfuegung steht, sollte man es nutzen.

                    Peter

                    1. Ich kenne Cheatah's Methode nicht. Wenn es etwas in der Art wie

                      while (-e 'datei.flock') {
                        sleep 1;
                      }
                      open LOCK, ">datei.flock";
                      close LOCK;
                      ...
                      unlink "datei.flock"

                      ist, dann ist flock auf jeden Fall vorzuziehen. Testen und Anlegen von datei.flock sind hier nicht atomar, daher kann es immer noch zu gleichzeitigen Zugriffen kommen. Das laesst sich vielleicht umgehen in dem man es so macht:

                      Ich mach das andersrum! Die Datei ist dann gelockt, wenn die flock-Datei NICHT existiert, denn löschen kann man die flockdatei nur einmal, meine lock-Funktion schaut so aus:

                      sub lock
                      {
                        $timeout = 0;
                        my $flockfile = $_[0];
                        while($timeout <= 150)
                        {
                          if(-e "$flockfile")
                          {
                            if(unlink($flockfile) == false)
                            {select(undef, undef, undef, 0.1); $timeout++;}
                            else
                            {return 1;}
                          }else{
                            {select(undef, undef, undef, 0.1); $timeout++;}
                          }
                        }
                        return 0;
                      }

                      mit anderen Worten, wenn die flock-Datei existiert läuft zu dem Zeitpunkt kein Prozess der auf die dadurch zu sichernde Datei zugreift. Sollte zwischen der Abfrage ob die Datei existiert und dem Löschbefehl, die Datei bereits durch einen anderen Prozess gelöscht worden sein, wird das auch nochmal geprüft, die Grauzone dazwischen ist dann so gering, daß da nicht viel schiefgehen dürfte.

                      Das einzige was mich persönlich dabei wirklich stört ist die Sache mit einem möglichen Script abbruch zwischen lock() und unlock(), so daß die flock-Datei nicht wieder erstellt wird und dadurch alle nachfolgenden Prozesse lahmliegen...

                      Hmmm... ich schlaf da nochmal drüber...

                      Ciao, Erik

                      1. Hi,

                        Ich mach das andersrum! Die Datei ist dann gelockt, wenn die flock-Datei NICHT existiert, denn löschen kann man die flockdatei nur einmal

                        Dasselbe macht dieses Forum hier auch. (Calocybe hat das eingebaut, glaube ich mich zu erinnern.)

                        Das einzige was mich persönlich dabei wirklich stört ist die Sache mit einem möglichen Script abbruch zwischen lock() und unlock(), so daß die flock-Datei nicht wieder erstellt wird und dadurch alle nachfolgenden Prozesse lahmliegen...

                        Das Forum-Poster-Skript macht erst mal <n> Sekunden Retry (und sleep()) mit Deiner Funktion - und maßt sich dann das Recht an, die Sperre aufzuheben. ;-)

                        mfG - Michael

                        1. Dasselbe macht dieses Forum hier auch. (Calocybe hat das eingebaut, glaube ich mich zu erinnern.)

                          na dann bin ich wenigstens nicht der einzige *g* der das so macht :)

                          Das Forum-Poster-Skript macht erst mal <n> Sekunden Retry (und sleep()) mit Deiner Funktion - und maßt sich dann das Recht an, die Sperre aufzuheben. ;-)

                          Hmm, So hatte ich auch erst gedacht, aber wenn wirklich viel Traffic ist und das Script mal ne Stunde so gut wie im Dauereinsatz ist, was mach ich dann? Wieviele Sekunden genau wartet denn das Forumsscript hier genau pro Versuch und wieviele Versuche macht es, weißt du das zufällig? Ansonsten, glaube ich ist meine selbstgeschriebene lock-funktion ausreichend für das Projekt (hier speziell geht es um ne Anmeldefunktion, welche Daten in einer Datei speichert), zumal ich noch einbauen werde, daß die Datenbank alle 5 Anmeldungen gesichert wird, ich glaube das sollte ausreichen... flock() schaue ich mir für die nächste größere Sache mal genauer an und kann den Ocde dann direkt darauf ausrichten...

                          Danke für die vielen Hinweise und Aufklärungen

                          Ciao, Erik

                          1. Hi,

                            Wieviele Sekunden genau wartet denn das Forumsscript hier genau pro Versuch und wieviele Versuche macht es, weißt du das zufällig?

                            10 Sekunden mit jeweils sleep(1) dazwischen.

                            Das Skript ist ja nur dann "im Einsatz", wenn es gerade das Auslösen eines Posting-Formulars (also das Speichern eines Postings) bearbeiten muß, und das ist nicht "pausenlos" der Fall. Das Füllen eines Posting-Formulars durch den Anwender findet außerhalb des kritischen Abschnitts statt.

                            mfG - Michael

                      2. if(-e "$flockfile")
                            {

                        Das Problem bleibt das gleiche (Stichwort race condition). Wenn zwei gleichzeitig, geht's in die Hose.

                        Peter

                        PS: Die Quotes sind uebrigens ueberfluessig.

                        1. Hallo Peter,

                          if(-e "$flockfile")
                              {
                          Das Problem bleibt das gleiche (Stichwort race condition). Wenn zwei gleichzeitig, geht's in die Hose.

                          naja, zunächst einmal geht es in den nächst tieferen Block. ;-)

                          Und dort kommt dann der nächste Versuch, nämlich das unlink(), welches nicht bei zwei simultanen Versuchen zweimal einen Returncode von 0 liefern sollte.
                          Damit wäre das mehrfache Betreten des kritischen Bereichs dann wohl erfolglich vermieden - oder?

                          mfG - Michael

                          1. naja, zunächst einmal geht es in den nächst tieferen Block. ;-)

                            Und dort kommt dann der nächste Versuch, nämlich das unlink(), welches nicht bei zwei simultanen Versuchen zweimal einen Returncode von 0 liefern sollte.
                            Damit wäre das mehrfache Betreten des kritischen Bereichs dann wohl erfolglich vermieden - oder?

                            Du hast recht.

                            Peter

                2. Tach,

                  Definitiv falsch. Der Autor hat offensichtlich keine Ahnung von der Materie, wenn er soetwas schreibt. RTFM: "man flock" oder deutlicher "perldoc perlopentut":

                  du solltest dich vor Pauschalurteilen hueten, wenn du aus dem Zusammenhang gerissene Zitate interpretierst.
                  Gelegentlich hilft es auch, mal nach links und rechts zu gucken.

                  n.d.p.

                  1. du solltest dich vor Pauschalurteilen hueten, wenn du aus dem Zusammenhang gerissene Zitate interpretierst.
                    Gelegentlich hilft es auch, mal nach links und rechts zu gucken.

                    Was soll ich denn da sehen? Ich habe mir das Original angesehen, und das ist *definitiv* Kappes, was der Autor schreibt.

                    Peter

                    1. Was soll ich denn da sehen? Ich habe mir das Original angesehen, und das ist *definitiv* Kappes, was der Autor schreibt.

                      dann solltest auch du lernen, Texte zu lesen und zu *verstehen*.

                      n.d.p.

                      1. Was soll ich denn da sehen? Ich habe mir das Original angesehen, und das ist *definitiv* Kappes, was der Autor schreibt.

                        dann solltest auch du lernen, Texte zu lesen und zu *verstehen*.

                        So, wie ist der Text denn zu verstehen? Hier steht - fuer mich -unmissverstaendlich: "Trifft ein open() auf eine gelockte Datei, wartet dieses so lange, bis die Datei geunlockt wurde und öffnet erst dann die Datei". Das ist definitv falsch, das Gegenteil ist der Fall. open stoert sich nicht im Mindesten daran, ob eine Datei gelockt ist. Die Aussage wird weder relativiert noch richtig gestellt.

                        *Du* verstehst offensichtlich nicht, meinst aber deinen Senf dazugeben zu muessen.

                        Peter

                        1. So, wie ist der Text denn zu verstehen?

                          Vor allem *im Zusammenhang*.

                          n.d.p.

                          1. Hallo n.d.,

                            ich fahre dir ja nun ungern in die Parade, aber drei mal ein  Statement ohne Erklaerung und fachlichen Inhalt, das muss doch wohl nicht sein. Es waere nett, wenn du jetzt mal konkret wuerdest...

                            Viele Gruesse
                              Kess

                            1. Hi Kess,

                              [...] aber drei mal ein  Statement ohne Erklaerung und fachlichen Inhalt, das muss doch wohl nicht sein. [...]

                              hast ja recht .-)

                              In bewusstem Artikel bezieht sich der Text auf ein Beispiel, welches dazusteht, der Text selbst dient "nur" als Erlaeuterung fuer Unbedarfte, und wenn man eben *nur* den Text zitiert und darueber herzieht, geht mir eben der Hut hoch.

                              cua

                              n.d.p.

                              1. Hi n.d.,

                                ah, siehste, ich kannte weder den Text, noch das Beispiel. Nun bin ich schlauer. Merci.

                                Viele Gruesse
                                  Kess

                                P.S. du bekommst morgen eine Mail von mir zu deiner Anfrage letztens .... wenn du noch magst.... heut pack ichs nicht mehr.

                              2. In bewusstem Artikel bezieht sich der Text auf ein Beispiel, welches dazusteht, der Text selbst dient "nur" als Erlaeuterung fuer Unbedarfte, und wenn man eben *nur* den Text zitiert und darueber herzieht, geht mir eben der Hut hoch.

                                Die Erklaerung ist und bleibt falsch! Das Gegenteil kannst Du offensichtlich nicht beweisen (wie auch?). Machst mich hier aber bloed von der Siete an. Du bist ein Troll!

                                Peter

        2. (Script ungetestet, könnte auch "+>" sein)

          Nein, das gibt es zwar auch, ist hier aber nicht sinnvoll. Siehe "perldoc -f open" und "perldoc perlopentut".

          Peter

  2. Ha! flock, mein Lieblingsbefehl nachdem ich mal 2 Tage lang versucht habe rauszufinden ob er auch auf Win2K funktioniert... wenn er auf Win2K und UNIX gleich funktioniert dann ist dein Fehler:

    open(COUNTER, "<../html/count.txt");
    flock(COUNTER, 2);
    $result = open(TESTFILE, ">../html/count.txt");
    flock(TESTFILE,2);  ### HIER!!!!
    close(TESTFILE);
    print $result;
    close(COUNTER);

    Ein open prueft nicht, ob eine Datei geflockt ist. Jedem open MUSS ein flock folgen. Da haelt das script dann an und wartet bis das vorherige flock aufgehoben wurde (durch flock(HANDLE,8) oder close).

    In deinem Beispiel wird die geflockte Datei also korrekt geoeffnet, und da dem open kein flock folgt auch wieder geschlossen. Daher das resultat 1.

    Wenn dem zweiten open ein flock folgen wuerde, haelt das script an, bis der erste prozess die datei wieder unflockt, in dem Bespiel passiert das aber nicht. Keine ahnung ob flock einen eingebauten timeout hat oder ob das script dann einfach haengen bleibt.

    ...wie gesagt, so laeufts auf Win2K...

    :o)