ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro-Mysql/Mysql.pm
Revision: 1.10
Committed: Thu Feb 17 02:06:55 2011 UTC (13 years, 3 months ago) by root
Branch: MAIN
Changes since 1.9: +6 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Coro::Mysql - let other threads run while doing mysql requests
4
5 =head1 SYNOPSIS
6
7 use Coro::Mysql;
8
9 my $DBH = Coro::Mysql::unblock DBI->connect (...);
10
11 =head1 DESCRIPTION
12
13 (Note that in this manual, "thread" refers to real threads as implemented
14 by the Coro module, not to the built-in windows process emulation which
15 unfortunately is also called "threads")
16
17 This module "patches" DBD::mysql database handles so that they do not
18 block the whole process, but only the thread that they are used in.
19
20 This can be used to make parallel sql requests using Coro, or to do other
21 stuff while mysql is rumbling in the background.
22
23 =head2 CAVEAT
24
25 Note that this module must be linked against exactly the same (shared,
26 possibly not working with all OSes) F<libmysqlclient> library as
27 DBD::mysql, otherwise it will not work.
28
29 Also, while this module makes database handles non-blocking, you still
30 cannot run multiple requests in parallel on the same database handle. If
31 you want to run multiple queries in parallel, you have to create multiple
32 database connections, one for each thread that runs queries. Not doing so
33 can corrupt your data - use a Coro::Semaphore when in doubt.
34
35 If you make sure that you never run two or more requests in parallel, you
36 can freely share the database handles between threads, of course.
37
38 Also, this module uses a number of "unclean" techniques (patching an
39 internal libmysql structure for one thing) and was initially hacked within
40 a few hours on a long flight to Malaysia.
41
42 It does, however, check whether it indeed got the structure layout
43 correct, so you should expect perl exceptions or early crashes as opposed
44 to data corruption when something goes wrong during patching.
45
46 =head2 SPEED
47
48 This module is implemented in XS, and as long as mysqld replies quickly
49 enough, it adds no overhead to the standard libmysql communication
50 routines (which are very badly written, btw.). In fact, since it has a
51 more efficient buffering and allows requests to run in parallel, it often
52 decreases the actual time to run many queries considerably.
53
54 For very fast queries ("select 0"), this module can add noticable overhead
55 (around 15%, 7% when EV can be used) as it tries to switch to other
56 coroutines when mysqld doesn't deliver the data immediately, although,
57 again, when running queries in parallel, they will usually execute faster.
58
59 For most types of queries, there will be no extra latency, especially on
60 multicore systems where your perl process can do other things while mysqld
61 does its stuff.
62
63 =head2 LIMITATIONS
64
65 This module only supports "standard" mysql connection handles - this
66 means unix domain or TCP sockets, and excludes SSL/TLS connections, named
67 pipes (windows) and shared memory (also windows). No support for these
68 connection types is planned, either.
69
70 =head1 CANCELLATION
71
72 Cancelling a thread that is within a mysql query will likely make the
73 handle unusable. As far as Coro::Mysql is concerned, the handle can be
74 safely destroyed, but it's not clear how mysql itself will react to a
75 cancellation.
76
77 =head1 FUNCTIONS
78
79 Coro::Mysql offers a single user-accessible function:
80
81 =over 4
82
83 =cut
84
85 package Coro::Mysql;
86
87 use strict qw(vars subs);
88 no warnings;
89
90 use Scalar::Util ();
91 use Carp qw(croak);
92
93 use Guard;
94 use AnyEvent ();
95 use Coro ();
96 use Coro::AnyEvent (); # not necessary with newer Coro versions
97
98 # we need this extra indirection, as Coro doesn't support
99 # calling SLF-like functions via call_sv.
100
101 sub readable { &Coro::Handle::FH::readable }
102 sub writable { &Coro::Handle::FH::writable }
103
104 BEGIN {
105 our $VERSION = '1.02';
106
107 require XSLoader;
108 XSLoader::load Coro::Mysql::, $VERSION;
109 }
110
111 =item $DBH = Coro::Mysql::unblock $DBH
112
113 This function takes a DBI database handles and "patches" it
114 so it becomes compatible to Coro threads.
115
116 After that, it returns the patched handle - you should always use the
117 newly returned database handle.
118
119 It is safe to call this function on any database handle (or just about any
120 value), but it will only do anything to L<DBD::mysql> handles, others are
121 returned unchanged. That means it is harmless when applied to database
122 handles of other databases.
123
124 It is also safe to pass C<undef>, so code like this is works as expected:
125
126 my $dbh = DBI->connect ($database, $user, $pass)->Coro::Mysql::unblock
127 or die $DBI::errstr;
128
129 =cut
130
131 sub unblock {
132 my ($DBH) = @_;
133
134 if ($DBH && $DBH->{Driver}{Name} eq "mysql") {
135 my $sock = $DBH->{sock};
136
137 open my $fh, "+>&" . $DBH->{sockfd}
138 or croak "Coro::Mysql unable to clone mysql fd";
139
140 if (AnyEvent::detect ne "AnyEvent::Impl::EV" || !_use_ev) {
141 require Coro::Handle;
142 $fh = Coro::Handle::unblock ($fh);
143 }
144
145 _patch $sock, $DBH->{sockfd}, $fh, tied ${$fh};
146 }
147
148 $DBH
149 }
150
151 1;
152
153 =back
154
155 =head1 USAGE EXAMPLE
156
157 This example uses L<PApp::SQL> and L<Coro::on_enter> to implement a
158 function C<with_db>, that connects to a database, uses C<unblock> on the
159 resulting handle and then makes sure that C<$PApp::SQL::DBH> is set to the
160 (per-thread) database handle when the given thread is running (it does not
161 restore any previous value of $PApp::SQL::DBH, however):
162
163 use Coro;
164 use Coro::Mysql;
165 use PApp::SQL;
166
167 sub with_db($$$&) {
168 my ($database, $user, $pass, $cb) = @_;
169
170 my $dbh = DBI->connect ($database, $user, $pass)->Coro::Mysql::unblock
171 or die $DBI::errstr;
172
173 Coro::on_enter { $PApp::SQL::DBH = $dbh };
174
175 $cb->();
176 }
177
178 This function makes it possible to easily use L<PApp::SQL> with
179 L<Coro::Mysql>, without worrying about database handles.
180
181 # now start 10 threads doing stuff
182 async {
183
184 with_db "DBI:mysql:test", "", "", sub {
185 sql_exec "update table set col = 5 where id = 7";
186
187 my $st = sql_exec \my ($id, $name),
188 "select id, name from table where name like ?",
189 "a%";
190
191 while ($st->fetch) {
192 ...
193 }
194
195 my $id = sql_insertid sql_exec "insert into table values (1,2,3)";
196 # etc.
197 };
198
199 } for 1..10;
200
201 =head1 SEE ALSO
202
203 L<Coro>, L<PApp::SQL> (a user friendly but efficient wrapper around DBI).
204
205 =head1 AUTHOR
206
207 Marc Lehmann <schmorp@schmorp.de>
208 http://home.schmorp.de/
209
210 =cut
211