Skip to content

Commit 5a62176

Browse files
committed
Revert "Use atomic filesystem operations for cPanel::StateFile."
This reverts commit 13c0387. "we have code that fails when the file is changed out from under it"
1 parent 8c6d890 commit 5a62176

3 files changed

Lines changed: 36 additions & 234 deletions

File tree

Makefile.PL

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ my %WriteMakefileArgs = (
2424
"Fcntl" => 0,
2525
"File::Path" => 0,
2626
"File::Spec" => 0,
27-
"File::Temp" => 0,
2827
"Getopt::Long" => 0,
2928
"POSIX" => 0,
3029
"Scalar::Util" => 0,
@@ -41,12 +40,10 @@ my %WriteMakefileArgs = (
4140
"TEST_REQUIRES" => {
4241
"Carp" => 0,
4342
"Cwd" => 0,
44-
"File::Slurper" => 0,
43+
"File::Temp" => 0,
4544
"FindBin" => 0,
4645
"Test::Exception" => 0,
4746
"Test::More" => 0,
48-
"Time::HiRes" => 0,
49-
"autodie" => 0,
5047
"lib" => 0
5148
},
5249
"VERSION" => "0.901",
@@ -61,7 +58,6 @@ my %FallbackPrereqs = (
6158
"Cwd" => 0,
6259
"Fcntl" => 0,
6360
"File::Path" => 0,
64-
"File::Slurper" => 0,
6561
"File::Spec" => 0,
6662
"File::Temp" => 0,
6763
"FindBin" => 0,
@@ -73,10 +69,8 @@ my %FallbackPrereqs = (
7369
"Test::Exception" => 0,
7470
"Test::More" => 0,
7571
"Text::Wrap" => 0,
76-
"Time::HiRes" => 0,
7772
"Unix::PID" => "0.21",
7873
"YAML::Syck" => 0,
79-
"autodie" => 0,
8074
"base" => 0,
8175
"lib" => 0,
8276
"parent" => 0,

lib/cPanel/StateFile.pm

Lines changed: 35 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,12 @@ sub import {
183183
if ( $state_file->{file_handle} ) {
184184

185185
# TODO probably need to check for failure, but then what do I do?
186-
eval { flock $state_file->{file_handle}, 8; };
186+
eval {
187+
local $SIG{'ALRM'} = sub { die "flock 8 timeout\n"; };
188+
my $orig_alarm = alarm $state_file->{flock_timeout};
189+
flock $state_file->{file_handle}, 8;
190+
alarm $orig_alarm;
191+
};
187192
close $state_file->{file_handle};
188193
$state_file->{file_handle} = undef;
189194

@@ -217,58 +222,29 @@ sub import {
217222
return;
218223
}
219224

220-
#Tested directly because this is critical logic.
221225
sub _open {
222-
my ($self) = @_;
226+
my ( $self, $mode ) = @_;
223227
my $state_file = $self->{state_file};
224228
$state_file->throw('Cannot open state file inside a call_unlocked call.') unless defined $self->{lock_file};
225229

226-
OPEN_FLOCK: {
227-
sysopen( my $fh, $state_file->{file_name}, Fcntl::O_CREAT() | Fcntl::O_RDWR(), 0600 )
228-
or $state_file->throw("Unable to open state file '$state_file->{file_name}': $!");
229-
230-
$self->_flock_after_open($fh);
231-
232-
#We might have blocked on the flock() long enough for
233-
#another process to have rename()d over the file that
234-
#we just locked. So we need to ensure that the file we
235-
#have locked is the same file as $state_file.
236-
my $fh_inode = ( stat $fh )[1];
237-
my $path_inode = ( stat $state_file->{file_name} )[1];
238-
if ( $fh_inode != $path_inode ) {
239-
redo OPEN_FLOCK;
240-
}
241-
242-
$state_file->{file_handle} = $fh;
243-
}
244-
}
245-
246-
sub _flock_after_open {
247-
my ( $self, $fh ) = @_;
248-
249-
my $timed_out;
250-
230+
open my $fh, $mode, $state_file->{file_name}
231+
or $state_file->throw("Unable to open state file '$state_file->{file_name}': $!");
251232
eval {
252-
local $SIG{'ALRM'} = sub {
253-
$timed_out = 1;
254-
die "flock LOCK_EX timeout\n";
255-
};
256-
257-
my $orig_alarm = alarm $self->{state_file}{flock_timeout};
258-
flock $fh, Fcntl::LOCK_EX();
233+
local $SIG{'ALRM'} = sub { die "flock 2 timeout\n"; };
234+
my $orig_alarm = alarm $state_file->{flock_timeout};
235+
flock $fh, 2;
259236
alarm $orig_alarm;
260237
1;
261238
} or do {
262239
close($fh);
263-
264-
if ($timed_out) {
265-
$self->{state_file}->throw("Guard timed out trying to lock state file “$self->{state_file}{flock_timeout}”.");
240+
if ( $@ eq "flock 2 timeout\n" ) {
241+
$state_file->throw('Guard timed out trying to open state file.');
242+
}
243+
else {
244+
$state_file->throw($@);
266245
}
267-
268-
$self->{state_file}->throw($@);
269246
};
270-
271-
return;
247+
$state_file->{file_handle} = $fh;
272248
}
273249

274250
sub update_file {
@@ -277,33 +253,26 @@ sub import {
277253
$state_file->throw('Cannot update_file inside a call_unlocked call.') unless defined $self->{lock_file};
278254

279255
if ( !$state_file->{file_handle} ) {
280-
$self->_open();
256+
if ( -e $state_file->{file_name} ) {
257+
$self->_open('+<');
258+
}
259+
else {
260+
sysopen( my $fh, $state_file->{file_name}, &Fcntl::O_CREAT | &Fcntl::O_EXCL | &Fcntl::O_RDWR )
261+
or $state_file->throw("Cannot create state file '$state_file->{file_name}': $!");
262+
$state_file->{file_handle} = $fh;
263+
}
281264
}
265+
seek( $state_file->{file_handle}, 0, 0 );
266+
truncate( $state_file->{file_handle}, 0 )
267+
or $state_file->throw("Unable to truncate the state file: $!");
282268

283-
#Set UNLINK in case we die().
284-
require File::Temp;
285-
my ( $fh, $path ) = File::Temp::tempfile( DIR => $self->{_file_dir}, UNLINK => 1 );
286-
287-
#We lock the temp file so that it’s “pre-locked”
288-
#when we rename() it into place below. That way the
289-
#production path stays consistently locked.
290-
$self->_flock_after_open($fh);
291-
292-
$state_file->{data_object}->save_to_cache($fh);
293-
294-
rename $path => $state_file->{file_name} or $state_file->throw("Failed to rename($path => $state_file->{file_name}: $!");
295-
296-
flock $state_file->{file_handle}, Fcntl::LOCK_UN();
297-
close $state_file->{file_handle};
298-
299-
@{$state_file}{ 'file_handle', 'file_size', 'file_mtime' } = (
300-
$fh,
301-
( stat $fh )[ 7, 9 ],
302-
);
269+
$state_file->{data_object}->save_to_cache( $state_file->{file_handle} );
270+
$state_file->{file_mtime} = ( stat( $state_file->{file_handle} ) )[9];
303271

304272
# Make certain we are at end of file.
305-
seek( $fh, 0, Fcntl::SEEK_END() ) or $state_file->throw("Unable to go to end of file “$state_file->{file_name}”: $!");
306-
273+
seek( $state_file->{file_handle}, 0, 2 )
274+
or $state_file->throw("Unable to go to end of file: $!");
275+
$state_file->{file_size} = tell( $state_file->{file_handle} );
307276
return;
308277
}
309278

@@ -461,7 +430,7 @@ sub import {
461430

462431
# File is newer or a different size
463432
$guard ||= cPanel::StateFile::Guard->new( { state => $self } );
464-
$guard->_open();
433+
$guard->_open('+<');
465434
$self->{data_object}->load_from_cache( $self->{file_handle} );
466435
( $self->{file_mtime}, $self->{file_size} ) = ( stat( $self->{file_handle} ) )[ 9, 7 ];
467436
}

t/statefile_lock_replace.t

Lines changed: 0 additions & 161 deletions
This file was deleted.

0 commit comments

Comments
 (0)