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