ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro-Mysql/Mysql.pm
Revision: 1.7
Committed: Thu Jan 13 11:57:09 2011 UTC (13 years, 5 months ago) by root
Branch: MAIN
Changes since 1.6: +3 -2 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 hacked within a few
40 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.).
51
52 For very fast queries ("select 0"), this module can add noticable overhead
53 (around 15%) as it tries to switch to other coroutines when mysqld doesn't
54 deliver the data instantly.
55
56 For most types of queries, there will be no overhead, especially on
57 multicore systems where your perl process can do other things while mysqld
58 does its stuff.
59
60 =head2 LIMITATIONS
61
62 This module only supports "standard" mysql connection handles - this
63 means unix domain or TCP sockets, and excludes SSL/TLS connections, named
64 pipes (windows) and shared memory (also windows). No support for these
65 connection types is planned, either.
66
67 =head1 FUNCTIONS
68
69 Coro::Mysql offers a single user-accessible function:
70
71 =over 4
72
73 =cut
74
75 package Coro::Mysql;
76
77 use strict qw(vars subs);
78 no warnings;
79
80 use Scalar::Util ();
81 use Carp qw(croak);
82
83 use Guard;
84 use Coro::Handle ();
85
86 # we need this extra indirection, as Coro doesn't support
87 # calling SLF-like functions via call_sv.
88
89 sub readable { &Coro::Handle::FH::readable }
90 sub writable { &Coro::Handle::FH::writable }
91
92 BEGIN {
93 our $VERSION = '1.02';
94
95 require XSLoader;
96 XSLoader::load Coro::Mysql::, $VERSION;
97 }
98
99 =item $DBH = Coro::Mysql::unblock $DBH
100
101 This function takes a DBI database handles and "patches" it
102 so it becomes compatible to Coro threads.
103
104 After that, it returns the patched handle - you should always use the
105 newly returned database handle.
106
107 It is safe to call this function on any database handle (or just about any
108 value), but it will only do anything to L<DBD::mysql> handles, others are
109 returned unchanged. That means it is harmless when applied to database
110 handles of other databases.
111
112 =cut
113
114 sub unblock {
115 my ($DBH) = @_;
116
117 if ($DBH->{Driver}{Name} eq "mysql") {
118 my $sock = $DBH->{sock};
119
120 open my $fh, "+>&" . $DBH->{sockfd}
121 or croak "Coro::Mysql unable to clone mysql fd";
122
123 $fh = Coro::Handle::unblock $fh;
124
125 _patch $sock, $DBH->{sockfd}, $fh, tied ${$fh};
126 }
127
128 $DBH
129 }
130
131 1;
132
133 =back
134
135 =head1 USAGE EXAMPLE
136
137 This example uses L<PApp::SQL> and L<Coro::on_enter> to implement a
138 function C<with_db>, that connects to a database, uses C<unblock> on the
139 resulting handle and then makes sure that C<$PApp::SQL::DBH> is set to the
140 (per-thread) database handle when the given thread is running (it does not
141 restore any previous value of $PApp::SQL::DBH, however):
142
143 use Coro;
144 use Coro::Mysql;
145 use PApp::SQL;
146
147 sub with_db($$$&) {
148 my ($database, $user, $pass, $cb) = @_;
149
150 my $dbh = Coro::Mysql::unblock DBI->connect ($database, $user, $pass)
151 or die $DBI::errstr;
152
153 Coro::on_enter { $PApp::SQL::DBH = $dbh };
154
155 $cb->();
156 }
157
158 This function makes it possible to easily use L<PApp::SQL> with
159 L<Coro::Mysql>, without worrying about database handles.
160
161 # now start 10 threads doing stuff
162 async {
163
164 with_db "DBI:mysql:test", "", "", sub {
165 sql_exec "update table set col = 5 where id = 7";
166
167 my $st = sql_exec \my ($id, $name),
168 "select id, name from table where name like ?",
169 "a%";
170
171 while ($st->fetch) {
172 ...
173 }
174
175 my $id = sql_insertid sql_exec "insert into table values (1,2,3)";
176 # etc.
177 };
178
179 } for 1..10;
180
181 =head1 SEE ALSO
182
183 L<Coro>, L<PApp::SQL> (a user friendly but efficient wrapper around DBI).
184
185 =head1 AUTHOR
186
187 Marc Lehmann <schmorp@schmorp.de>
188 http://home.schmorp.de/
189
190 =cut
191