ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro-Mysql/Mysql.pm
(Generate patch)

Comparing Coro-Mysql/Mysql.pm (file contents):
Revision 1.2 by root, Sat May 30 06:58:22 2009 UTC vs.
Revision 1.8 by root, Thu Jan 13 12:08:56 2011 UTC

20This can be used to make parallel sql requests using Coro, or to do other 20This can be used to make parallel sql requests using Coro, or to do other
21stuff while mysql is rumbling in the background. 21stuff while mysql is rumbling in the background.
22 22
23=head2 CAVEAT 23=head2 CAVEAT
24 24
25Note that this module must be linked against exactly the same 25Note that this module must be linked against exactly the same (shared,
26F<libmysqlclient> library as DBD::mysql, otherwise it will not work. 26possibly not working with all OSes) F<libmysqlclient> library as
27DBD::mysql, otherwise it will not work.
27 28
28Also, while this module makes database handles non-blocking, you still 29Also, while this module makes database handles non-blocking, you still
29cannot run multiple requests in parallel on the same database handle. If 30cannot run multiple requests in parallel on the same database handle. If
30you want to run multiple queries in parallel, you have to create multiple 31you want to run multiple queries in parallel, you have to create multiple
31database connections, one for each thread that runs queries. 32database connections, one for each thread that runs queries. Not doing so
33can corrupt your data - use a Coro::Semaphore when in doubt.
32 34
33If you make sure that you never run two or more requests in parallel, you 35If you make sure that you never run two or more requests in parallel, you
34cna freely share the database handles between threads, of course. 36can freely share the database handles between threads, of course.
35 37
36Also, this module uses a number of "unclean" techniques (patching an 38Also, this module uses a number of "unclean" techniques (patching an
37internal libmysql structure for one thing) and was hacked within a few 39internal libmysql structure for one thing) and was hacked within a few
38hours on a long flight to Malaysia. 40hours on a long flight to Malaysia.
39 41
40It does, however, check whether it indeed got the structure layout 42It does, however, check whether it indeed got the structure layout
41correct, so you should expect perl exceptions or early crashes as opposed 43correct, so you should expect perl exceptions or early crashes as opposed
42to data corruption when something goes wrong. 44to data corruption when something goes wrong during patching.
43 45
44=head2 SPEED 46=head2 SPEED
45 47
46This module is implemented in XS, and as long as mysqld replies quickly 48This module is implemented in XS, and as long as mysqld replies quickly
47enough, it adds no overhead to the standard libmysql communication 49enough, it adds no overhead to the standard libmysql communication
48routines (which are very badly written). 50routines (which are very badly written, btw.).
49 51
50For very fast queries ("select 0"), this module can add noticable overhead 52For very fast queries ("select 0"), this module can add noticable overhead
51(around 15%) as it tries to switch to other coroutines when mysqld doesn't 53(around 15%) as it tries to switch to other coroutines when mysqld doesn't
52deliver the data instantly. 54deliver the data instantly.
53 55
54For most types of queries, there will be no overhead, especially on 56For most types of queries, there will be no extra latency, especially on
55multicore systems where your perl process can do other things while mysqld 57multicore systems where your perl process can do other things while mysqld
56does its stuff. 58does its stuff.
59
60=head2 LIMITATIONS
61
62This module only supports "standard" mysql connection handles - this
63means unix domain or TCP sockets, and excludes SSL/TLS connections, named
64pipes (windows) and shared memory (also windows). No support for these
65connection types is planned, either.
66
67=head1 FUNCTIONS
68
69Coro::Mysql offers a single user-accessible function:
57 70
58=over 4 71=over 4
59 72
60=cut 73=cut
61 74
75 88
76sub readable { &Coro::Handle::FH::readable } 89sub readable { &Coro::Handle::FH::readable }
77sub writable { &Coro::Handle::FH::writable } 90sub writable { &Coro::Handle::FH::writable }
78 91
79BEGIN { 92BEGIN {
80 our $VERSION = '0.1'; 93 our $VERSION = '1.02';
81 94
82 require XSLoader; 95 require XSLoader;
83 XSLoader::load Coro::Mysql::, $VERSION; 96 XSLoader::load Coro::Mysql::, $VERSION;
84} 97}
85 98
89so it becomes compatible to Coro threads. 102so it becomes compatible to Coro threads.
90 103
91After that, it returns the patched handle - you should always use the 104After that, it returns the patched handle - you should always use the
92newly returned database handle. 105newly returned database handle.
93 106
107It is safe to call this function on any database handle (or just about any
108value), but it will only do anything to L<DBD::mysql> handles, others are
109returned unchanged. That means it is harmless when applied to database
110handles of other databases.
111
94=cut 112=cut
95 113
96sub unblock { 114sub unblock {
97 my ($DBH) = @_; 115 my ($DBH) = @_;
98 my $sock = $DBH->{sock};
99 116
100 open my $fh, "+>&" . $DBH->{sockfd} 117 if ($DBH->{Driver}{Name} eq "mysql") {
101 or croak "Coro::Mysql unable to clone mysql fd"; 118 my $sock = $DBH->{sock};
102 119
103 $fh = Coro::Handle::unblock $fh; 120 open my $fh, "+>&" . $DBH->{sockfd}
121 or croak "Coro::Mysql unable to clone mysql fd";
104 122
123 $fh = Coro::Handle::unblock $fh;
124
105 _patch $sock, $DBH->{sockfd}, tied ${$fh}; 125 _patch $sock, $DBH->{sockfd}, $fh, tied ${$fh};
106 $DBH->{private_Coro_Mysql} = guard {
107 _unpatch $sock;
108 undef $fh;
109 }; 126 }
110 127
111 $DBH 128 $DBH
112} 129}
113 130
1141; 1311;
115 132
116=back 133=back
117 134
135=head1 USAGE EXAMPLE
136
137This example uses L<PApp::SQL> and L<Coro::on_enter> to implement a
138function C<with_db>, that connects to a database, uses C<unblock> on the
139resulting 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
141restore 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
158This function makes it possible to easily use L<PApp::SQL> with
159L<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
183L<Coro>, L<PApp::SQL> (a user friendly but efficient wrapper around DBI).
184
118=head1 AUTHOR 185=head1 AUTHOR
119 186
120 Marc Lehmann <schmorp@schmorp.de> 187 Marc Lehmann <schmorp@schmorp.de>
121 http://home.schmorp.de/ 188 http://home.schmorp.de/
122 189

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines