Kozz has asked for the wisdom of the Perl Monks concerning the following question:
I just need a few more eyes to look at this code and help me determine just what in the world could possibly be going wrong here. this is a CGI script, by the way.
my $tempfile="/tmp/$$.tmp";
open(DBA, "+< $datafile") or die "Could not read $datafile: $!";
flock(DBA, 2);
seek(DBA, 0, 0);
open(TMPA, "+> $tempfile") or die "Could not open tempfile: $!";
flock(TMPA, 2) or die "ERROR: $!"; # it dies here?
seek(TMPA, 0, 0);
while(<DBA>){
# more code here, etc etc ...
Of course, this is only a small piece of a MUCH larger script I've already written.
I'm opening a datafile and comparing it to some user input,
and then opening a tempfile to write any lines that should
be preserved from DBA. Then I'd rewind both files and
write from TMPA to DBA and then truncate, and close.
Anyhow, the real problem comes in when I try to flock the
temp file. I've put debugging lines in the code with
messages that say things like "I've got this far" or
whatever, after each line. And it gets all the way up
to that flock call to the TMPA filehandle just fine. But if
I let the script try to execute that line, the browser just
sits there and hangs... like it's in a loop or something.
What might be happening here? The first flock call to the DBA filehandle works just fine. I'm pulling my hair out after staring at this code for over an hour now. Please help.
*sobs*
Re: More Eyes
by tye (Sage) on Aug 22, 2000 at 07:36 UTC
|
When flock() hangs and you haven't specified LOCK_NB, then it is very, very likely that another process holds a lock on that file and you are waiting for that lock to clear.
Since the file is named "/tmp/$$.tmp", I can't think what other process would be likely to hold a lock on it. Try the following:
use Fcntl qw( :flock );
#[...]
open(TMPA, "+> $tempfile")
or die "Could not open tempfile: $!";
flock(TMPA, LOCK_EX|LOCK_NB) or die "ERROR: $!";
FYI, saying "it dies here" makes it sound like the
"or die" is triggered and you see the value of $!.
-
tye
(but my friends call me "Tye") | [reply] [d/l] |
|
tye, Thanks for the input. I tried your suggestion, and when configured as you suggest, the flock dies with the message "Resource temporarily unavailable". Wow. What does that mean? I mean, it says what it says, yeah. But what does it really mean, in terms of flocking? It's quite strange. When I made a temp directory of my own "/home/username/htdocs/tmp" and made it chmod 777, it was able to flock just fine.
So is there an issue with flocking files which are not in your own userspace (i.e. /tmp or something), perhaps?
Update: Incidentally, I got this very same result with the script on two different machines: one running Slack 7, and the other running FreeBSD 3.1
Update 2: I just had to try the simplest version, so I did this:
#!/usr/bin/perl
use Fcntl qw( :flock );
my $tempfile="/tmp/$$.temp";
print "Content-type: text/html\n\n";
print "Testing flocking now.<BR>\n";
open(TMP, "+> $tempfile") or die "Could not open tempfile: $!";
flock(TMP, LOCK_EX|LOCK_NB) or die "no lock: $!";
seek(TMP, 0, 0);
print TMP "Blah blah blah"; # just to test
close(TMP);
unlink $tempfile;
print "That seemed to go just fine.\n";
And it ran just fine. Go figure. I'm quite puzzled.
| [reply] [d/l] |
|
Hmmm. Interesting, in some versions of Unix /tmp is held in memory I haven't access to your ?nixs but I wonder if that has a bearing on things?
| [reply] |
Re: More Eyes
by merlyn (Sage) on Aug 22, 2000 at 15:36 UTC
|
There is really no point in flocking a temp file that you've just destroyed. If someone
else was using it, too bad, you've just killed their data.
Once you've flocked the input file, are you now the only one that is doing the operation? If so, no more flocking is needed. Just create your temp file, and rename
over it, or whatever you were going to do at the end.
However, flocking a file you will be renaming over the top is a bit problematic.
I've posted other code here that shows a template for that at Exclusively updating a file that continues to be repeatedly read.
-- Randal L. Schwartz, Perl hacker | [reply] |
|
*laugh*
At the exact moment merlyn was noticing that you were
destroying the temp file on open, le and I were discussing
a problem that turned out to be his not being able to flock
a file he had destroyed on open.
With your original code change how you open the temp file
and see if that makes it work for you. If it does then I
definitely learned something interesting today. :-)
| [reply] |
Re(tilly) 1: More Eyes
by tilly (Archbishop) on Aug 22, 2000 at 06:14 UTC
|
Your code works for me, but instead of messing around in
/tmp yourself you should try installing File::Temp
and using that instead. | [reply] |
I must thank you all, and deeply apologize
by Kozz (Friar) on Aug 22, 2000 at 19:05 UTC
|
I should have taken tilly's suggestion from the VERY
start and used Temp::File. And now I feel quite
foolish, but perhaps a little bit wiser, and I must acknowledge my folly
to the Perlmonks who've endured me.
Especially since the solution which would solve this mystery
was in none of the pieces of code I posted here. I realized
that the original block of code I posted in the parent thread
was in a subroutine which had been called by ANOTHER subroutine,
and in THAT subroutine I had already opened and flocked a
tempfile which had been created moments ago with the exact
same naming scheme.
So the most obvious solution was invisible to me late at night: "The file exists, and that's why you can't get a lock on it, dumbass!"
Thankfully things were clearer in the morning. I feel sooo silly.
| [reply] |
RE: More Eyes, Please
by turnstep (Parson) on Aug 22, 2000 at 18:03 UTC
|
The original example uses:
open(DBA, "+< $datafile") ...
but the next 2 code examples use:
open(TMPA, "+> $tempfile") ...
Note the direction of the mode indicator - in the first
example, you are opening the file for read/write
access, or, to be specific, you are opening the file
for input, and want read/write access. In the next
examples, you are opening it for output (and clobbering
the contents in the process), and want read/write access.
The second is not very useful: if you have already opened
it for writing, and just set it to zero length, there
is nothing to read! If you are using flock, you
want to use the first example, so that any changes made
to the file (like, say, truncating it to 0 bytes) is
made *after* you have sucessfully flocked
the file. You could possibly use the second in cases where
you do not care about what is in the file, but merely
about whether it is locked or not (e.g. a semaphore).
| [reply] [d/l] [select] |
|
|