Eonblast/Emysql — Issue #20: race condition with Nconnections=1
Author: bvdeenen
Created: 2012-02-01 14:09:31+00:00
State: open

Hi all

I'm new here, but I seem to have stumbled upon a race condition where simultaneously executing queries on a certain pool end up using a connection that actually belongs to another pool. I've narrowed it down to a simple testcase using two sql tables in two database

mysqldump -udemo -pdemo test2
CREATE TABLE `test` ( `b` int(11) NOT NULL )
mysqldump -udemo -pdemo test1
CREATE TABLE `test` ( `a` int(11) NOT NULL )

I this erl file:

-module(em).

-include_lib("eunit/include/eunit.hrl").
-include_lib("emysql/include/emysql.hrl").

-compile(export_all).

t_test() ->

crypto:start(),
application:start(emysql),

try emysql:remove_pool(test1) catch _:_ -> ok end,
try emysql:remove_pool(test2) catch _:_ -> ok end,
try emysql:remove_pool(test3) catch _:_ -> ok end,

emysql:add_pool(test1, 1, "demo", "demo", "localhost", 3306, "test1", utf8),
emysql:add_pool(test2, 1, "demo", "demo", "localhost", 3306, "test2", utf8),
emysql:add_pool(test3, 1, "demo", "demo", "localhost", 3306, "test1", utf8),

?assertMatch( #result_packet{}, emysql:execute(test1, "select a from test")),

?assertMatch( #result_packet{}, emysql:execute(test2, "select b from test")),

?assertMatch( #result_packet{}, emysql:execute(test3, "select a from test")),

F=fun() ->
timer:sleep(100+random:uniform(500)),
?assertMatch( #result_packet{}, emysql:execute(test2, "select b from test")),
?assertMatch( #result_packet{}, emysql:execute(test3, "select a from test")),
ok
end,
[spawn(F) || _ <- lists:seq(1,5)],
timer:sleep(1000),
ok.

Running em:test() with values of 1 for the nconnections in the `emysql:add_pool(...)` causes an assertMatch failure:

=ERROR REPORT==== 1-Feb-2012::14:53:06 ===
Error in process <0.10468.0> with exit value: {{assertMatch_failed,[{module,em},{line,29},{expression,"emysql :
execute ( test2 , \"select b from test\" )"},{pattern,"# result_packet { }"},
{value,{error_packet,1,1054,<<5 bytes>>,"Unknown column 'b' in 'field list'"}}]},[{em,'-t_test/0-fun-3-'...

From other tests in more complex situations with actual data in the columns, I know that it was actually talking on another connection than the one specified with add_pool. I also notice that when the error occurs, if you do a `emysql_conn_mgr:pools()` call, the order of the pools is changed from the initial order.

If you increase the connections in the add_pool call, the whole thing works fine and you get no errors.