File Coverage

blib/lib/Cache/Memcached/Semaphore.pm
Criterion Covered Total %
statement 12 55 21.8
branch 0 24 0.0
condition 0 12 0.0
subroutine 4 8 50.0
pod 3 3 100.0
total 19 102 18.6


line stmt bran cond sub pod time code
1             package Cache::Memcached::Semaphore;
2 1     1   201450 use strict;
  1         2  
  1         36  
3             require 5.007003;
4              
5 1     1   6 use base qw(Exporter);
  1         1  
  1         163  
6             #---------------------------------------------------------------------
7             our %EXPORT_TAGS = (
8             all => [ qw(
9             &acquire
10             &wait_acquire
11             ) ],
12             );
13             #---------------------------------------------------------------------
14              
15             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
16             #---------------------------------------------------------------------
17              
18             our $VERSION = '0.3';
19              
20 1     1   6 use Time::HiRes qw( usleep gettimeofday );
  1         6  
  1         8  
21 1     1   197 use Digest::MD5 qw(md5_hex);
  1         2  
  1         562  
22              
23             #---------------------------------------------------------------------
24             sub new {
25 0     0 1   my $proto = shift;
26 0   0       my $class = ref($proto) || $proto;
27            
28 0           my %args = (
29             name => undef,
30             memd => undef,
31             force => 0, # force lock is experimental
32             timeout => undef,
33             @_,
34             );
35            
36 0 0 0       if ( $args{name} && $args{memd}) {
37 0           my $memd = $args{memd};
38            
39 0 0         if ( $memd ) {
40 0           my $key = "__lock__" . $args{name};
41 0           my $val = md5_hex( gettimeofday() . $$ );
42 0           my $res = $memd->add( $key, $val );
43 0 0 0       if ( $res || $args{force}) {
44 0 0         unless ( $res ) {
45 0           $memd->set( $key, $val );
46 0 0         return undef unless $memd->get( $key ) eq $val;
47             }
48 0           my $self = {
49             key => $key,
50             val => $val,
51             memd => $memd,
52             timeout => $args{timeout},
53             };
54            
55 0           bless $self, $class;
56            
57 0           return $self;
58             }
59             }
60             }
61            
62 0           return undef;
63             }
64             #---------------------------------------------------------------------
65              
66             sub DESTROY {
67 0     0     my $self = shift;
68 0           my $memd = $self->{memd};
69            
70 0 0         if ( $memd ) {
71 0           my $val = $memd->get( $self->{key} );
72 0 0         $val = "" unless $val;
73 0 0         if ( $val eq $self->{val} ) {
74 0           my $res = $memd->delete( $self->{key}, $self->{timeout} );
75             } else {
76 0           warn "Wrong value at $self->{key} while unlocking.\nExpected $self->{val}\nGot $val" ;
77             }
78             } else {
79 0           warn "No memd $self->{memd_id}. Cannot unlock $self->{key}";
80             }
81             }
82             #---------------------------------------------------------------------
83              
84             sub acquire {
85 0     0 1   my %args = (
86             name => undef,
87             memd => undef,
88             timeout => undef,
89             @_,
90             );
91            
92 0           return Cache::Memcached::Semaphore->new( %args );
93             }
94             #---------------------------------------------------------------------
95              
96             sub wait_acquire {
97 0     0 1   my %args = (
98             name => undef,
99             memd => undef,
100             timeout => undef,
101             max_wait => undef,
102             poll_time => 0.1,
103             force_after_timeout => 0,
104             @_,
105             );
106            
107 0           my $wait_indef = 0;
108 0 0         $wait_indef = 1 unless $args{max_wait};
109 0           my $wait_left = $args{max_wait};
110 0           my $wait_time = $args{poll_time};
111            
112 0           my $lock = Cache::Memcached::Semaphore->new(
113             name => $args{name},
114             memd => $args{memd},
115             timeout => $args{timeout},
116             );
117            
118 0           while ( !$lock ) {
119 0           usleep( $wait_time );
120            
121 0           $lock = Cache::Memcached::Semaphore->new(
122             name => $args{name},
123             memd => $args{memd},
124             timeout => $args{timeout},
125             );
126              
127 0 0         unless( $wait_indef ) {
128 0           $wait_left -= $wait_time;
129 0 0         last if ( $wait_left <= 0 );
130             }
131             }
132            
133 0 0 0       if ( !$lock && $args{force_after_timeout} ) {
134 0           $lock = Cache::Memcached::Semaphore->new(
135             name => $args{name},
136             memd => $args{memd},
137             timeout => $args{timeout},
138             force => 1,
139             );
140             }
141            
142 0           return $lock;
143             }
144             #---------------------------------------------------------------------
145              
146             1;
147             __END__