line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mysql::NameLocker; |
2
|
1
|
|
|
1
|
|
497
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
38
|
|
3
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
417
|
|
4
|
|
|
|
|
|
|
our $VERSION = '1.00'; |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
Mysql::NameLocker - Safe way of locking and unlocking MySQL tables using named locks. |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 SYNOPSIS |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use Mysql::NameLocker; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# Simulate a record lock |
15
|
|
|
|
|
|
|
my $tablename = 'category' |
16
|
|
|
|
|
|
|
my $id = 123; |
17
|
|
|
|
|
|
|
my $lockname = "$tablename_$id"; |
18
|
|
|
|
|
|
|
my $timeout = 10; |
19
|
|
|
|
|
|
|
my $locker = new Mysql::NameLocker($dbh,$lockname,$timeout); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# Execute some tricky statements here... |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# Locks are automically released when $locker goes out of scope. |
24
|
|
|
|
|
|
|
undef($locker); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 DESCRIPTION |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
Mysql::NameLocker is a simple class for safely using MySQL named locks. |
29
|
|
|
|
|
|
|
A locks is created when you instantiate the class and is automatically |
30
|
|
|
|
|
|
|
released when the object goes out of scope (or when you call undef on the |
31
|
|
|
|
|
|
|
object). One situation where this class is useful is when you have |
32
|
|
|
|
|
|
|
persistent database connections such as in some mod_perl scripts and you |
33
|
|
|
|
|
|
|
want to be sure that locks are always released even when a script dies |
34
|
|
|
|
|
|
|
somewhere unexpectedly. |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 CLASS METHODS |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head2 new ($dbh,$lockname,$timeout) |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Attempts to acquire a named lock and returns a Mysql::NameLocker object |
41
|
|
|
|
|
|
|
that encapsulates this lock. If a timeout occurs, then undef is returned. |
42
|
|
|
|
|
|
|
If an error occurs (The MySQL statement GET_LOCK() returns NULL) then this |
43
|
|
|
|
|
|
|
constructor croaks. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Parameters: |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=over 4 |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=item 1. DBI database handle object. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=item 2. Lock name. |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item 3. Timeout in seconds. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=back |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
Returns: Mysql::NameLocker object or undef if failed to acquire lock. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=cut |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub new { |
62
|
0
|
|
|
0
|
1
|
|
my $proto = shift; |
63
|
0
|
|
|
|
|
|
my $dbh = shift; |
64
|
0
|
|
|
|
|
|
my $lockname = shift; |
65
|
0
|
|
|
|
|
|
my $timeout = shift; |
66
|
0
|
0
|
0
|
|
|
|
unless(defined($dbh) && defined($lockname) && length($lockname) && defined($timeout)) { |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
67
|
0
|
|
|
|
|
|
croak('Invalid parameters for ' . __PACKAGE__ . '->new() constructor!'); |
68
|
|
|
|
|
|
|
} |
69
|
0
|
|
|
|
|
|
my $sth = $dbh->prepare('SELECT GET_LOCK(?,?)'); |
70
|
0
|
0
|
|
|
|
|
unless(defined($sth)) { |
71
|
0
|
|
|
|
|
|
croak($dbh->errstr()); |
72
|
|
|
|
|
|
|
} |
73
|
0
|
|
|
|
|
|
$sth->bind_param(1,$lockname); |
74
|
0
|
|
|
|
|
|
$sth->bind_param(2,$timeout); |
75
|
0
|
0
|
|
|
|
|
unless($sth->execute()) { |
76
|
0
|
|
|
|
|
|
croak($sth->errstr()); |
77
|
|
|
|
|
|
|
} |
78
|
0
|
|
|
|
|
|
my ($result) = $sth->fetchrow_array(); |
79
|
0
|
|
|
|
|
|
$sth->finish(); |
80
|
0
|
0
|
|
|
|
|
unless(defined($result)) { |
81
|
0
|
|
|
|
|
|
croak("Error trying to acquire named lock.\n"); |
82
|
|
|
|
|
|
|
} |
83
|
0
|
0
|
|
|
|
|
unless($result) { |
84
|
0
|
|
|
|
|
|
return undef; |
85
|
|
|
|
|
|
|
} |
86
|
0
|
|
|
|
|
|
my $self = {'_dbh' => $dbh, |
87
|
|
|
|
|
|
|
'_lockname' => $lockname}; |
88
|
0
|
|
0
|
|
|
|
my $class = ref($proto) || $proto; |
89
|
0
|
|
|
|
|
|
bless $self,$class; |
90
|
0
|
|
|
|
|
|
return $self; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head2 DESTROY |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
Destructor called implicitly by perl when object is destroyed. The acquired |
101
|
|
|
|
|
|
|
lock is released here if the DBI database handle is still connected. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=cut |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub DESTROY { |
106
|
0
|
|
|
0
|
|
|
my $self = shift; |
107
|
0
|
|
|
|
|
|
my $dbh = $self->{'_dbh'}; |
108
|
0
|
0
|
|
|
|
|
if ($dbh->ping()) { |
109
|
0
|
|
|
|
|
|
my $sth = $dbh->prepare('SELECT RELEASE_LOCK(?)'); |
110
|
0
|
|
|
|
|
|
$sth->bind_param(1,$self->{'_lockname'}); |
111
|
0
|
|
|
|
|
|
$sth->execute(); |
112
|
0
|
|
|
|
|
|
$sth->finish(); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
1; |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
__END__ |