File Coverage

blib/lib/Log/Dispatch/FileRotate/Mutex.pm
Criterion Covered Total %
statement 42 50 84.0
branch 10 18 55.5
condition 4 8 50.0
subroutine 10 12 83.3
pod 4 4 100.0
total 70 92 76.0


line stmt bran cond sub pod time code
1             #
2             # This file is part of Log-Dispatch-FileRotate
3             #
4             # This software is copyright (c) 2005 by Mark Pfeiffer.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9              
10             package Log::Dispatch::FileRotate::Mutex;
11             $Log::Dispatch::FileRotate::Mutex::VERSION = '1.38';
12             # ABSTRACT: Flock Based File Mutex.
13              
14 8     8   59 use strict;
  8         20  
  8         275  
15 8     8   42 use warnings;
  8         19  
  8         267  
16 8     8   42 use Carp 'croak';
  8         14  
  8         430  
17              
18 8     8   3445 use Log::Dispatch::FileRotate::Flock qw(safe_flock flopen);
  8         75  
  8         504  
19 8     8   70 use Fcntl ':flock';
  8         18  
  8         4741  
20              
21             my $HAS_THREADS = $INC{'threads.pm'} ? 1 : 0;
22             my $THREAD_ID = $HAS_THREADS ? threads->tid() : 0;
23              
24             sub CLONE {
25 0 0   0   0 $THREAD_ID = threads->tid() if $HAS_THREADS;
26             }
27              
28             sub DESTROY {
29 0     0   0 my $self = shift;
30              
31 0         0 my $pid = $self->pid;
32              
33 0 0       0 if ($self->{$pid}) {
34 0         0 $self->unlock;
35 0         0 close(delete $self->{_fh});
36             }
37              
38 0         0 return;
39             }
40              
41              
42             sub new {
43 6     6 1 21 my ($class, $path, %args) = @_;
44              
45 6   33     37 $class = ref $class || $class;
46              
47 6         41 my $self = bless {
48             _path => $path,
49             %args
50             }, $class;
51              
52 6         83 return $self;
53             }
54              
55              
56             sub lock {
57 228     228 1 368 my $self = shift;
58              
59 228         421 my $pid = $self->pid;
60              
61 228 100 66     655 unless (exists $self->{$pid}) {
62             # we have not opened the lockfile in this thread.
63 6         38 my ($fh, $inode) = flopen($self->{_path});
64              
65 6         48 $self->_set_permissions;
66              
67 6 50       24 unless (defined $fh) {
68 0         0 return 0;
69             }
70              
71 6         17 $self->{_fh} = $fh;
72 6         15 $self->{_inode} = $inode;
73 6         18 $self->{$pid} = 1;
74             }
75             elsif ($self->{$pid} == 0) {
76             # file is open, but not locked.
77             if (safe_flock($self->{_fh}, LOCK_EX)) {
78             my ($inode) = (stat $self->{_path})[1];
79              
80             if ($inode != $self->{_inode}) {
81             # file was removed or changed underneath us, reopen instead
82             delete $self->{$pid};
83              
84             close(delete $self->{_fh});
85              
86             delete $self->{$pid};
87             delete $self->{_inode};
88              
89             return $self->lock;
90             }
91              
92             $self->{$pid} = 1;
93             }
94             }
95              
96             # otherwise this $pid is already holding the lock
97              
98 228   50     975 return $self->{$pid} || 0;
99             }
100              
101             sub _set_permissions {
102 6     6   15 my $self = shift;
103              
104 6 100       26 unless (defined $self->{permissions}) {
105 3         8 return;
106             }
107              
108 3         7 my $file = $self->{_path};
109              
110 3         37 my $current_mode = (stat $self->{_path})[2] & 07777;
111              
112 3 50       13 if ($current_mode ne $self->{permissions}) {
113             chmod $self->{permissions}, $self->{_path}
114             or croak sprintf 'Failed to chmod %s to %04o: %s',
115 3 50       75 $self->{_path}, $self->{permissions} & 07777, $!;
116             }
117             }
118              
119              
120             sub unlock {
121 228     228 1 395 my $self = shift;
122              
123 228         428 my $pid = $self->pid;
124              
125 228 100       595 if ($self->{$pid}) {
126 226         700 safe_flock($self->{_fh}, LOCK_UN);
127 226         1814 $self->{$pid} = 0;
128             }
129             }
130              
131              
132             sub pid {
133 456 50   456 1 1388 return $HAS_THREADS
134             ? join('.', $$, $THREAD_ID)
135             : $$;
136             }
137              
138             1;
139              
140             __END__
141              
142             =pod
143              
144             =encoding UTF-8
145              
146             =head1 NAME
147              
148             Log::Dispatch::FileRotate::Mutex - Flock Based File Mutex.
149              
150             =head1 VERSION
151              
152             version 1.38
153              
154             =head1 SYNOPSIS
155              
156             Internal Use Only!
157              
158             =head1 DESCRIPTION
159              
160             Internal Use Only!
161              
162             =head1 METHODS
163              
164             =head2 new($path)
165              
166             Create a new mutex for the given file path. Only one mutex per path should be
167             created. The path will not actually be opened or locked until you call L<lock>.
168              
169             =head2 lock()
170              
171             Obtains a lock on the path. If the thread id or pid has changed since the path
172             was opened, the path will be re-opened automatically in this thread or process.
173              
174             =head2 unlock()
175              
176             Releases the lock if the current thread or process is holding it.
177              
178             =head2 pid(): string
179              
180             Get the current process or thread id
181              
182             =head1 SOURCE
183              
184             The development version is on github at L<https://https://github.com/mschout/perl-log-dispatch-filerotate>
185             and may be cloned from L<git://https://github.com/mschout/perl-log-dispatch-filerotate.git>
186              
187             =head1 BUGS
188              
189             Please report any bugs or feature requests on the bugtracker website
190             L<https://github.com/mschout/perl-log-dispatch-filerotate/issues>
191              
192             When submitting a bug or request, please include a test-file or a
193             patch to an existing test-file that illustrates the bug or desired
194             feature.
195              
196             =head1 AUTHOR
197              
198             Michael Schout <mschout@cpan.org>
199              
200             =head1 COPYRIGHT AND LICENSE
201              
202             This software is copyright (c) 2005 by Mark Pfeiffer.
203              
204             This is free software; you can redistribute it and/or modify it under
205             the same terms as the Perl 5 programming language system itself.
206              
207             =cut