Tom: PHP: Generelles zum Thema File-Locking

Beitrag lesen

Hello,

Der richtige Link: http://twins.sumsebienchen.de/counter.zip

Ich möchte darauf hinweisen, dass die Locking-Strategie in diesem Script nicht greift:

flock($fp, 1);
fputs($fp, $file);
flock($fp, 3);
fclose($fp);

Es handelt sich bei diesen PHP-Funktionen um "advisory locking". Das bedeutet, dass in einer Tabelle ein Vermerk gesetzt wird, dass die Dateisperre nun bitte zu beachten ist. Die Beachtung der Dateisperre kann aber nur durch das Abfragen des Funktionsergebnisses von flock() wahrgenommen werden.

Die Funktion fputs() bekommt von ggf. tatsächlich angemeldeten Lock überhaupt nichts mit. Dazu müsste man mit "mandatory locks" ("HardLock") arbeiten.

Richtig wäre also:

for($lockcount = 0; $lockcount < 5; $lockcount++)
{
  if (@flock($fp, 1))   ## Fehlermeldung muss hier ausgeschaltet werden
  {
    fputs($fp, $file);
    flock($fp, 3);
    break;
  }
  else
  {
    # Fehlerbehandlung
  }
}

fclose($fp);

Außerdem ist das Locken an dieser Stelle zu spät, wenn die datei nur geschreiben wird. Beim Locking muss man generell sicherstellen, dass zwischen dem letzten eigenen Lesevorgang und dem eigenen Schreibvorgang kein weiterer Schreibvorgang stattgefunden hat. Das kann man auf drei Arten erreichen:

1. Man lockt von vor dem Lesen bis nach dem Schreiben exclusiv
   Das nennt man dann "pessimistic locking strategie"
   Diese methode lässt sich am einfachsten umsetzen.
   Beispiel: http://bitworks.de/~selfHTML/speichern.php

2. Man fügt einen "Conflict Counter" hinzu, der bei jedem Schreibvorgang
   um eins hochgezählt wird. Geschrieben werden darf aber nur, wenn sich
   der Conflict Counter seit dem letzten Lesen nicht verändert hat.
   Das bedeutet aber, dass man innerhalb des Locks den Zähler nochmals
   lesen muss. Nur wenn er sich seit dem lezten Lesen vor Beginn der
   Datenmanipulation bis jetzt nicht geändert hat, darf er um eins er-
   höht werden, und es wird weggeschrieben.
   Das nennt man dann "optimistic locking strategie", dam nan eigentlich
   davon ausgeht, dass der Conflict-Handler i.d.R. nicht anspricht. Diese
   Methode erfordert zwar eien zusätzliche Leseoperation, ist aber in
   Bezug auf paralleles Lesen von Datenbeständen performanter.

3. Man nutzt die "academic locking strategie".
   Hier wird jeder Veränderungswunsch von Daten damit eingeleitet, dass
   versucht wird, einen exclusiv Lock zu setzen. Hat dieser Erfolg, wird
   sofort auf "shrared read lock" zurückgenommen. So kann jede andere
   Applikation (jeder andere User) die Daten noch lesen, aber er erfährt
   beim eigenen Wunsch, die Daten zu verändern, dass dies im Moment nicht
   möglich ist, da er keinen exclusiv lock setzen kann, solange ein shared
   read lock gestzt ist. Den darf er nun aber auch selber nicht mehr setzen,
   da er damit verhindern würde, dass der erste User nach Abschluss seiner
   Manipulation für den kurzen Moment des Schreibvorganges aus exclusive
   lock "hochschaltet".

Dieses Verfahren funktioniert auch bestens mit mandatory locking und
   bietet dann die höchsate Datensicherheit.

Rein physisch ist eine Datei solange für andere Prozesse gesperrt, wie ein Prozess darauf zugreift. Da die Zugriffsdauern  sich aber im Millisekundenbereich bewegen, muss man schon einige Hundert Zugriffe pro Sekunde auslösen, um einen _physischen_ Konflikt herbeizuführen. Das hatte z.B. Sven Rautenberg in unserem Versuch mit dem Speichern-Script gemacht. Da ich die Datei nicht lesen konnte und den Grund des Nicht-Lesen-Könnens nicth abgefragt habe, (nur boolesch, keine Fehlernummer), hat meine Scriptinstanz die Daten neu initialisiert, da sie davon ausging, dass die Datei nicht vorhanden war. Wenn ich die Fehlernummer abgefragt hätte, wäre "Access denied" dabei herausgekommen, was etwas anderes ist als "File not found".

Soviel zum Arbeiten mit Locks und dem Sumsebienchen-Script.

Liebe Grüße aus http://www.braunschweig.de

Tom

--
Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen