File Coverage

blib/lib/XAS/Lib/Lockmgr.pm
Criterion Covered Total %
statement 9 76 11.8
branch 0 24 0.0
condition 0 3 0.0
subroutine 3 10 30.0
pod 6 6 100.0
total 18 119 15.1


line stmt bran cond sub pod time code
1             package XAS::Lib::Lockmgr;
2              
3             our $VERSION = '0.01';
4              
5 1     1   1576 use DateTime;
  1         1  
  1         26  
6 1     1   413 use DateTime::Span;
  1         22326  
  1         48  
7              
8             use XAS::Class
9 1         19 debug => 0,
10             version => $VERSION,
11             base => 'XAS::Singleton',
12             mixin => 'XAS::Lib::Mixins::Process',
13             utils => ':validation dotid load_module',
14             accessors => 'lockers',
15             constants => 'LOCK_DRIVERS TRUE FALSE HASHREF',
16             vars => {
17             PARAMS => {
18             -deadlocked => { optional => 1, default => 5 },
19             -deadattempts => { optional => 1, default => 5 }
20             }
21             }
22 1     1   6 ;
  1         1  
23              
24             #use Data::Dumper;
25              
26             # ----------------------------------------------------------------------
27             # Public Methods
28             # ----------------------------------------------------------------------
29              
30             sub add {
31 0     0 1   my $self = shift;
32 0           my $p = validate_params(\@_, {
33             -key => 1,
34             -args => { optional => 1, default => {}, type => HASHREF },
35             -driver => { optional => 1, default => 'Filesystem', regex => LOCK_DRIVERS },
36             });
37              
38 0           my $key = $p->{'key'};
39 0           my $args = $p->{'args'};
40 0           my $module = 'XAS::Lib::Lockmgr::' . $p->{'driver'};
41              
42 0 0         unless (defined($self->lockers->{$key})) {
43              
44 0           load_module($module);
45              
46 0           $self->lockers->{$key} = $module->new(-key => $key, -args => $args);
47              
48             }
49              
50             }
51              
52             sub remove {
53 0     0 1   my $self = shift;
54 0           my ($key) = validate_params(\@_, [1]);
55              
56 0           my $stat;
57              
58 0 0         if (my $locker = $self->lockers->{$key}) {
59              
60 0           $stat = $locker->destroy();
61 0           delete $self->lockers->{$key};
62              
63             } else {
64              
65 0           $self->throw_msg(
66             dotid($self->class) . '.remove.nokey',
67             'lock_nokey',
68             $key
69             );
70              
71             }
72              
73 0           return $stat;
74              
75             }
76              
77             sub lock {
78 0     0 1   my $self = shift;
79 0           my ($key) = validate_params(\@_, [1]);
80              
81 0           my $stat;
82 0           my $attempts = 1;
83              
84 0 0         if (my $locker = $self->lockers->{$key}) {
85              
86             LOCK: {
87              
88 0 0         unless ($stat = $locker->lock()) {
  0            
89              
90 0 0         unless ($stat = $self->_deadlock($key)) {
91              
92 0           $attempts += 1;
93 0 0         redo LOCK if ($attempts <= $self->deadattempts);
94              
95             }
96              
97             }
98              
99             }
100              
101             } else {
102              
103 0           $self->throw_msg(
104             dotid($self->class) . '.lock.nokey',
105             'lock_nokey',
106             $key
107             );
108              
109             }
110              
111 0           return $stat;
112              
113             }
114              
115             sub unlock {
116 0     0 1   my $self = shift;
117 0           my ($key) = validate_params(\@_, [1]);
118              
119 0           my $stat;
120              
121 0 0         if (my $locker = $self->lockers->{$key}) {
122              
123 0           $stat = $locker->unlock();
124              
125             } else {
126              
127 0           $self->throw_msg(
128             dotid($self->class) . '.unlock.nokey',
129             'lock_nokey',
130             $key
131             );
132              
133             }
134              
135 0           return $stat;
136              
137             }
138              
139             sub try_lock {
140 0     0 1   my $self = shift;
141 0           my ($key) = validate_params(\@_, [1]);
142              
143 0           my $stat;
144              
145 0 0         if (my $locker = $self->lockers->{$key}) {
146              
147 0           $stat = $locker->try_lock();
148              
149             } else {
150              
151 0           $self->throw_msg(
152             dotid($self->class) . '.try_lock.nokey',
153             'lock_nokey',
154             $key
155             );
156              
157             }
158              
159 0           return $stat;
160              
161             }
162              
163             # ----------------------------------------------------------------------
164             # Private Methods
165             # ----------------------------------------------------------------------
166              
167             sub _deadlock {
168 0     0     my $self = shift;
169 0           my ($key) = validate_params(\@_, [1]);
170              
171 0           my $stat = FALSE;
172              
173 0 0         if (my $locker = $self->lockers->{$key}) {
174              
175 0           my $now = DateTime->now(time_zone => 'local');
176 0           my ($host, $pid, $time) = $locker->whose_lock();
177              
178 0           $time->set_time_zone('local');
179              
180 0           my $span = DateTime::Span->from_datetimes(
181             start => $now->clone->subtract(minutes => $self->deadlocked),
182             end => $now
183             );
184              
185 0           $self->log->debug(sprintf('deadlock: start - %s', $span->start));
186 0           $self->log->debug(sprintf('deadlock: end - %s', $span->end));
187 0           $self->log->debug(sprintf('deadlock: lock - %s', $time));
188              
189 0 0         unless ($span->contains($time)) {
190              
191 0 0         if ($host eq $self->env->host) {
192              
193 0           my $status = $self->proc_status($pid);
194              
195 0 0 0       unless (($status == 3) || ($status == 2)) {
196              
197 0           $locker->break_lock();
198 0           $self->log->warn_msg('lock_broken', $key);
199 0           $stat = TRUE;
200              
201             }
202              
203             } else {
204              
205 0           $self->throw_msg(
206             dotid($self->class) . '.deadlock.remote',
207             'lock_remote',
208             $key
209              
210             );
211              
212             }
213              
214             }
215              
216             } else {
217              
218 0           $self->throw_msg(
219             dotid($self->class) . '.deadlock.nokey',
220             'lock_nokey',
221             $key
222             );
223              
224             }
225              
226 0           return $stat;
227              
228             }
229              
230             sub init {
231 0     0 1   my $class = shift;
232              
233 0           my $self = $class->SUPER::init(@_);
234              
235 0           $self->{'lockers'} = {};
236              
237 0           return $self;
238              
239             }
240              
241             1;
242              
243             __END__