Skip to content

Commit

Permalink
Attempt to make DBD::mysql stable in async code
Browse files Browse the repository at this point in the history
According to [^1] we have to care about connections:
[1] https://dev.mysql.com/doc/refman/5.7/en/c-api-threaded-clients.html
  • Loading branch information
FROGGS committed Mar 25, 2018
1 parent f7ce95d commit 595c93d
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
10 changes: 8 additions & 2 deletions lib/DBDish/Connection.pm6
Expand Up @@ -24,7 +24,10 @@ has $.last-rows is rw;
method dispose() {
$_.dispose for %!Statements.values;
self._disconnect;
?($.parent.Connections{self.WHICH}:delete);
#state $access = Lock.new;
#$access.protect: {
?($.parent.Connections{self.WHICH}:delete);
#}
}
submethod DESTROY() {
self.dispose;
Expand All @@ -41,7 +44,10 @@ method new(*%args) {
my \con = ::?CLASS.bless(|%args);
con.reset-err;
con.?set-defaults;
%args<parent>.Connections{con.WHICH} = con;
#state $access = Lock.new;
#$access.protect: {
%args<parent>.Connections{con.WHICH} = con;
#}
}

method prepare(Str $statement, *%args) { ... }
Expand Down
14 changes: 12 additions & 2 deletions lib/DBDish/mysql.pm6
@@ -1,19 +1,29 @@
use v6;
use NativeCall;
need DBDish;
# DBDish::mysql.pm6

unit class DBDish::mysql:auth<mberends>:ver<0.1.4> does DBDish::Driver;
use DBDish::mysql::Native;
need DBDish::mysql::Connection;

has %.mysql-init-per-thread;

#------------------ methods to be called from DBIish ------------------
method connect(Str :$host = 'localhost', Int :$port = 3306, Str :$database = 'mysql', Str :$user, Str :$password, Str :$socket ) {
state $access = Lock.new;
my $connection;
my $mysql_client = MYSQL.mysql_init;
my $mysql_client;
# We call basially mysql_library_init here, which is exposed as mysql_server_init.
$access.protect: {
#%!mysql-init-per-thread{$*THREAD.id()} //=
mysql_server_init(0, Pointer, Pointer);
$mysql_client = MYSQL.mysql_init;
};
#my $mysql_client = MYSQL.mysql_init;
my $errstr = $mysql_client.mysql_error;

unless $errstr {

# real_connect() returns either the same client pointer or null
my $result = $mysql_client.mysql_real_connect(
$host, $user, $password, $database, $port, $socket, 0
Expand Down
3 changes: 3 additions & 0 deletions lib/DBDish/mysql/Native.pm6
Expand Up @@ -196,6 +196,9 @@ class MYSQL is export is repr('CPointer') {
method mysql_get_server_info(MYSQL:D: --> Str) is native(LIB) { * }
}

# This is #define'd to be the same as mysql_library_init
sub mysql_server_init(int32, Pointer, Pointer --> int32) is export is native(LIB) { * }

sub mysql_get_client_version(--> uint32) is export is native(LIB) { * }
sub mysql_get_client_info(--> Str) is export is native(LIB) { * }

Expand Down
5 changes: 3 additions & 2 deletions lib/DBIish.pm6
Expand Up @@ -45,7 +45,8 @@ unit class DBIish:auth<mberends>:ver<0.5.9>;
$d.connect(|%_);
}
method install-driver( $drivername ) {
my $d = %installed{$drivername} //= do {
state $access = Lock.new;
my $d = $access.protect: { %installed{$drivername} //= do {
CATCH {
when X::CompUnit::UnsatisfiedDependency {
X::DBIish::DriverNotFound.new(:bogus($drivername)).fail;
Expand All @@ -65,7 +66,7 @@ unit class DBIish:auth<mberends>:ver<0.5.9>;
warn "$module doesn't do DBDish::Driver role!";
}
M.new(:parent($err-handler), |%($*DBI-DEFS<ConnDefaults>), |%_);
}
}};
without $d { .throw; };
$d;
}
Expand Down
26 changes: 26 additions & 0 deletions t/28-mysql-threaded.t
@@ -0,0 +1,26 @@
use DBIish;
use Test;

plan 100;

# This is meant to ensure that we load libmysqlclient.{so|dll} early enough.
DBIish.install-driver('mysql', :RaiseError);

await do for 1..100 {
start {
diag "Connecting to database for test $_ in thread $*THREAD.id()";
my $mysql = DBIish.connect('mysql',
:database<dbdishtest>,
:user<testuser>,
:password<testpass>,
:RaiseError,
);
my $time = rand * 10;
my $sth = $mysql.prepare("SELECT $time, SLEEP($time)");
$sth.execute();

# sleepsorted output
pass "Slept about $time seconds for test $_ in thread $*THREAD.id()";
$mysql.dispose();
}
}

0 comments on commit 595c93d

Please sign in to comment.