File Coverage

blib/lib/ExclusiveLock/Guard.pm
Criterion Covered Total %
statement 48 70 68.5
branch 20 38 52.6
condition 3 11 27.2
subroutine 8 9 88.8
pod 0 3 0.0
total 79 131 60.3


line stmt bran cond sub pod time code
1             package ExclusiveLock::Guard;
2 6     6   280515 use strict;
  6         15  
  6         200  
3 6     6   32 use warnings;
  6         7  
  6         272  
4             our $VERSION = '0.07';
5              
6 6     6   931 use Errno qw(EWOULDBLOCK);
  6         1356  
  6         809  
7 6     6   31 use Fcntl qw(LOCK_EX LOCK_NB LOCK_UN);
  6         6  
  6         268  
8 6     6   5368 use File::stat;
  6         46897  
  6         38  
9              
10             my $ERRSTR;
11              
12 0     0 0 0 sub errstr { $ERRSTR }
13              
14             sub new {
15 6     6 0 3007996 my($class, $filename, %args) = @_;
16 6   50     180 my $retry_count = $args{retry_count} || 5;
17              
18 6         45 my $fh;
19 6         46 my $count = 0;
20 6         26 my $is_locked = 1;
21 6         28 while (1) {
22 6         21 $ERRSTR = undef;
23 6         15 $is_locked = 1;
24 6 50       938 unless (open $fh, '>', $filename) {
25 0         0 $ERRSTR = "failed to open file:$filename:$!";
26 0         0 return;
27             }
28 6 100       44 if ($args{nonblocking}) {
29 2 100       43 unless (flock $fh, LOCK_EX | LOCK_NB) {
30 1 50       17 if ($! != EWOULDBLOCK) {
31 0         0 $ERRSTR = "failed to flock file:$filename:$!";
32 0         0 return;
33             }
34 1         4 $is_locked = 0;
35             }
36             } else {
37 4 50       90 unless (flock $fh, LOCK_EX) {
38 0         0 $ERRSTR = "failed to flock file:$filename:$!";
39 0         0 return;
40             }
41             }
42 6 50 33     326 unless (-f $filename && stat($fh)->ino == do { my $s = stat($filename); $s ? $s->ino : -1 }) {
  6 50       1823  
  6         759  
43 0 0       0 unless (flock $fh, LOCK_UN) {
44 0         0 $ERRSTR = "failed to unlock flock file:$filename:$!";
45 0         0 return;
46             }
47 0 0       0 unless (close $fh) {
48 0         0 $ERRSTR = "failed to close file:$filename:$!";
49 0         0 return;
50             }
51 0 0 0     0 if ($retry_count && ++$count > $retry_count) {
52 0         0 $ERRSTR = "give up! $retry_count times retry to lock.";
53 0         0 return;
54             }
55 0         0 next;
56             }
57 6         387 last;
58             }
59              
60             bless {
61 6         115 filename => $filename,
62             fh => $fh,
63             is_locked => $is_locked,
64             }, $class;
65             }
66              
67 3     3 0 38 sub is_locked { $_[0]->{is_locked} }
68              
69             sub DESTROY {
70 6     6   2246328 my $self = shift;
71 6 100       897 return unless $self->{is_locked};
72              
73 5         112 my $fh = delete $self->{fh};
74 5         75 my $filename = delete $self->{filename};
75 5 50       235 unless (close $fh) {
76 0         0 warn "failed to close file:$filename:$!";
77 0         0 return;
78             }
79              
80             # try unlink lock file
81 5 50       657 if (open my $unlink_fh, '<', $filename) { # else is unlinked lock file by another process?
82             # A
83 5 100       509 if (flock $unlink_fh, LOCK_EX | LOCK_NB) { # else is locked the file by another process
84 4 50 33     351 if (-f $filename && stat($unlink_fh)->ino == do { my $s = stat($filename); $s ? $s->ino : -1 }) { # else is unlink and create file by another process in the A timing
  4 50       905  
  4         679  
85 4 50       402 unless (unlink $filename) {
86 0         0 warn "failed to unlink file:$filename:$!";
87             }
88 4 50       56 unless (flock $unlink_fh, LOCK_UN) {
89 0         0 warn "failed to unlock flock file:$filename:$!";
90             }
91 4 50       279 unless (close $unlink_fh) {
92 0           warn "failed to close file:$filename:$!";
93             }
94             }
95             }
96             }
97             }
98              
99             1;
100             __END__