rzward has asked for the wisdom of the Perl Monks concerning the following question:
I have a CGI script that reads from and writes to a text file on the web server. Before reading or writing, the script uses flock to lock another file. The script is distributed with a program I sell and has been working on many different Unix, Linux and MS Windows web servers for years.
However, one customer discovered that on his Linux web server, the text file is consistently getting corrupted. I sent him a modified version of the script that tests the flock call and it seems flock always returns TRUE right away, even when the file it is trying to lock should still be locked by another user.
Below are two subroutines: LockFile and UnlockFile. LockFile creates a temporary file when it is asked to lock the file exclusively. UnlockFile deletes the temporary file.
For the purposes of this discussion, I simplified the functions a little. The script with the modified LockFile and UnlockFile subroutines has been tested on Linux and MS Windows web servers. On the customer's Linux web server, the LockFile subroutine consistently dies with the message "Acquired an exclusive lock for $flockPath but cannot create $fexistPath." It does not do this on any other web server that I have tested.
I thought there may be a problem with sysopen on the customers' web server. So, I added an alternative method to flock that used sysopen instead and it worked.
Even if the CGI script is run using the same process for each website visitor on the customer's web server, shouldn't flock wait until the lock is released before returning TRUE?
sub LockFile { local $path = $_[0] ; local $mode = $_[1] ; local $flockPath = $path . '.lck' ; local $flockFH = $flockPath ; open ($flockFH, ">$flockPath") or die ("Failed to open $flockPath") +; if (flock ($flockFH, $mode)) { use Fcntl ; local $fexistPath = $path . '.lck.tmp' ; if ($mode & LOCK_EX) { local $fexistFH = $fexistPath ; sysopen ($fexistFH, $fexistPath, O_WRONLY | O_CREAT | O_EXCL) or die ("Acquired an exclusive lock for $flockPath but cannot +create $fexistPath.") ; close $fexistFH ; } elsif (-e $fexistPath) { die ("Acquired a shared lock for $flockPath but found that $fexi +stPath exists.") ; } } else { die ("System Busy") ; } return ($flockFH, $path, $mode) ; } sub UnlockFile { use Fcntl ; local $fh = $_[0] ; local $path = $_[1] ; local $mode = $_[2] ; if ($mode & LOCK_EX) { local $fexistPath = $path . '.lck.tmp' ; unlink ($fexistPath) > 0 or die ("Failed to delete the lock file $ +fexistPath.") ; } close ($fh) ; }
For example, the subroutines would be called like:
local ($lockFH, $lockPath, $lockMode) = LockFile ("test.txt", 2); # Wait 10 seconds before calling UnlockFile UnlockFile ($lockFH, $lockPath, $lockMode);
Thank you in advance for your help.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: In a CGI script can flock return TRUE right away even if the file has already been locked?
by merlyn (Sage) on Feb 20, 2006 at 15:35 UTC | |
by rzward (Monk) on Feb 20, 2006 at 16:48 UTC |