
Mortimer
journeyman
Jun 6, 2001, 6:51 AM
Post #17 of 18
(1600 views)
|
#!/usr/bin/perl -w use strict; use Fcntl; use CGI qw( :fatalsToBrowser ); my $q = CGI->new(); print $q->header; my $hit_file = '/path/to/page.txt'; my $locked_flag = '/path/to/lock.txt'; my $flock_on = 'no'; my $waited_for = 0; my $timeout = 5; my $global = 1; #---------------------------------------------- if( &choose_lock( $flock_on, $locked_flag, $waited_for, $timeout ) ){ undef $/; my $content = <HFILE>; if( $global == 1 ){ $content =~ s/<head>.*?<\/head>//gs; } else{ $content =~ s/<head>.*?<\/head>//s; } seek( HFILE, 0, 0 ); truncate( HFILE, 0 ); print HFILE $content; if($flock_on eq 'no'){ sleep 3; unlink( $locked_flag ); print "Lock file deleted< br>"; close( HFILE ); } else{ close(HFILE); } } ### sub choose_lock{ my($flock_on,$locked_flag,$waited_for,$timeout) = @_; if( $flock_on eq 'no' ){ open( HFILE, "+<$hit_file" )or die( "Cannot open $hit_file: $!\n" ); &lock_f( $locked_flag, $waited_for, $timeout ); } else{ open( HFILE, "+<$hit_file" )or die( "Cannot open $hit_file: $!\n" ); flock( HFILE, 2 ); } } ### sub lock_f{ my( $locked_flag, $waited_for, $timeout ) = @_; if( eval{ sysopen( LFILE, $locked_flag, O_RDWR | O_EXCL | O_CREAT )or die( $! ) } ){ print LFILE "First: $$"; print "Try $waited_for - lock file created< br>"; close( LFILE ); } else{ if( $waited_for > $timeout ){ print "Cannot open $hit_file< br>"; return 0; exit; } else{ $waited_for++; sleep 1; &lock_f( $locked_flag, $waited_for, $timeout ); } } } #---------------------------------------------- Hello Marcus. I suppose I should have started a new thread for this because you're right about it not being relevant enough to patrik's original question. I suppose this issue had to come up. I don't think there is a way to make any alternative file lock 100% secure accross all platforms. But I can't accept that as a reason for not doing anything, or for not opening the file just once, and doing the whole lot in as shorter time as possible. At least our solutions go much further (depending on the number of processes started in a given time period) in securing data in files, but of course we should never abandon our backup systems! With my solution, the problem isn't that more than one process can create *the* lock file, more that they alternate (irregularly) in creating their own lock files, and deleting the other's. They can't do anything at the same time. I'm sure you've pictured scenarios such as where Process P1 comes along and sees there is no lock file (at the -e line). There's a pause while it gets ready to create a lock file. During this pause, before P1 can create it's lock file, P2 sees the absence of a lock file and also gets ready to create one...etc...and eventually they both do. So we have two (or maybe more) processes running with the rights to change the data file. I don't want to mention P3, and the fact that all the processes may have different workloads. The best solution is to have an os which supports flock() because apparently this can't happen. A similar thing would happen at the rename( $vote, $lock ) in your script. If two processes come along within an instance of acceptable time, they'll both be able to see that there is a $vote to rename, and so both will continue. I wouldn't use rename because (I've read) that this function behaves too differently accross platforms. However, I'm definitely not suggesting that creating a new lock file is a better option. To be honest, I don't know. Well anyway, I did a lot of searching, and a little reading around the net, and after hours of misery and frustration, I decided to have a go with IPC::ShareLite, a module (available from CPAN) that deals with shared segment space for variables. Before I started I emailed the author Maurice Aubrey to ask if he thought it would be suitable. He said yes, but didn't advise it because the semaphore calls should be used directly. He said to look at sysopen() and the Fcntl module. So I did and here's my revised script using sysopen(). The -e condition is out, and the data file update by a competing process now relies on sysopen() failing atomically when it is passed O_EXCL when the lock file already exists. Does this mean that the cpu time originally available between the -e test and the open is no longer a problem? Dunno! Cheers, Dave. www.dmscripts.com davemortimer@bigpond.com
|