1############################################################################
2#
3# Apache::Session::Lock::MySQL
4# MySQL locking for Apache::Session
5# Copyright(c) 2000 Jeffrey William Baker (jwbaker@acm.org)
6# Distribute under the Perl License
7#
8############################################################################
9
10package Apache::Session::Lock::MySQL;
11
12use strict;
13
14use DBI;
15use vars qw($VERSION);
16
17$VERSION = '1.01';
18
19sub new {
20    my $class = shift;
21
22    return bless {lock => 0, lockid => undef, dbh => undef, mine => 0}, $class;
23}
24
25sub acquire_read_lock  {
26    my $self    = shift;
27    my $session = shift;
28
29    return if $self->{lock};
30
31    if (!defined $self->{dbh}) {
32        if (defined $session->{args}->{LockHandle}) {
33            $self->{dbh} = $session->{args}->{LockHandle};
34        }
35        else {
36            if (!$session->{args}->{LockDataSource}) {
37                die "LockDataSource not provided for Apache::Session::Lock::MySQL";
38            }
39            $self->{dbh} = DBI->connect(
40                $session->{args}->{LockDataSource},
41                $session->{args}->{LockUserName},
42                $session->{args}->{LockPassword},
43                { RaiseError => 1, AutoCommit => 1 }
44            );
45            $self->{mine} = 1;
46        }
47    }
48
49    local $self->{dbh}->{RaiseError} = 1;
50
51    $self->{lockid} = "Apache-Session-$session->{data}->{_session_id}";
52
53    #MySQL requires a timeout on the lock operation.  There is no option
54    #to simply wait forever.  So we'll wait for a hour.
55
56    my $sth = $self->{dbh}->prepare_cached(q{SELECT GET_LOCK(?, 3600)}, {}, 1);
57    $sth->execute($self->{lockid});
58    $sth->finish();
59
60    $self->{lock} = 1;
61}
62
63sub acquire_write_lock {
64    $_[0]->acquire_read_lock($_[1]);
65}
66
67sub release_read_lock {
68    my $self = shift;
69
70    if ($self->{lock}) {
71        local $self->{dbh}->{RaiseError} = 1;
72
73        my $sth = $self->{dbh}->prepare_cached(q{SELECT RELEASE_LOCK(?)}, {}, 1);
74        $sth->execute($self->{lockid});
75        $sth->finish();
76
77        $self->{lock} = 0;
78    }
79}
80
81sub release_write_lock {
82    $_[0]->release_read_lock;
83}
84
85sub release_all_locks  {
86    $_[0]->release_read_lock;
87}
88
89sub DESTROY {
90    my $self = shift;
91
92    $self->release_all_locks;
93
94    if ($self->{mine}) {
95        $self->{dbh}->disconnect;
96    }
97}
98
991;
100
101=pod
102
103=head1 NAME
104
105Apache::Session::Lock::MySQL - Provides mutual exclusion using MySQL
106
107=head1 SYNOPSIS
108
109 use Apache::Session::Lock::MySQL;
110
111 my $locker = Apache::Session::Lock::MySQL->new();
112
113 $locker->acquire_read_lock($ref);
114 $locker->acquire_write_lock($ref);
115 $locker->release_read_lock($ref);
116 $locker->release_write_lock($ref);
117 $locker->release_all_locks($ref);
118
119=head1 DESCRIPTION
120
121Apache::Session::Lock::MySQL fulfills the locking interface of
122Apache::Session.  Mutual exclusion is achieved through the use of MySQL's
123GET_LOCK and RELEASE_LOCK functions.  MySQL does not support the notion
124of read and write locks, so this module only supports exclusive locks.  When
125you request a shared read lock, it is instead promoted to an exclusive
126write lock.
127
128=head1 CONFIGURATION
129
130The module must know how to connect to your MySQL database to acquire locks.
131You must provide a datasource name, a user name, and a password.  These options
132are passed in the usual Apache::Session style, and are very similar to the
133options for Apache::Session::Store::MySQL.  Example:
134
135 tie %hash, 'Apache::Session::MySQL', $id, {
136     LockDataSource => 'dbi:mysql:database',
137     LockUserName   => 'database_user',
138     LockPassword   => 'K00l'
139 };
140
141Instead, you may pass in an already opened DBI handle to your database.
142
143 tie %hash, 'Apache::Session::MySQL', $id, {
144     LockHandle => $dbh
145 };
146
147=head1 AUTHOR
148
149This module was written by Jeffrey William Baker <jwbaker@acm.org>.
150
151=head1 SEE ALSO
152
153L<Apache::Session>
154