Webbasierte Adressdatenbank

File Locking, warum?
Wie wir in Webserver eine Einführung gesehen haben, können mehrere Anfragen an einen httpd zur gleichen Zeit gestellt werden. Dies bedeutet für unsere Adressdatenbank, daß z. B. ein Benutzer aus dem Datenfile liest, während ein anderer schreibend darauf zugreift. Mit an Sicherheit grenzender Wahrscheinlichkeit wird dies schief gehen, am Schluß bleibt ein zerstörtes Datenfile zurück. Wir müssen also Maßnahmen ergreifen um dieses Verhalten zu unterbinden, das sogenannte "file locking" oder flock.
Um ein flock erfolgreich durchzuführen, bedarf es allerdings der Ünterstützung des Betriebssystemes. Linux und Unix bieten diese Unterstützung, Windows nicht.

Wie wird ein File gelockt?
Locks gibt es in zwei Varianten, shared und exclusiv. Den shared Lock verwendet man normaler Weise zum Lesen. Ein so gelocktes File kann von weiteren Prozessen ebenso mit einem shared Lock versehen werden. Wenn man in eine Datei schreiben will, verwendet man den exclusiv Lock. Fordert ein weiterer Prozess einen exclusiv, oder shared Lock an, wird er kein Erfolg haben. D. h. der Prozess mit exclusiv Lock kann schreiben ohne das etws schief geht.
Allerdings funktioniert das Ganze nur, wenn alle Prozesse, die mit dem File arbeiten den Lock Mechanismus verwenden.

Beispiel locksh.pl

     1:  #!/usr/bin/perl -w
     2:
     3:  use strict;
     4:  use Fcntl qw/:flock/; # Importiert Lock Konstanten
     5:
     6:  my $dat_file = "daten.txt";
     7:  my $num;
     8:
     9:  open (DAT , "<$dat_file") || die "Kann file $dat_file: nicht öffnen: $!";
    10:
    11:  flock(DAT, LOCK_SH) || die "Fehler beim Locken: $!";
    12:  
    13:  print "File zum Lesen gelockt\n";
    14:  chomp($num = <DAT>);
    15:  print $num."\n";
    16:  sleep 15;
    17:
    18:  close(DAT) || die "Kann File $dat_file nicht schliesen: $!";
    19:
    20:  print "File unlocked!\n";
    

In der Zeile 4 importieren wir die Lock Konstanten aus dem Standard Modul  Fcntl . Nach dem Öffnen der Datei zum Lesen setzen wir den shared Lock in der Zeile 11. Ein explizites Unlock wird nicht durchgeführt, dies wird beim  close  in Zeile 18 automatisch gemacht. In Zeile 16 warten wir 15 Sekunden bis es weitergeht. Das gibt uns die Möglichkeit das Skript in einer weitern Shell erneut aufzurufen und zu sehen was passiert.

Beispiel lockex.pl

     1:  #!/usr/bin/perl -w
     2:
     3:  use strict;
     4:  use Fcntl qw/:flock/; # Importiert Lock Konstanten
     5:
     6:  my $dat_file = "daten.txt";
     7:  my $num;
     8:
     9:  open (DAT , "+<$dat_file") || die "Kann File $dat_file nicht öffnen: $!";
    10:  
    11:  flock (DAT, LOCK_EX|LOCK_NB) || &fehler(1);
    12:  flock (DAT, LOCK_EX) || &fehler(2);
    13:
    14:  print "File zum schreiben und lesen gelocked\n";	
    15:  chomp($num = <DAT>) || 0;
    16:  print $num."\n";
    17:  seek(DAT, 0, 0) || die "Kann nicht an den Anfang der Datei spulen: $!";
    18:  truncate(DAT, 0) || die "Kann File nicht abschneiden: $!";
    19;  print DAT $num+1, "\n";
    20:  sleep 15;
    21:  close(DAT) || die "Kann File $dat_file nicht schliesen: $!";
    22:  print "File unlocked!\n";
    23:  
    24:  sub fehler {
    25:      my $error = @_;
    26:      my %fehlertext = (1 => 'Kein sofortiger Schreib Lock möglich!',
    27:                        2 => 'Fehler beim Schreib Lock!');
    28:      print "$fehlertext{$error}\n";
    29:      exit;
    30:  }
    

Hier öffnen wir das File zum Lesen und Schreiben. In Zeile 11 versuchen wir zuerst einen nonblocking Lock, denn, wird ein exclusiv Lock gesetzt, und ein anderer Prozess versucht einen weiteren exclusiv Lock zu setzten muß der warten, bis der erste Lock aufgehoben ist. Der nonblocking Lock gibt uns die Möglichkeit in eine Fehlerroutine zu gelangen, falls der exclusiv Lock fehlschlägt. Dann Lesen wir eine Zeile des Files ein, "spulen zum Anfang der Datei" zurück (Zeile 17). Danach leeren wir das File (Zeile18), erhöhen den Zähler und schreiben ihn zurück. Auch hier löschen wir den Lock nicht explizit, da gegebenenfalls ja ein Schreibpuffer aktiv ist. Das würde dazu führen, daß ein anderer Prozess schreibt, bevor wir mit  close  den Schreibpuffer in die Datei schreiben.

Literaturhinweise:

Zurück zum Anfang dieses Projekts.