note 51338 added to function.flock
| From: | zmey at kmv dot ru | Date: | Mon, 28 Mar 2005 06:33:46 +0000 |
| Subject: | note 51338 added to function.flock | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-87073@lists.php.net to get a copy of this message | ||
2pentek_imre at mailbox dot hu:
flock() alone is not enough to handle race conditions, you will require the fseek() function too:
<?php
$f=fopen($filename,"a+") or die();
flock($f,LOCK_EX) or die();
// in case some other script has appended to the file while we were waiting on flock()...
fseek($f,0,SEEK_END);
//here write some lines to the file -- not included
//then close:
// flock($f,LOCK_UN) or die(); // fclose will remove all locks automatically
fclose($f) or die();
?>
But the problem with interrupted script under apache still cannot be addressed gracefully. If the
script is interrupted while writing to the file, the file's contents will get corrupt.
Temporary files are nice, but they do not guarantee that your information will not be lost. For
example:
<?php
// open file for read-write access
$f=fopen($filename,"r+");
flock($f,LOCK_EX) or die();
$ft=fopen($filename.(getmypid()),"w") or die();
//here we copy data from the locked file to temporary one, modifying it in the process
//then close temporary file:
fclose($ft) or die();
// Now we have two files: temporary file and locked source file.
// This trick works under *nix, but has some drawbacks.
// For Windows, we must first unlink the original file.
rename($filename.(getmypid()),$filename) or die();
// this will unlock the hidden, ex-original file under *nix, but will fail under win.
fclose($f) or die();
?>
Under *nix, this code works just fine, but still can lead to data loss. Look:
1. We lock the original file.
2. Another copy of the script tries to lock the file (say, to modify some other part of file). It
waits till we release the lock.
3. We make temporary file with modified data, and close it.
4. Rename succeeds, but in fact it works this way:
4.1 Original file's inode is marked as deleted, but the file is still on the disk because there
are open handles to it. The file will be actually deleted only after the last handle closes.
4.2 Temporary file's inode is corrected so that its name is the name of the original file.
What are the consequences? The second script, that was patiently waiting for us to unlock the file,
gets access to the file, BUT: the file is not the new, updated version! The script's handle
still points to the original file, although it is not accessible by any other program. So the script
happily processes the OLD version of the original file, and replaces the files once again. Voila -
the updates made by the first script are all lost!
Under Windows, we will not be able to rename the temporary file without unlinking the original file
first. Besides, we will not be able to unlink the file without unlocking it (Windows uses mandatory
locking)! So we will not be able to reliably replace the original file with the temporary one
without some trickery (e.g., use of external lock files).
----
Manual Page -- http://www.php.net/manual/en/function.flock.php
Edit -- http://master.php.net/manage/user-notes.php?action=edit+51338
Delete: added to the manual -- http://master.php.net/manage/user-notes.php?action=delete+51338&report=yes&reason=added+to+the+manual
Delete: bad code -- http://master.php.net/manage/user-notes.php?action=delete+51338&report=yes&reason=bad+code
Delete: spam -- http://master.php.net/manage/user-notes.php?action=delete+51338&report=yes&reason=spam
Delete: useless -- http://master.php.net/manage/user-notes.php?action=delete+51338&report=yes&reason=useless
Delete: other reasons -- http://master.php.net/manage/user-notes.php?action=delete+51338&report=yes
Reject -- http://master.php.net/manage/user-notes.php?action=reject+51338&report=yes
Search -- http://master.php.net/manage/user-notes.php