note 51338 deleted from function.flock by danbrown

From: Date: Mon, 18 May 2009 00:43:17 +0000
Subject: note 51338 deleted from function.flock by danbrown
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-155419@lists.php.net to get a copy of this message
Note Submitter: zmey at kmv dot ru ---- 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).

« previous php.notes (#155419) next »