File Coverage

blib/lib/DDLock/Client/File.pm
Criterion Covered Total %
statement 15 62 24.1
branch 0 26 0.0
condition 0 7 0.0
subroutine 5 12 41.6
pod 0 6 0.0
total 20 113 17.7


line stmt bran cond sub pod time code
1             package DDLock::Client::File;
2              
3 3     3   17 use Fcntl qw{:DEFAULT :flock};
  3         7  
  3         1619  
4 3     3   19 use File::Spec qw{};
  3         6  
  3         65  
5 3     3   14 use File::Path qw{mkpath};
  3         6  
  3         208  
6 3     3   10312 use IO::File qw{};
  3         7353  
  3         77  
7              
8 3     3   19 use fields qw{name path tmpfile pid hooks};
  3         6  
  3         22  
9              
10             our $TmpDir = File::Spec->tmpdir;
11              
12             ### (CONSTRUCTOR) METHOD: new( $lockname )
13             ### Createa a new file-based lock with the specified I.
14             sub new {
15 0     0 0   my DDLock::Client::File $self = shift;
16 0 0         $self = fields::new( $self ) unless ref $self;
17 0           my ( $name, $lockdir ) = @_;
18              
19 0           $self->{pid} = $$;
20              
21 0   0       $lockdir ||= $TmpDir;
22 0 0         if ( ! -d $lockdir ) {
23             # Croaks if it fails, so no need for error-checking
24 0           mkpath $lockdir;
25             }
26              
27 0           my $lockfile = File::Spec->catfile( $lockdir, eurl($name) );
28              
29             # First open a temp file
30 0           my $tmpfile = "$lockfile.$$.tmp";
31 0 0         if ( -e $tmpfile ) {
32 0 0         unlink $tmpfile or die "unlink: $tmpfile: $!";
33             }
34              
35 0 0         my $fh = new IO::File $tmpfile, O_WRONLY|O_CREAT|O_EXCL
36             or die "open: $tmpfile: $!";
37 0           $fh->close;
38 0           undef $fh;
39              
40             # Now try to make a hard link to it
41 0 0         link( $tmpfile, $lockfile )
42             or die "link: $tmpfile -> $lockfile: $!";
43 0 0         unlink $tmpfile or die "unlink: $tmpfile: $!";
44              
45 0           $self->{path} = $lockfile;
46 0           $self->{tmpfile} = $tmpfile;
47 0           $self->{hooks} = {};
48              
49 0           return $self;
50             }
51              
52             sub name {
53 0     0 0   my DDLock::Client::File $self = shift;
54 0           return $self->{name};
55             }
56              
57             sub set_hook {
58 0     0 0   my DDLock::Client::File $self = shift;
59 0   0       my $hookname = shift || return;
60              
61 0 0         if (@_) {
62 0           $self->{hooks}->{$hookname} = shift;
63             } else {
64 0           delete $self->{hooks}->{$hookname};
65             }
66             }
67              
68             sub run_hook {
69 0     0 0   my DDLock::Client::File $self = shift;
70 0   0       my $hookname = shift || return;
71              
72 0 0         if (my $hook = $self->{hooks}->{$hookname}) {
73 0           local $@;
74 0           eval { $hook->($self) };
  0            
75 0 0         warn "DDLock::Client::File hook '$hookname' threw error: $@" if $@;
76             }
77             }
78              
79             ### METHOD: release()
80             ### Release the lock held by the object.
81             sub release {
82 0     0 0   my DDLock::Client::File $self = shift;
83 0           $self->run_hook('release');
84 0 0         return unless $self->{path};
85 0 0         unlink $self->{path} or die "unlink: $self->{path}: $!";
86 0           unlink $self->{tmpfile};
87             }
88              
89              
90             ### FUNCTION: eurl( $arg )
91             ### URL-encode the given I and return it.
92             sub eurl
93             {
94 0     0 0   my $a = $_[0];
95 0           $a =~ s/([^a-zA-Z0-9_,.\\: -])/sprintf("%%%02X",ord($1))/eg;
  0            
96 0           $a =~ tr/ /+/;
97 0           return $a;
98             }
99              
100              
101             DESTROY {
102 0     0     my $self = shift;
103 0           $self->run_hook('DESTROY');
104 0 0         $self->release if $$ == $self->{pid};
105             }
106              
107             1;
108              
109              
110             # Local Variables:
111             # mode: perl
112             # c-basic-indent: 4
113             # indent-tabs-mode: nil
114             # End: