File Coverage

blib/lib/WWW/Link_Controller/Lock.pm
Criterion Covered Total %
statement 19 54 35.1
branch 1 40 2.5
condition 0 3 0.0
subroutine 7 9 77.7
pod 2 2 100.0
total 29 108 26.8


line stmt bran cond sub pod time code
1              
2              
3             =head1 NAME
4              
5             WWW::Link_Controller::Lock - application locks on link database.
6              
7             =head1 DESCRIPTION
8              
9             This provides a very simple lock on the link database used for
10             stopping multiple processes which write to the database starting at
11             the same time.
12              
13             We don't care about any of the other databases (e.g. schedule) 'cos
14             they ain't that critical and can be easily reconstructed if needed...
15             Hmm.
16              
17             This should be replaced with something which works properly, probably
18             based on transactions as implemented in postgress (all read only
19             queries allways get an immediate answer, although it may be about a
20             time in the past).
21              
22             =head1 IMPLEMENTATION
23              
24             We create a symbolic link related to the name of the database file
25             with our process data in the target.
26              
27             When the program ends we remove the lock automatically..
28              
29             When we start up and the lock exists we tell the user the name of the
30             lock and ask them to remove it.
31              
32             When asked to verify the lock, we check that the process data matches
33             our data.
34              
35             =head1 ADVANTAGES
36              
37             =over 4
38              
39             =item *
40              
41             Easy for people to understand the locks
42              
43             =item *
44              
45             Should work over NFS etc..
46              
47             =item *
48              
49             Reasonably safe
50              
51             =back
52              
53             =head1 FUNCTIONS
54              
55             =cut
56              
57             package WWW::Link_Controller::Lock;
58             $REVISION=q$Revision: 1.7 $ ; $VERSION = sprintf ( "%d.%02d", $REVISION =~ /(\d+).(\d+)/ );
59 1     1   1521 use warnings;
  1         2  
  1         32  
60 1     1   5 use strict;
  1         2  
  1         28  
61 1     1   897 use English;
  1         5272  
  1         6  
62 1     1   531 use vars qw($lock_file $link_data $localhost $lock_owner);
  1         2  
  1         77  
63 1     1   906 use Sys::Hostname;
  1         1207  
  1         50  
64 1     1   5 use Cwd;
  1         2  
  1         592  
65              
66             $lock_file=undef;
67             $lock_owner=0;
68             $link_data=undef;
69             $localhost=hostname;
70              
71             $WWW::Link_Controller::Lock::silent = 0 unless defined
72             $WWW::Link_Controller::Lock::silent;
73              
74             =head2 WWW::Link_Controller::Lock::lock($linkfile)
75              
76             Creates our lock_file (actually a symlink); dies if it can't.
77              
78             =cut
79              
80             sub lock ($) {
81 0     0 1   my $name=shift;
82 0 0         die "we can only do one lock" if defined $lock_file;
83 0           my ($path,$file)=$name =~ m,((?:.*/)?)([^/]+),;
84              
85 0           $lock_file=$path . '#' . $file . '.lock';
86 0 0         -e $lock_file and do {
87 0 0         not -l $lock_file and
88             die "The lock file $lock_file exists and isn't a symbolic link!";
89 0           my $existing_link_data=readlink $lock_file;
90 0           die "lock_file $lock_file exists: seems to be simlink to "
91             . "$existing_link_data" ;
92             };
93              
94 0 0         -l $lock_file and do {
95 0           my $existing_link_data=readlink $lock_file;
96 0           die "lock_file $lock_file exists: held by $existing_link_data;" .
97             " remove if stale";
98             };
99              
100 0           $link_data=$PROCESS_ID . '@' . $localhost;
101 0 0         print STDERR "W::L::Lock creating lock file $lock_file -> $link_data\n"
102             unless $WWW::Link_Controller::Lock::silent;
103 0 0         symlink $link_data, $lock_file
104             or die "failed to create lock_file $lock_file";
105 0           $lock_owner=1;
106             }
107              
108              
109             =head2 WWW::Link_Controller::Lock::checklock()
110              
111             Checks that we still hold the lock we originally created. Used to
112             minimise the chance of problems when the lock is broken by someone
113             careless.
114              
115             Use this on long running programs just before writing to the
116             database.
117              
118             =cut
119              
120             sub checklock () {
121 0 0   0 1   die "lock_file undefined; perhaps you didn't lock" unless $lock_file;
122 0 0         die "linkdata undefined; error in Lock.pm" unless $link_data;
123             # die "lock file $lock_file doesn't exist in " . cwd unless -e $lock_file;
124 0 0         die "lock isn't a symlink" unless -l $lock_file;
125 0 0         die "lock has been stolen" unless readlink $lock_file eq $link_data;
126 0 0         print STDERR "WWW::Link_Controller::Lock: checked lock file $lock_file\n"
127             unless $WWW::Link_Controller::Lock::silent;
128 0           return 1;
129             }
130              
131              
132             sub END {
133              
134             #FIXME: this doesn't get called after signals, but it probably should
135              
136 1 50   1     return unless $lock_owner;
137 0 0         do { warn "linkdata undefined; error in Lock.pm" ; $?=1 unless $?; return}
  0 0          
  0            
  0            
138             unless $link_data;
139 0 0         do { warn "lock isn't a symlink" ; $?=1 unless $?; return}
  0 0          
  0            
  0            
140             unless -l $lock_file;
141 0 0         do { warn "lock has been stolen" ; $?=1 unless $?; return}
  0 0          
  0            
  0            
142             unless readlink $lock_file eq $link_data;
143 0 0         print STDERR "W::L::Lock deleting lock file $lock_file -> $link_data\n"
144             unless $WWW::Link_Controller::Lock::silent;
145 0 0 0       unlink $lock_file or warn "failed to delete lock file $lock_file"
146             if $lock_owner
147             }
148              
149             1;