opi: Paralleler Schreibzugriff auf eine Datei ohne flock

Hallo zusammen,

ist ein paralleler Schreibzugriff auf eine Datei problemlos möglich?

Ich habe ca. 40-200 Prozesse, die sich in einer Datei registrieren
sollen. Die Datei hat einen strukturierten Aufbau:

--------------------------------------------------------------
| 30 Zeichen       | 50 Zeichen                 | 6 Zeichen  |
--------------------------------------------------------------
| Alias            | verschiedene Parameter     | Prozess ID |
--------------------------------------------------------------

Jeder Alias ist einzigartig.

Jeder Prozess soll seinen Eintrag in kurzen Intervallen aktualisieren.
Wenn der Prozess noch nicht existiert, dann hängt er sich mittels
O_APPEND hinten dran.

Nun möchte ich die Datei _nicht_ locken, damit es zu keinen Warte-
zuständen kommt. Kann die Datei fehlerhaft geschrieben werden, wenn
die Prozesse gleichzeit nur die Zeile aktualisieren, in der sie
registriert sind?

Worauf muss ich bei meinem Vorhaben insbesondere achten?

Für Hilfe wäre ich dankbar.

Greez,
opi

--
Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
  1. hallo,

    ist ein paralleler Schreibzugriff auf eine Datei problemlos möglich?

    Möglich ist es, aber nicht problemlos und auch nicht ratsam.

    Kann die Datei fehlerhaft geschrieben werden, wenn
    die Prozesse gleichzeit nur die Zeile aktualisieren, in der sie
    registriert sind?

    Genau das ist ist es meines Wissens, weshalb du keinen solchen "Verzicht" anstreben solltest. Der mögliche Zeitverlust, wenn die Prozesse aufeinander warten müssen, ist minimal.

    Grüße aus Berlin

    Christoph S.

    --
    Visitenkarte
    http://www.christoph-schnauss.de
    ss:| zu:) ls:& fo:) va:) sh:| rl:|
    1. Hallo,

      hallo,

      ist ein paralleler Schreibzugriff auf eine Datei problemlos möglich?

      Möglich ist es, aber nicht problemlos und auch nicht ratsam.

      Warum nicht problemlos? Was könnte passieren?

      Kann die Datei fehlerhaft geschrieben werden, wenn
      die Prozesse gleichzeit nur die Zeile aktualisieren, in der sie
      registriert sind?

      Genau das ist es meines Wissens, weshalb du keinen solchen "Verzicht" anstreben solltest. Der mögliche Zeitverlust, wenn die Prozesse aufeinander warten müssen, ist minimal.

      Ich habe das mal getestet und konnte keine Fehler entdecken, was
      nicht heißt, dass es doch schief gehen könnte. Aber ich würde gerne
      wissen was das sein könnte.

      Mein Skript (parallel.pl):

        
      #!/usr/bin/perl  
        
      use strict;  
      use warnings;  
      use Fcntl qw(:DEFAULT :flock);  
        
      my $arg = "@ARGV";  
        
      die "Usage: $0 <zeile x>\n" unless $arg =~ /^zeile \d$/;  
        
      for (my $i=0 ; $i < 1000000 ; $i++) {  
        
         my $uptime = <F> if open(F,'<',"/proc/uptime") or die $!;  
         $uptime =~ s/\..*$//;  
         chomp($uptime);  
        
         sysopen(FILE,"./testdatei",O_RDWR) or die $!;  
        
         my $index   = [];  
         my $int     = 0;  
        
         while (<FILE>) {  
            my $line = $_;  
            $index->[$int] = tell(FILE);  
            if ( $line =~ /^#/ ) {  
               $int++;  
               next;  
            }  
            (my $col1 = substr($line,0,10))  =~ s/\s+$//;  
            (my $col2 = substr($line,10,10)) =~ s/\s+$//;  
            (my $col3 = substr($line,20,10)) =~ s/\s+$//;  
            if ($col1 eq $arg) {  
               $int--;  
               $col2++;  
               seek(FILE,$index->[$int],0);  
               printf FILE '%-10s', $col1;  
               printf FILE '%-10s', $col2;  
               printf FILE '%-10s', $uptime;  
               last;  
            }  
            $int++;  
         }  
        
         close FILE;  
      }  
      
      

      Meine Datendatei (testdatei) vor dem Start:

      #12345678901234567890123456789
      zeile 1   0         uptime
      zeile 2   0         uptime
      zeile 3   0         uptime
      zeile 4   0         uptime
      zeile 5   0         uptime

      So schaute die Datei beim Start aus.

      Dann habe ich die Prozesse gestartet:

      ./parallel.pl zeile 1 &
      ./parallel.pl zeile 2 &
      ./parallel.pl zeile 3 &
      ./parallel.pl zeile 4 &
      ./parallel.pl zeile 5 &

      Meine Datendatei danach:

      #12345678901234567890123456789
      zeile 1   1000000   21277
      zeile 2   1000000   21319
      zeile 3   1000000   21281
      zeile 4   1000000   21333
      zeile 5   1000000   21338

      Greez,
      opi

      --
      Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
      1. hallo,

        ist ein paralleler Schreibzugriff auf eine Datei problemlos möglich?
        Möglich ist es, aber nicht problemlos und auch nicht ratsam.
        Warum nicht problemlos? Was könnte passieren?

        Wenn zwei (oder mehr) Prozesse gleichzeitig schreibend auf ein und dieselbe Datei zugreifen, kann es passieren, daß sie ihre Eingaben gegenseitig überschreiben. flock soll genau das verhindern.

        use Fcntl qw(:DEFAULT :flock);

        Hier hast du zwar das richtige Modul angesprochen, aber im Script passiert dann nichts.

        sysopen(FILE,"./testdatei",O_RDWR) or die $!;

        Ups. Warum nimmst du sysopen?

        Grüße aus Berlin

        Christoph S.

        --
        Visitenkarte
        http://www.christoph-schnauss.de
        ss:| zu:) ls:& fo:) va:) sh:| rl:|
        1. Hallo Christoph,

          Wenn zwei (oder mehr) Prozesse gleichzeitig schreibend auf ein und dieselbe Datei zugreifen, kann es passieren, daß sie ihre Eingaben gegenseitig überschreiben. flock soll genau das verhindern.

          das kann ich nicht ganz nachvollziehen. Wie sollen sie sich
          gegenseitig überschreiben, wenn sie völlig andere Zeilen bearbeiten
          und sich beim überschreiben an feste Konventionen halten wie zum
          Beispiel eine feste Spaltenlänge?

          Datenbankprozesse warten auch nicht aufeinander, wenn sie 100 GB
          große Datendateien bearbeiten. Oder doch?

          use Fcntl qw(:DEFAULT :flock);

          Hier hast du zwar das richtige Modul angesprochen, aber im Script passiert dann nichts.

          Natürlich passiert was. Mittels sysopen wird die Datei ./testdatei
          im Lese- und Schreibmodus mit O_RDWR geöffnet.

          sysopen(FILE,"./testdatei",O_RDWR) or die $!;

          Ups. Warum nimmst du sysopen?

          Der Lockmechanismus kann nur einwandfrei funktionieren, wenn ich ihn
          in all meinen Perlskripts einsetze. Hier locke ich zwar nichts, aber
          es ist halt mein Standardmodul zum Öffnen von Dateien.

          Greez,
          opi

          --
          Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
          1. hallo,

            Wenn zwei (oder mehr) Prozesse gleichzeitig schreibend auf ein und dieselbe Datei zugreifen, kann es passieren, daß sie ihre Eingaben gegenseitig überschreiben. flock soll genau das verhindern.
            das kann ich nicht ganz nachvollziehen.

            Auf einem Einzelrechner ist das auch kaum nachvollziehbar. Rufe mal dein Script über zwei verschiedene virtuelle hosts gleichzeitig auf, oder wenn du kannst, gleichzeitig über zwei oder mehrere Netzwerkrechner. Du könntest auch mal in SELFHTML nachlesen.

            use Fcntl qw(:DEFAULT :flock);
            Hier hast du zwar das richtige Modul angesprochen, aber im Script passiert dann nichts.
            Natürlich passiert was. Mittels sysopen wird die Datei ./testdatei
            im Lese- und Schreibmodus mit O_RDWR geöffnet.

            Das war nicht gemeint. Du hast kein LOCK im Script stehen.

            Der Lockmechanismus kann nur einwandfrei funktionieren, wenn ich ihn
            in all meinen Perlskripts einsetze.

            Das verstehe ich nicht. Spielt aber keine Rolle.

            Grüße aus Berlin

            Christoph S.

            --
            Visitenkarte
            http://www.christoph-schnauss.de
            ss:| zu:) ls:& fo:) va:) sh:| rl:|
            1. Hallo Christoph,

              Auf einem Einzelrechner ist das auch kaum nachvollziehbar. Rufe mal dein Script über zwei verschiedene virtuelle hosts gleichzeitig auf, oder wenn du kannst, gleichzeitig über zwei oder mehrere Netzwerkrechner. Du könntest auch mal in SELFHTML nachlesen.

              es ist ganz egal, von wo aus auf die Datei zugegriffen wird, da
              jeder Prozess, egal von wo aus er auf die Datei zugreift, eine
              eigene Zeile besitzt, in der er registriert ist. Nur auf diese
              eine Zeile greift er zu. Nur diese eine Zeile wird von ihm
              bearbeitet.

              use Fcntl qw(:DEFAULT :flock);
              Hier hast du zwar das richtige Modul angesprochen, aber im Script passiert dann nichts.
              Natürlich passiert was. Mittels sysopen wird die Datei ./testdatei
              im Lese- und Schreibmodus mit O_RDWR geöffnet.

              Das war nicht gemeint. Du hast kein LOCK im Script stehen.

              Das muss ich doch auch nicht. Ohne den Lockmechanismus machen
              open und sysopen eigentlich das Gleiche.

              open                   sysopen
              ---------------------------------------------
                <            O_RDONLY
                >            O_WRONLY | O_TRUNC | O_CREAT
                >>           O_WRONLY | O_APPEND

              Jede der beiden Funktionen kann etwas, was die andere nicht kann.
              Ich bevorzuge die "Features" von sysopen.

              Der Lockmechanismus kann nur einwandfrei funktionieren, wenn ich ihn
              in all meinen Perlskripts einsetze.

              Das verstehe ich nicht. Spielt aber keine Rolle.

              Aber ich erkläre es dir gerne. Was nützt es, in einem Perlskript
              eine Datei mit

              sysopen(FILE,$file,O_RDWR);
                   flock(FILE,LOCK_EX);

              zu öffnen, wenn ich in einem anderen Perlkript auf die gleiche Datei
              mittels

              open(FILE,'>>',$file);

              zugreife. open interessiert es nicht, ob die Datei gelockt ist.
              Aus diesem Grund nutze ich in meiner gesamten Umgebung den flock-
              Mechanismus. Nur so kann ich sicherstellen, das sich keine Skripts
              in den Weg kommen.

              Und das ich sysopen statt open in meinem Beispiel eingesetzt habe
              liegt einfach daran, weil ich immer sysopen statt open nutze.

              Ich kann mir aber noch immer nicht vorstellen, weshalb sich mehrere
              Prozesse, die alle eine andere Zeile bearbeiten, in die Quere kommen
              sollten.

              Greez,
              opi

              --
              Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
  2. Hi,

    ist ein paralleler Schreibzugriff auf eine Datei problemlos möglich?

    Das fordert doch geradezu eine Antwort im Stile Radio Eriwans heraus: im Prinzip nicht, aber ...

    Ich habe ca. 40-200 Prozesse,

    Hier wird nur zwischen "Einer" und "Mehrere" unterschieden, denn sobald es mehr als ein paralleler Zugiff ist, faengt der Aerger an.

    die sich in einer Datei registrieren
    sollen. Die Datei hat einen strukturierten Aufbau:

    So, da waeren wir ja schon beim "aber" von oben.


    | 30 Zeichen       | 50 Zeichen                 | 6 Zeichen  |

    | Alias            | verschiedene Parameter     | Prozess ID |

    Jeder Alias ist einzigartig.

    Kannst Du das garantieren?
    Wenn Du das auch noch ueberpruefen kannst, brauchst Du tatsaechlich keinen Locking Mechanismus.

    Jeder Prozess soll seinen Eintrag in kurzen Intervallen aktualisieren.
    Wenn der Prozess noch nicht existiert, dann hängt er sich mittels
    O_APPEND hinten dran.

    Was meint Prozess? Ein regulaerer Prozess? Der Alias ist dann die PID? Dann achte darauf, das Du einem evt Integeroverflow begegnest, denn wenn die PIDs am Ende angelangt sind, fangen sie evt wieder von vorne an.
    Es gibt aber auch nur einen dokumentierten Fall, ist also _sehr_ unwahrscheinlich ;-)

    Nun möchte ich die Datei _nicht_ locken, damit es zu keinen Warte-
    zuständen kommt.

    Das ist nun wirklich kein Grund! Das lineare Suchen in der Datei nach dem passendem Eintrag dauert mit Sicherheit laenger als ein Locking fuer das Einsortieren! ;-)
    Aber Datei-Locking ist nicht sehr einfach und in den raren Faellen wenn es vermieden werden kann, sollte es auch vermieden werden. KISS ("Keep It Simmple, Stupid!") ist ein gutes Prinzip.

    Kann die Datei fehlerhaft geschrieben werden, wenn
    die Prozesse gleichzeit nur die Zeile aktualisieren, in der sie
    registriert sind?

    Wie gesagt: wenn Du dafuer Sorge tragen kannst, das sie wirklich nur die eine Zeile beharken und sich ansonsten nicht gegenseitig in's Gehege kommen sehe ich da keine Probleme.

    Worauf muss ich bei meinem Vorhaben insbesondere achten?

    Das Du hier nicht testen kannst, denn es ist durchaus moeglich, das sich die einzelnen Prozesse aus reinem Zufall nicht in's Gehege kommen (Du kannst halt nicht auf Fehler testen, nur auf Funktion), also muss schon das Design stimmen.

    so short

    Christoph Zurnieden

    1. Hallo Christoph,


      | 30 Zeichen       | 50 Zeichen                 | 6 Zeichen  |

      | Alias            | verschiedene Parameter     | Prozess ID |

      Jeder Alias ist einzigartig.

      Kannst Du das garantieren?
      Wenn Du das auch noch ueberpruefen kannst, brauchst Du tatsaechlich keinen Locking Mechanismus.

      oh ja. Der Alias setzt sich zusammen aus

      std_min_sec+pid+prozessname+ip_adresse

      das ganze noch zu einem Key generiert. Hier bediene ich mich der
      SHA2 Verschlüsselung, da ich schon eine fertige Funktion zum
      generieren von Passwörtern habe.

      Jeder Prozess soll seinen Eintrag in kurzen Intervallen aktualisieren.
      Wenn der Prozess noch nicht existiert, dann hängt er sich mittels
      O_APPEND hinten dran.

      Was meint Prozess? Ein regulaerer Prozess? Der Alias ist dann die PID? Dann achte darauf, das Du einem evt Integeroverflow begegnest, denn wenn die PIDs am Ende angelangt sind, fangen sie evt wieder von vorne an.

      siehe oben...

      Worauf muss ich bei meinem Vorhaben insbesondere achten?

      Das Du hier nicht testen kannst, denn es ist durchaus moeglich, das sich die einzelnen Prozesse aus reinem Zufall nicht in's Gehege kommen (Du kannst halt nicht auf Fehler testen, nur auf Funktion), also muss schon das Design stimmen.

      Das werde ich! DANKE :-)

      Greez,
      opi

      --
      Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
      1. Hi,

        Der Alias setzt sich zusammen aus

        std_min_sec+pid+prozessname+ip_adresse

        Du musst Dich hier auf das OS verlassen, aber das sollte keine Probleme geben. Irgendwann nutzt auch die schoenste Paranoia nix mehr ;-)

        das ganze noch zu einem Key generiert. Hier bediene ich mich der
        SHA2 Verschlüsselung,

        Hiermit erhoest Du die Chancen auf einen "Doppelfehler" wieder leicht.
        Ich hoere schon das Raunen:"Hae?", also kurz erklaert:
        Das Design des Alias ist gut, damit lassen sich bis zur Datumsumstellung 2038[1] sicher einzigartige Namen schaffen. Die Wahrscheinlichkeit zwei gleiche Namen zu erhalten ist also Null bei idealen Voraussetzungen (Das OS geht nach Vorschrift bei der Verteilung der PIDs). Wenn Du jedoch ein Hash erzeugst besteht immer eine Wahrscheinlichkkeit groesser Null, das zwei verschiedene Eingaben die gleiche Ausgabe erzeugen. Bei einem kryptographisch gutem Algorithms mit einer Ausgabelaenge von 128 Bit waeren das 1:2^80. Eine verdammt kleine Zahl, aber doch groesser als Null.

        Aber die Praktikabilitaet eine Hashes laesst das verschmerzen glaube ich ;-)

        Ein ordentlicher Programmierer prueft aber trotzdem nach dem Erzeugen und vor der ersten Nutzung, ob der Schluessel evt schon vorhanden ist. Es gibt ja auch noch andere Moeglichkeiten, das die Datei nicht mehr stimmt.

        DANKE :-)

        Ne Du, umarmen is' nich', hau bloss ab! ;-)

        so short

        Christoph Zurnieden

        [1] Du musst sowieso irgendwo begrenzen, ansonsten braeuchtest Du unendlich grosse Aliase und ein Zeitrahmen ist meist eine gute Beschraenkung, so auch hier.

        1. Hallo Christoph,

          Hiermit erhoest Du die Chancen auf einen "Doppelfehler" wieder leicht.
          Ich hoere schon das Raunen:"Hae?",

          da hast du allerdings recht! :-)

          also kurz erklaert:
          Das Design des Alias ist gut, damit lassen sich bis zur Datumsumstellung 2038[1] sicher einzigartige Namen schaffen. Die Wahrscheinlichkeit zwei gleiche Namen zu erhalten ist also Null bei idealen Voraussetzungen (Das OS geht nach Vorschrift bei der Verteilung der PIDs).

          und selbst wenn nicht ganz... ich glaube nicht, dass sich die
          PIDs innerhalb einer Sekunde überrunden. Ausserdem sind wir auf
          dem Weg zu 64bit Systemen. Bis 2038 vielleicht noch mehr... oder?

          Was ich natürlich auch machen könnte - als DBA hätte ich da eher
          drauf kommen können - kann ich mir doch eine Datei in Form einer
          Sequence erstellen. Jeder Prozess lockt kurzfristig und bedient sich
          der Zahl+1 und legt diese auch dort ab. Wenn es dann irgendwann Mal
          soweit ist und ich bei dem Ende eines Doublewertes angekommen bin,
          dann kann ich auch wieder bei 1 anfangen :-)

          Aber die Praktikabilitaet eine Hashes laesst das verschmerzen glaube ich ;-)

          Der Hash wird nicht von den Prozessen genutzt, sonder von einem
          anderen Prozess, der diese Datei ausliest.

          Ein ordentlicher Programmierer prueft aber trotzdem nach dem Erzeugen und vor der ersten Nutzung, ob der Schluessel evt schon vorhanden ist.

          Ja das prüfe ich. Mein Algorythmus war, solange den Key neu zu
          erzeugen bis er einzigartig ist.

          Ne Du, umarmen is' nich', hau bloss ab! ;-)

          Bin schon wech... nice Weekend! :-)

          Greez,
          opi

          --
          Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
          1. Hi,

            und selbst wenn nicht ganz... ich glaube nicht, dass sich die
            PIDs innerhalb einer Sekunde überrunden.

            Wir sind hier nicht in einem theologischem Seminar, das hat mit Glauben nix zu tun. Entweder weist Du etwas oder nicht. Das einzige, was "Glauben" nahe kommt, waere statistische Wahrscheinlichkeit, aber auch das ist reine Mathematik.

            Ausserdem sind wir auf
            dem Weg zu 64bit Systemen. Bis 2038 vielleicht noch mehr... oder?

            Das darf fuer das Design keine Rolle spielen, nur fuer die einzelnen Implementation. Der Zeitraum bezieht sich auch nur auf die moegliche maximale Gueltigkeitsdauer der Datei. Also ohne irgendeinen Neustart, Mainframelike.

            Was ich natürlich auch machen könnte - als DBA hätte ich da eher
            drauf kommen können - kann ich mir doch eine Datei in Form einer
            Sequence erstellen. Jeder Prozess lockt kurzfristig und bedient sich
            der Zahl+1 und legt diese auch dort ab. Wenn es dann irgendwann Mal
            soweit ist und ich bei dem Ende eines Doublewertes angekommen bin,
            dann kann ich auch wieder bei 1 anfangen :-)

            Nichst selber basteln, was es schon fertig gibt.
            Zudem holst Du Dir wirklich unnoetige Komplexitaet ohne irgendeinen GEwinn in's Haus. Lass es lieber, das Design ist gut wie es ist.

            Aber die Praktikabilitaet eine Hashes laesst das verschmerzen glaube ich ;-)

            Der Hash wird nicht von den Prozessen genutzt, sonder von einem
            anderen Prozess, der diese Datei ausliest.

            Auch das spielt keine Rolle beim Design, darf gar keine spielen.

            Ein ordentlicher Programmierer prueft aber trotzdem nach dem Erzeugen und vor der ersten Nutzung, ob der Schluessel evt schon vorhanden ist.

            Ja das prüfe ich. Mein Algorythmus war, solange den Key neu zu
            erzeugen bis er einzigartig ist.

            Das ist falsch.
            Der Algorithmus zur Erzeugung des Alias ist sicher.
            Wenn Du also einen doppelten Eintrag in der Datei findest, dann ist die Datei als korumpiert zu verwerfen und neu aufzubauen.
            BTW: es ist natuerlich dafuer Sorge zu tragen, das die Datei auch wirklich *from scratch* neu aufgebaut werden kann!

            so short

            Christoph Zurnieden

            1. Hallo Christoph,

              Was ich natürlich auch machen könnte - als DBA hätte ich da eher
              drauf kommen können - kann ich mir doch eine Datei in Form einer
              Sequence erstellen. Jeder Prozess lockt kurzfristig und bedient sich
              der Zahl+1 und legt diese auch dort ab. Wenn es dann irgendwann Mal
              soweit ist und ich bei dem Ende eines Doublewertes angekommen bin,
              dann kann ich auch wieder bei 1 anfangen :-)

              Nichst selber basteln, was es schon fertig gibt.
              Zudem holst Du Dir wirklich unnoetige Komplexitaet ohne irgendeinen GEwinn in's Haus. Lass es lieber, das Design ist gut wie es ist.

              Meinst du mein bisheriger Vorgang oder das es etwas in der Form
              von Sequences für Perl gibt?

              Greez,
              opi

              --
              Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
              1. Hi,

                Nichst selber basteln, was es schon fertig gibt.
                Zudem holst Du Dir wirklich unnoetige Komplexitaet ohne irgendeinen GEwinn in's Haus. Lass es lieber, das Design ist gut wie es ist.

                Meinst du mein bisheriger Vorgang oder das es etwas in der Form
                von Sequences für Perl gibt?

                Du hast Dein Teil schon fertig, warum willst Du das umbauen? Zudem wolltest Du Locking vermeiden und baust es so doch wieder ein. Etwas einfacheres als das Design, das Du jetzt hast duerfte schwer zu finden sein. Viel einfacher ist es, die Sache auf dem Weg ungewollt zu komplizieren, wie man ja sieht.
                Es kann hoechstens noch sein, das der Zweck, zu dem die Datei vorgehalten wird bei etwas anderem Design des Gesamtkunstwerkes wegfallen koennte. Aber ich kenne ja Dein Projekt nicht, kann nur das Detail beurteilen.
                Wenn Du es also einfacher haben willst frage Dich oder andere (meinetwegen die Leute hier) ob Dein Gesamtkonzept stimmig ist. Wenn das nicht korrekt ist nuetzt das schoenste Algorithmusoptimieren rein gar nix.

                so short

                Christoph Zurnieden