File Coverage

blib/lib/DBIx/Locker/Lock.pm
Criterion Covered Total %
statement 47 47 100.0
branch 12 18 66.6
condition n/a
subroutine 13 13 100.0
pod 5 5 100.0
total 77 83 92.7


line stmt bran cond sub pod time code
1 1     1   6 use strict;
  1         1  
  1         25  
2 1     1   4 use warnings;
  1         2  
  1         20  
3 1     1   12 use 5.008;
  1         3  
4             # ABSTRACT: a live resource lock
5              
6             package DBIx::Locker::Lock 1.103;
7              
8 1     1   5 use Carp ();
  1         1  
  1         12  
9 1     1   3 use Sub::Install ();
  1         2  
  1         162  
10              
11             #pod =method new
12             #pod
13             #pod B<Calling this method is a very, very stupid idea.> This method is called by
14             #pod L<DBIx::Locker> to create locks. Since you are not a locker, you should not
15             #pod call this method. Seriously.
16             #pod
17             #pod my $locker = DBIx::Locker::Lock->new(\%arg);
18             #pod
19             #pod This returns a new lock.
20             #pod
21             #pod locker - the locker creating the lock
22             #pod lock_id - the id of the lock in the lock table
23             #pod expires - the time (in epoch seconds) at which the lock will expire
24             #pod locked_by - a hashref of identifying information
25             #pod lockstring - the string that was locked
26             #pod
27             #pod =cut
28              
29             sub new {
30 5     5 1 17 my ($class, $arg) = @_;
31              
32             my $guts = {
33             is_locked => 1,
34             locker => $arg->{locker},
35             lock_id => $arg->{lock_id},
36             expires => $arg->{expires},
37             locked_by => $arg->{locked_by},
38             lockstring => $arg->{lockstring},
39 5         41 };
40              
41 5         16 return bless $guts => $class;
42             }
43              
44             #pod =method locker
45             #pod
46             #pod =method lock_id
47             #pod
48             #pod =method locked_by
49             #pod
50             #pod =method lockstring
51             #pod
52             #pod These are accessors for data supplied to L</new>.
53             #pod
54             #pod =cut
55              
56             BEGIN {
57 1     1   5 for my $attr (qw(locker lock_id locked_by lockstring)) {
58             Sub::Install::install_sub({
59             code => sub {
60 31 50   31   1983 Carp::confess("$attr is read-only") if @_ > 1;
61 31         216 $_[0]->{$attr}
62             },
63 4         158 as => $attr,
64             });
65             }
66             }
67              
68             #pod =method expires
69             #pod
70             #pod This method returns the expiration time (as a unix timestamp) as provided to
71             #pod L</new> -- unless expiration has been changed. Expiration can be changed by
72             #pod using this method as a mutator:
73             #pod
74             #pod # expire one hour from now, no matter what initial expiration was
75             #pod $lock->expires(time + 3600);
76             #pod
77             #pod When updating the expiration time, if the given expiration time is not a valid
78             #pod unix time, or if the expiration cannot be updated, an exception will be raised.
79             #pod
80             #pod =cut
81              
82             sub expires {
83 4     4 1 704 my $self = shift;
84 4 100       22 return $self->{expires} unless @_;
85              
86 1         3 my $new_expiry = shift;
87              
88 1 50       10 Carp::confess("new expiry must be a Unix epoch time")
89             unless $new_expiry =~ /\A\d+\z/;
90              
91 1         23 my $time_array = [ localtime $new_expiry ];
92              
93 1         6 my $dbh = $self->locker->dbh;
94 1         30 my $table = $self->locker->table;
95              
96 1         6 my $rows = $dbh->do(
97             "UPDATE $table SET expires = ? WHERE id = ?",
98             undef,
99             $self->locker->_time_to_string($time_array),
100             $self->lock_id,
101             );
102              
103 1 50       32065 my $str = defined $rows ? $rows : 'undef';
104 1 50       5 Carp::confess("error updating expiry: UPDATE returned $str") if $rows != 1;
105              
106 1         5 $self->{expires} = $new_expiry;
107              
108 1         5 return $new_expiry;
109             }
110              
111             #pod =method guid
112             #pod
113             #pod This method returns the lock's globally unique id.
114             #pod
115             #pod =cut
116              
117 2     2 1 1964 sub guid { $_[0]->locked_by->{guid} }
118              
119             #pod =method is_locked
120             #pod
121             #pod Method to see if the lock is active or not
122             #pod
123             #pod =cut
124              
125             sub is_locked {
126 14 100   14 1 512 $_[0]->{is_locked} = $_[1] if exists $_[1];
127             $_[0]->{is_locked}
128 14         67 }
129              
130             #pod =method unlock
131             #pod
132             #pod This method unlocks the lock, deleting the semaphor record. This method is
133             #pod automatically called when locks are garbage collected.
134             #pod
135             #pod =cut
136              
137             sub unlock {
138 7     7 1 16 my ($self) = @_;
139              
140 7 100       15 return unless $self->is_locked;
141              
142 5         18 my $dbh = $self->locker->dbh;
143 5         170 my $table = $self->locker->table;
144              
145 5         19 my $rows = $dbh->do("DELETE FROM $table WHERE id=?", undef, $self->lock_id);
146              
147 5 50       72809 Carp::confess('error releasing lock') unless $rows == 1;
148 5         28 $self->is_locked(0);
149             }
150              
151             sub DESTROY {
152 5     5   2928 my ($self) = @_;
153 5         10 local $@;
154 5 50       18 return unless $self->locked_by->{pid} == $$;
155 5         14 $self->unlock;
156             }
157              
158             1;
159              
160             __END__
161              
162             =pod
163              
164             =encoding UTF-8
165              
166             =head1 NAME
167              
168             DBIx::Locker::Lock - a live resource lock
169              
170             =head1 VERSION
171              
172             version 1.103
173              
174             =head1 PERL VERSION
175              
176             This library should run on perls released even a long time ago. It should work
177             on any version of perl released in the last five years.
178              
179             Although it may work on older versions of perl, no guarantee is made that the
180             minimum required version will not be increased. The version may be increased
181             for any reason, and there is no promise that patches will be accepted to lower
182             the minimum required perl.
183              
184             =head1 METHODS
185              
186             =head2 new
187              
188             B<Calling this method is a very, very stupid idea.> This method is called by
189             L<DBIx::Locker> to create locks. Since you are not a locker, you should not
190             call this method. Seriously.
191              
192             my $locker = DBIx::Locker::Lock->new(\%arg);
193              
194             This returns a new lock.
195              
196             locker - the locker creating the lock
197             lock_id - the id of the lock in the lock table
198             expires - the time (in epoch seconds) at which the lock will expire
199             locked_by - a hashref of identifying information
200             lockstring - the string that was locked
201              
202             =head2 locker
203              
204             =head2 lock_id
205              
206             =head2 locked_by
207              
208             =head2 lockstring
209              
210             These are accessors for data supplied to L</new>.
211              
212             =head2 expires
213              
214             This method returns the expiration time (as a unix timestamp) as provided to
215             L</new> -- unless expiration has been changed. Expiration can be changed by
216             using this method as a mutator:
217              
218             # expire one hour from now, no matter what initial expiration was
219             $lock->expires(time + 3600);
220              
221             When updating the expiration time, if the given expiration time is not a valid
222             unix time, or if the expiration cannot be updated, an exception will be raised.
223              
224             =head2 guid
225              
226             This method returns the lock's globally unique id.
227              
228             =head2 is_locked
229              
230             Method to see if the lock is active or not
231              
232             =head2 unlock
233              
234             This method unlocks the lock, deleting the semaphor record. This method is
235             automatically called when locks are garbage collected.
236              
237             =head1 AUTHOR
238              
239             Ricardo SIGNES <cpan@semiotic.systems>
240              
241             =head1 COPYRIGHT AND LICENSE
242              
243             This software is copyright (c) 2022 by Ricardo SIGNES.
244              
245             This is free software; you can redistribute it and/or modify it under
246             the same terms as the Perl 5 programming language system itself.
247              
248             =cut