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