in reply to Opening the same file over and over. Shorter way to do this?
I like the implementation using rename. On UNIX/Linux rename is atomic which means you have no race condition.
If you add sysopen with EXCL and CREAT on a temporary file with a fixed name then that call can only ever succeed if no one else is doing this update since O_EXCL | O_CREAT is atomic. If you can get all updaters, of which your program may be it, to use this convention you now have an atomic file open also. This eliminates the race condition in the original which would occur if someone grabs the lock and changes something between when you read and write. Now its locked for the entire critical section which allows only one updater to the file from the successful sysopen until the rename call. Readers will get either the entire old file or the entire new file with no chance of an inconsistent file. You could also choose to sleep a moment and retry the sysopen if you want an auto retry. Also you could have readers check for the temporary file also meaning they would wait until its gone to read but this has the problem of the updater dying leaving a lock effectively denying access to the old, yet consistent, file.
I have also lexicalized the variables I used so as not to pollute the global name space. this may even compile under use strict; Also, I am using lexical variables for my file handles $in and $out. These will close automatically when the function returns but they should be closed before the rename happens. You will need a recent Perl to do this (5.6 works and maybe a little earlier versions also) And I did a local on the $/ assignment so that $/ is left alone when I return back to my caller.
use Fcntl will get you the definitions of the O_ things. I am using write only (O_WRONLY) on the temp-file since I want to start at the top and go from there.
Here is my code snippet implementing the method described here.
use Fcntl; sub add { my($file, $domain_string)=@_; my $tempfile="Clever_but_constant_name_here"; my $in, $out; sysopen $out, "$tempfile", O_WRONLY|O_CREAT|O_EXCL or die "Tempora +ry file $tempfile exists"; open $in, "<$file" or die $!; local $/ = "\;\n\n"; my @array = <$in>; close $in; push @array, $domain_string; @array = sort @array; print $out @array; close $out; rename $tempfile, $file or die $!; }
Enjoy.
|
|---|