Tom: file-locking um konkurrierende Datei-Zugriffe zu regeln?

Beitrag lesen

Hello,

ich soll file-locking betreiben, um konkurrierende Zugriffe auf eine Datei, die auch immer überschrieben wird, zu vermeiden. Nun kann ich da aber in  PHP gar nichts zu finden. Außerdem dachte ich immer: wenn eine Datei geöffnet wird, ist sie automatisch für andere Benutzer gesperrt. Stimmt das nicht?

wie ist das konkret mit 'file()' und 'fopen()'?

Solange eine Dateioperation läuft, kann keine andere laufen. Allerdings muss man das "microskopisch" betrachten. Wenn mit file() Daten ausgelesen werden, wird das in Blöcken gemacht, da die gesamte Datei wahrschinlich nicht auf einmal in den IO-buffer passt (@CK... da war doch gerade was?). Zwischen diesen einzelnen Leseaufrufen von der Platte in den Puffer liegen nun zeitliche Lücken. Wenn die Datei also nicht für die Gesamtdauer aller Leseaufrufe für andere gesperrt wird, könnten Andere zwischendurch einen Schreibbefehl absetzen und dann würden sich ggf. beide Prozesse gegenseitig stören. Das liegt im Wesentlichen daran, dass die physischen "Puffergrenzen" nicht mit den logischen Satzgrenzen übereinstimmen.

Da ich den PHP-Programmierern viel Gutes zutraue, nehem ich mal an, dass während des Leseprozesses mit file() die Datei für andere gesperrt ist.

Das nütz uns aber nichts, wenn wir ein Update auf einen Bereich (Datensatz) in der Datei ausüben wollen. Dann müssten wir den gesamten Update-Prozess abschirmen.

Theoretisch würde das so aussehen.

1. Datei sperren
2. Datei öffnen
3. Datei lesen
4. Veränderung durchführen
5. Datei schreiben
6. Datei schließen
7. Datei entsprerren

PHP unterstützt aber in den normalen Filefunktionen kein mandatory Locking (google) sondern nur advisory Locking.

Beim mandatory Locking sind i.d.R der Sperr- und der Öffnungsprozess in einem Betriebssystemaufruf zusammengefasst. Das verhindert "Lücken" im zeitlichen Ablauf.

Beim advisory Locking haben Dateioperation (öffen, lesen, schreiben, schließen, Zeiger bewegen, abschneiden,...) und Locking nichts miteinander zu tun. Die einzige Verbindung zwischen diesen beiden getrennten Prozessen wird über das Dateihandle hergestellt.

Das Handle wird für das Lockung benutzt, um die Datei zu kennzeichnen. In einer separaten Tabelle wird eingetragen, welcher Prozess (User) gerade welche Lockingstufe für welche Datei wünscht. Wenn man also Dateioperationen durchführen will, muss man sich erst ein handle auf die Datei besorgen (fopen() ) und dann nachfragen, ob man ein Lock auf die Datei bekommen kann. Da dies nur beratende Wirkung hat, kann man trotzdem versuchen alle Dateioperationen durchzuführen. Vielleicht trifft man gerade eine "Lücke" und schon ist es passiert. Es müssen also alle Programme, die auf die gemeinsamen Dateien zugreifen, auch dieselben Regeln beachten.

Es gibt zwei aktive Locking-Stufen:

LOCK_SH: verhindert, dass jemand Anderes ein LOCK_EX bekommt
           wird nur ertielt, wenn kein LOCK_EX eines
           anderen Usersvorliegt
           ein vorhandenes LOCK_SH eines anderen Users
           stört nicht

LOCK_EX: verhindert, dass jemand anderes ein LOCK_SH
           oder LOCK_EX bekommt.
           wird nur erteilt, wenn überhaupt kein LOCK eines
           anderen Users vorlag. Ein eigenes LOCK_SH stört nicht.

Die einfachste Strategie ist es nun, zum ausschließlichen Lesen von Dateien immer ein LOCK_SH zu beantragen und wenn man auch Daten schreiben will, immer ein LOCK_EX zu beantragen.

Filehandle besorgen
  Datei EXCLUSIV sperren lassen
  Daten lesen
  Daten ändern
  Daten schreiben
  Datei schließen

Durch das Schließen wird das LOCK automatisch aufgehoben.
Der gesamte Prozess oben sollte so kompakt (also kurz) wie möglich gehalten werden.

Wie geht man nun vor, wenn man einen Datensatz ändern will?

Dies erfordert für den optimierten konkurrierenden Betrieb eine speziell angepasste Dateistruktur. In satzorientierten Dateien muss jeder Datensatz einen Konflikt-Zähler (oft reicht ein Timestamp) tragen.

Vorgangsbeschreibung

Handle besorgen
  Datei read-Lock
  Datei lesen
  datei schließen

Page mit Auswahlliste an den Client senden

Client fordert einzelnen Satz zum Lesen an

Handle besorgen
  Datei read-Lock
  Datei lesen (mit den aktuellen Timestamps)
  datei schließen

Einezldatensatz mit Formular an Client senden

Client führt Veränderungen durch und fordert Update an

Handle besorgen
  Datei Exclusive lock
  Datei lesen
  Datensatz raussuchen
  Timestamps vergleichen
  bei Gleichheit den Satz austauschen, Timestamp aktualisieren,
    OK setzen, bei Ungleichheit NotOK setzen und nichts machen

Daten zurückschreiben
  Datei schließen

OK:    dem Client die aktualisierte Auswahlliste schicken
  NotOK: dem Client den eigenen Datensatz UND den aktuellen aus der
         Datei in einem Doppelformular zurückschicken mit ZWEI submit-         Buttons. Der Client kann nun entscheiden, in welchem der beiden
         Vorlagen er seine Änderungen vornimmt. Beim Update wird aber
         auf jeden Fall der Timestamp des letzten gelesenen Satzes
         benutzt.

Das Verfahren nennt man "optimistic Locking", da man ersteinmal davon
  ausgeht, dass zwischen Lesen der Vorlagedaten und Rückschreiben nichts
  weiter passiert ist.

Es gibt auch das "pessimistic Locking". Hier wird ein Satz gezielt für
  die Veränderung angefordert und in diesem ein Merker gesetzt, welcher
  User gerade das Ändern angefordert hat. Solange dieser Merker nicht
  beseitigt wurde, kann kein anderer User den Satz bearbeiten.
  Bei HTTP ist dieses Verfahren nicht ohen weiteres verwendbar, da
  massenweise lost Flags entstehen könnten.

Die Funktion file() eignet sich alleine nicht zum Konkurrierenden Betrieb, da sie kein Handle liefert. Aber man kann einen Trick anwenden und ein seperates Lockfile verwenden. siehe hierzu http://selfhtml.bitworks.de "speichern". Das Lockfile kann eine Dummydatei sein oder auch eine mit Funktion, z.B. das LOG-File der Applikation.

ICh hoffe, ich kpnnte Dir helfen...

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

Tom

--
Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
Nur selber lernen macht schlau