oldmoe-mysqlplus 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +8 -0
- data/TODO_LIST +13 -0
- data/ext/extconf.rb +18 -4
- data/ext/mysql.c +66 -38
- data/lib/mysqlplus.rb +11 -9
- data/mysqlplus.gemspec +21 -15
- data/test/c_threaded_test.rb +5 -5
- data/test/native_threaded_test.rb +5 -0
- data/test/test_all_hashes.rb +43 -0
- data/test/test_failure.rb +17 -0
- data/test/test_helper.rb +6 -7
- data/test/test_many_requests.rb +7 -0
- data/test/test_parsing_while_response_is_being_read.rb +48 -0
- data/test/test_threaded_sequel.rb +24 -0
- metadata +14 -8
data/README
CHANGED
@@ -20,6 +20,14 @@ An enhanced MySQL database driver. With support for async operations and threade
|
|
20
20
|
--with-mysql-dir=/usr/local/mysql \
|
21
21
|
--with-mysql-lib=/usr/local/mysql/lib \
|
22
22
|
--with-mysql-include=/usr/local/mysql/include
|
23
|
+
== Using
|
24
|
+
to use within rails
|
25
|
+
add require 'mysqlplus' to the top of environment.rb
|
26
|
+
this instantiates the Mysql class that you can use.
|
27
|
+
and it will automagically use async_query instead of query, so it's a drop in replacement.
|
28
|
+
|
29
|
+
Same with other scripts that want to use it--just require 'mysqlplus' BEFORE you require 'mysql' and it will
|
30
|
+
load the asynchronous version, then ignore the sequent require 'mysql' call.
|
23
31
|
|
24
32
|
=== Credits
|
25
33
|
|
data/TODO_LIST
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
TODO list:
|
2
|
+
|
3
|
+
Is there a quick, cheap, easy way to test for writability so we don't have to use select on the way in? Does it take long anyway?
|
4
|
+
|
5
|
+
Docs for how to use with rails, etc. [there is mysqlplus_adapter, so maybe we're good there].
|
6
|
+
|
7
|
+
Merge in lourens' branch -- I like the double check for not using send_query twice in a row! [rdp]
|
8
|
+
|
9
|
+
look into http://coderrr.wordpress.com/2009/01/11/ruby-and-mysqlplus-select-deadlock/
|
10
|
+
|
11
|
+
Some of the test/* anticipate a certain database existing--todo create it first, then drop it [?]
|
12
|
+
|
13
|
+
critical todo list:
|
data/ext/extconf.rb
CHANGED
@@ -1,10 +1,24 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
+
dirs = ENV['PATH'].split(':') + %w[
|
4
|
+
/opt
|
5
|
+
/opt/local
|
6
|
+
/opt/local/mysql
|
7
|
+
/opt/local/lib/mysql5
|
8
|
+
/usr
|
9
|
+
/usr/local
|
10
|
+
/usr/local/mysql
|
11
|
+
/usr/local/mysql-*
|
12
|
+
/usr/local/lib/mysql5
|
13
|
+
].map{|dir| "#{dir}/bin" }
|
14
|
+
|
15
|
+
GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5}"
|
16
|
+
|
3
17
|
if /mswin32/ =~ RUBY_PLATFORM
|
4
18
|
inc, lib = dir_config('mysql')
|
5
19
|
exit 1 unless have_library("libmysql")
|
6
|
-
elsif mc = with_config('mysql-config') then
|
7
|
-
mc =
|
20
|
+
elsif mc = (with_config('mysql-config') || Dir[GLOB].first) then
|
21
|
+
mc = Dir[GLOB].first if mc == true
|
8
22
|
cflags = `#{mc} --cflags`.chomp
|
9
23
|
exit 1 if $? != 0
|
10
24
|
libs = `#{mc} --libs`.chomp
|
@@ -31,8 +45,8 @@ else
|
|
31
45
|
exit 1
|
32
46
|
end
|
33
47
|
|
34
|
-
if have_func('rb_thread_blocking_region') and have_macro('
|
35
|
-
|
48
|
+
if have_func('rb_thread_blocking_region') and have_macro('RUBY_UBF_IO', 'ruby.h')
|
49
|
+
$CPPFLAGS << " -DHAVE_TBR"
|
36
50
|
end
|
37
51
|
|
38
52
|
# make mysql constant
|
data/ext/mysql.c
CHANGED
@@ -190,8 +190,10 @@ static VALUE mysqlres2obj(MYSQL_RES* res)
|
|
190
190
|
resp->res = res;
|
191
191
|
resp->freed = Qfalse;
|
192
192
|
rb_obj_call_init(obj, 0, NULL);
|
193
|
+
/* disabled until it can be reviewed further--rely on the normal GC for now.
|
193
194
|
if (++store_result_count > GC_STORE_RESULT_LIMIT)
|
194
195
|
rb_gc();
|
196
|
+
*/
|
195
197
|
return obj;
|
196
198
|
}
|
197
199
|
|
@@ -719,18 +721,43 @@ static VALUE use_result(VALUE obj)
|
|
719
721
|
}
|
720
722
|
|
721
723
|
static VALUE res_free(VALUE);
|
724
|
+
|
725
|
+
typedef struct {
|
726
|
+
MYSQL *m;
|
727
|
+
const char *data;
|
728
|
+
unsigned long len;
|
729
|
+
} QueryArgs;
|
730
|
+
|
731
|
+
static VALUE blocking_query(void *data)
|
732
|
+
{
|
733
|
+
QueryArgs *args = (QueryArgs *) data;
|
734
|
+
return (VALUE) mysql_real_query(args->m, args->data, args->len);
|
735
|
+
}
|
736
|
+
|
722
737
|
/* query(sql) */
|
723
738
|
static VALUE query(VALUE obj, VALUE sql)
|
724
739
|
{
|
725
740
|
int loop = 0;
|
726
741
|
MYSQL* m = GetHandler(obj);
|
742
|
+
QueryArgs args;
|
743
|
+
int result;
|
744
|
+
|
727
745
|
Check_Type(sql, T_STRING);
|
728
746
|
if (GetMysqlStruct(obj)->connection == Qfalse) {
|
729
747
|
rb_raise(eMysql, "query: not connected");
|
730
748
|
}
|
731
749
|
if (rb_block_given_p()) {
|
732
|
-
|
750
|
+
#ifdef RUBY_VM
|
751
|
+
args.m = m;
|
752
|
+
args.data = RSTRING_PTR(sql);
|
753
|
+
args.len = RSTRING_LEN(sql);
|
754
|
+
result = (int) rb_thread_blocking_region(blocking_query, &args, RUBY_UBF_PROCESS, 0);
|
755
|
+
#else
|
756
|
+
result = mysql_real_query(m, RSTRING_PTR(sql), RSTRING_LEN(sql));
|
757
|
+
#endif
|
758
|
+
if (result != 0)
|
733
759
|
mysql_raise(m);
|
760
|
+
|
734
761
|
do {
|
735
762
|
MYSQL_RES* res = mysql_store_result(m);
|
736
763
|
if (res == NULL) {
|
@@ -749,7 +776,16 @@ static VALUE query(VALUE obj, VALUE sql)
|
|
749
776
|
#endif
|
750
777
|
return obj;
|
751
778
|
}
|
752
|
-
|
779
|
+
|
780
|
+
#ifdef RUBY_VM
|
781
|
+
args.m = m;
|
782
|
+
args.data = RSTRING_PTR(sql);
|
783
|
+
args.len = RSTRING_LEN(sql);
|
784
|
+
result = (int) rb_thread_blocking_region(blocking_query, &args, RUBY_UBF_PROCESS, 0);
|
785
|
+
#else
|
786
|
+
result = mysql_real_query(m, RSTRING_PTR(sql), RSTRING_LEN(sql));
|
787
|
+
#endif
|
788
|
+
if (result != 0)
|
753
789
|
mysql_raise(m);
|
754
790
|
if (GetMysqlStruct(obj)->query_with_result == Qfalse)
|
755
791
|
return obj;
|
@@ -764,13 +800,12 @@ static VALUE socket(VALUE obj)
|
|
764
800
|
MYSQL* m = GetHandler(obj);
|
765
801
|
return INT2NUM(m->net.fd);
|
766
802
|
}
|
767
|
-
|
768
803
|
/* socket_type */
|
769
804
|
static VALUE socket_type(VALUE obj)
|
770
805
|
{
|
771
806
|
MYSQL* m = GetHandler(obj);
|
772
807
|
VALUE description = vio_description( m->net.vio );
|
773
|
-
return NILorSTRING( description );
|
808
|
+
return (VALUE) NILorSTRING( description );
|
774
809
|
}
|
775
810
|
|
776
811
|
/* blocking */
|
@@ -824,42 +859,33 @@ static VALUE get_result(VALUE obj)
|
|
824
859
|
return store_result(obj);
|
825
860
|
}
|
826
861
|
|
827
|
-
|
828
|
-
static VALUE async_query(int argc, VALUE* argv, VALUE obj)
|
862
|
+
static void schedule(VALUE obj, VALUE timeout)
|
829
863
|
{
|
830
|
-
|
831
|
-
|
832
|
-
fd_set read;
|
833
|
-
int ret;
|
864
|
+
MYSQL* m = GetHandler(obj);
|
865
|
+
fd_set read;
|
834
866
|
|
835
|
-
|
867
|
+
timeout = ( NIL_P(timeout) ? m->net.read_timeout : INT2NUM(timeout) );
|
836
868
|
|
837
|
-
|
869
|
+
struct timeval tv = { tv_sec: timeout, tv_usec: 0 };
|
838
870
|
|
839
|
-
|
871
|
+
FD_ZERO(&read);
|
872
|
+
FD_SET(m->net.fd, &read);
|
840
873
|
|
841
|
-
|
842
|
-
|
874
|
+
if (rb_thread_select(m->net.fd + 1, &read, NULL, NULL, &tv) < 0) {
|
875
|
+
rb_raise(eMysql, "query: timeout");
|
876
|
+
}
|
877
|
+
}
|
843
878
|
|
844
|
-
|
879
|
+
/* async_query(sql,timeout=nil) */
|
880
|
+
static VALUE async_query(int argc, VALUE* argv, VALUE obj)
|
881
|
+
{
|
882
|
+
VALUE sql, timeout;
|
845
883
|
|
846
|
-
|
847
|
-
FD_SET(m->net.fd, &read);
|
884
|
+
rb_scan_args(argc, argv, "11", &sql, &timeout);
|
848
885
|
|
849
|
-
|
850
|
-
ret = rb_thread_select(m->net.fd + 1, &read, NULL, NULL, &tv);
|
851
|
-
if (ret < 0) {
|
852
|
-
rb_raise(eMysql, "query: timeout");
|
853
|
-
}
|
854
|
-
|
855
|
-
if (ret == 0) {
|
856
|
-
continue;
|
857
|
-
}
|
886
|
+
send_query(obj,sql);
|
858
887
|
|
859
|
-
|
860
|
-
break;
|
861
|
-
}
|
862
|
-
}
|
888
|
+
schedule(obj, timeout);
|
863
889
|
|
864
890
|
return get_result(obj);
|
865
891
|
}
|
@@ -1136,7 +1162,7 @@ static VALUE process_all_hashes(VALUE obj, VALUE with_table, int build_array, in
|
|
1136
1162
|
{
|
1137
1163
|
MYSQL_RES* res = GetMysqlRes(obj);
|
1138
1164
|
unsigned int n = mysql_num_fields(res);
|
1139
|
-
VALUE ary;
|
1165
|
+
VALUE ary = Qnil;
|
1140
1166
|
if(build_array)
|
1141
1167
|
ary = rb_ary_new();
|
1142
1168
|
MYSQL_ROW row = mysql_fetch_row(res); // grab one off the top, to determine the rows
|
@@ -1203,6 +1229,8 @@ static VALUE process_all_hashes(VALUE obj, VALUE with_table, int build_array, in
|
|
1203
1229
|
|
1204
1230
|
if(yield)
|
1205
1231
|
return obj;
|
1232
|
+
|
1233
|
+
return Qnil; /* we should never get here -- this takes out a compiler warning */
|
1206
1234
|
}
|
1207
1235
|
|
1208
1236
|
/* fetch_hash2 (internal) */
|
@@ -1586,12 +1614,12 @@ static VALUE stmt_execute(int argc, VALUE *argv, VALUE obj)
|
|
1586
1614
|
s->param.bind[i].buffer = &(s->param.buffer[i]);
|
1587
1615
|
t.second_part = 0;
|
1588
1616
|
t.neg = 0;
|
1589
|
-
t.second = FIX2INT(
|
1590
|
-
t.minute = FIX2INT(
|
1591
|
-
t.hour = FIX2INT(
|
1592
|
-
t.day = FIX2INT(
|
1593
|
-
t.month = FIX2INT(
|
1594
|
-
t.year = FIX2INT(
|
1617
|
+
t.second = FIX2INT(rb_ary_entry(a, 0));
|
1618
|
+
t.minute = FIX2INT(rb_ary_entry(a, 1));
|
1619
|
+
t.hour = FIX2INT(rb_ary_entry(a, 2));
|
1620
|
+
t.day = FIX2INT(rb_ary_entry(a, 3));
|
1621
|
+
t.month = FIX2INT(rb_ary_entry(a, 4));
|
1622
|
+
t.year = FIX2INT(rb_ary_entry(a, 5));
|
1595
1623
|
*(MYSQL_TIME*)&(s->param.buffer[i]) = t;
|
1596
1624
|
} else if (CLASS_OF(argv[i]) == cMysqlTime) {
|
1597
1625
|
MYSQL_TIME t;
|
data/lib/mysqlplus.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
-
require 'mysql'
|
1
|
+
require 'mysql' # this should load the mysqlplus version of mysql.so, as we assume the user has installed mysql as a gem and have not done any previous "require 'mysql'" to have loaded the other
|
2
2
|
|
3
|
+
#
|
4
|
+
# Mysqlplus library gives you a [slightly modified] version of the Mysql class
|
5
|
+
# See http://www.kitebird.com/articles/ruby-mysql.html for details, as well as the test directory within the library
|
6
|
+
#
|
3
7
|
class Mysql
|
4
8
|
|
5
|
-
def
|
9
|
+
def ruby_async_query(sql, timeout = nil) # known to deadlock TODO
|
6
10
|
send_query(sql)
|
7
11
|
select [ (@sockets ||= {})[socket] ||= IO.new(socket) ], nil, nil, nil
|
8
12
|
get_result
|
9
13
|
end
|
10
|
-
|
11
|
-
end
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
rows
|
15
|
+
begin
|
16
|
+
alias_method :async_query, :c_async_query
|
17
|
+
rescue NameError => e
|
18
|
+
raise LoadError.new "error loading mysqlplus--this may mean you ran a require 'mysql' before a require 'mysqplus', which much come first"
|
18
19
|
end
|
20
|
+
|
19
21
|
end
|
data/mysqlplus.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "mysqlplus"
|
3
|
-
s.version = "0.1.
|
4
|
-
s.date = "
|
3
|
+
s.version = "0.1.1"
|
4
|
+
s.date = "2009-03-22"
|
5
5
|
s.summary = "Enhanced Ruby MySQL driver"
|
6
6
|
s.email = "oldmoe@gmail.com"
|
7
7
|
s.homepage = "http://github.com/oldmoe/mysqlplus"
|
@@ -9,19 +9,25 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.has_rdoc = true
|
10
10
|
s.authors = ["Muhammad A. Ali"]
|
11
11
|
s.platform = Gem::Platform::RUBY
|
12
|
-
s.files = [
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
s.files = %w[
|
13
|
+
README
|
14
|
+
Rakefile
|
15
|
+
TODO_LIST
|
16
|
+
ext/error_const.h
|
17
|
+
ext/extconf.rb
|
18
|
+
ext/mysql.c
|
19
|
+
lib/mysqlplus.rb
|
20
|
+
mysqlplus.gemspec
|
21
|
+
test/c_threaded_test.rb
|
22
|
+
test/evented_test.rb
|
23
|
+
test/native_threaded_test.rb
|
24
|
+
test/test_all_hashes.rb
|
25
|
+
test/test_failure.rb
|
26
|
+
test/test_helper.rb
|
27
|
+
test/test_many_requests.rb
|
28
|
+
test/test_parsing_while_response_is_being_read.rb
|
29
|
+
test/test_threaded_sequel.rb
|
30
|
+
]
|
25
31
|
s.rdoc_options = ["--main", "README"]
|
26
32
|
s.extra_rdoc_files = ["README"]
|
27
33
|
s.extensions << "ext/extconf.rb"
|
data/test/c_threaded_test.rb
CHANGED
@@ -3,34 +3,34 @@ require File.dirname(__FILE__) + '/test_helper'
|
|
3
3
|
ThreadedMysqlTest.new( 10, "Threaded, C, very small overhead" ) do |test|
|
4
4
|
test.setup{ Mysql.real_connect('localhost','root') }
|
5
5
|
test.per_query_overhead = 0.005
|
6
|
-
test.
|
6
|
+
test.query_with = :c_async_query
|
7
7
|
test.run!
|
8
8
|
end
|
9
9
|
|
10
10
|
ThreadedMysqlTest.new( 10, "Threaded, C, small overhead" ) do |test|
|
11
11
|
test.setup{ Mysql.real_connect('localhost','root') }
|
12
12
|
test.per_query_overhead = 0.1
|
13
|
-
test.
|
13
|
+
test.query_with = :c_async_query
|
14
14
|
test.run!
|
15
15
|
end
|
16
16
|
|
17
17
|
ThreadedMysqlTest.new( 10, "Threaded, C, medium overhead" ) do |test|
|
18
18
|
test.setup{ Mysql.real_connect('localhost','root') }
|
19
19
|
test.per_query_overhead = 1
|
20
|
-
test.
|
20
|
+
test.query_with = :c_async_query
|
21
21
|
test.run!
|
22
22
|
end
|
23
23
|
|
24
24
|
ThreadedMysqlTest.new( 10, "Threaded, C, large overhead" ) do |test|
|
25
25
|
test.setup{ Mysql.real_connect('localhost','root') }
|
26
26
|
test.per_query_overhead = 3
|
27
|
-
test.
|
27
|
+
test.query_with = :c_async_query
|
28
28
|
test.run!
|
29
29
|
end
|
30
30
|
|
31
31
|
ThreadedMysqlTest.new( 10, "Threaded, C, random overhead" ) do |test|
|
32
32
|
test.setup{ Mysql.real_connect('localhost','root') }
|
33
33
|
test.per_query_overhead = :random
|
34
|
-
test.
|
34
|
+
test.query_with = :c_async_query
|
35
35
|
test.run!
|
36
36
|
end
|
@@ -3,29 +3,34 @@ require File.dirname(__FILE__) + '/test_helper'
|
|
3
3
|
ThreadedMysqlTest.new( 10, "Threaded, native Ruby, very small overhead" ) do |test|
|
4
4
|
test.setup{ Mysql.real_connect('localhost','root') }
|
5
5
|
test.per_query_overhead = 0.005
|
6
|
+
test.query_with = :async_query
|
6
7
|
test.run!
|
7
8
|
end
|
8
9
|
|
9
10
|
ThreadedMysqlTest.new( 10, "Threaded, native Ruby, small overhead" ) do |test|
|
10
11
|
test.setup{ Mysql.real_connect('localhost','root') }
|
11
12
|
test.per_query_overhead = 0.1
|
13
|
+
test.query_with = :async_query
|
12
14
|
test.run!
|
13
15
|
end
|
14
16
|
|
15
17
|
ThreadedMysqlTest.new( 10, "Threaded, native Ruby, medium overhead" ) do |test|
|
16
18
|
test.setup{ Mysql.real_connect('localhost','root') }
|
17
19
|
test.per_query_overhead = 1
|
20
|
+
test.query_with = :async_query
|
18
21
|
test.run!
|
19
22
|
end
|
20
23
|
|
21
24
|
ThreadedMysqlTest.new( 10, "Threaded, native Ruby, large overhead" ) do |test|
|
22
25
|
test.setup{ Mysql.real_connect('localhost','root') }
|
23
26
|
test.per_query_overhead = 3
|
27
|
+
test.query_with = :async_query
|
24
28
|
test.run!
|
25
29
|
end
|
26
30
|
|
27
31
|
ThreadedMysqlTest.new( 10, "Threaded, native Ruby, random overhead" ) do |test|
|
28
32
|
test.setup{ Mysql.real_connect('localhost','root') }
|
29
33
|
test.per_query_overhead = :random
|
34
|
+
test.query_with = :async_query
|
30
35
|
test.run!
|
31
36
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# shows the effect of using .all_hashes instead of looping on each hash
|
2
|
+
# run it by substiting in a 'long' [many row] query for the query variable and toggling use_all_hashes here at the top
|
3
|
+
# note that we load all the rows first, then run .all_hashes on the result [to see more easily the effect of all hashes]
|
4
|
+
# on my machine and a 200_000 row table, it took 3.38s versus 3.65s
|
5
|
+
require 'rubygems'
|
6
|
+
require 'mysqlplus'
|
7
|
+
|
8
|
+
use_the_all_hashes_method = true
|
9
|
+
|
10
|
+
$count = 5
|
11
|
+
|
12
|
+
$start = Time.now
|
13
|
+
|
14
|
+
$connections = []
|
15
|
+
$count.times do
|
16
|
+
$connections << Mysql.real_connect('localhost','root', '', 'local_leadgen_dev')
|
17
|
+
end
|
18
|
+
|
19
|
+
puts 'connection pool ready'
|
20
|
+
|
21
|
+
$threads = []
|
22
|
+
$count.times do |i|
|
23
|
+
$threads << Thread.new do
|
24
|
+
|
25
|
+
query = "select * from campus_zips"
|
26
|
+
puts "sending query on connection #{i}"
|
27
|
+
conn = $connections[i]
|
28
|
+
result = conn.async_query(query)
|
29
|
+
if use_the_all_hashes_method
|
30
|
+
saved = result.all_hashes
|
31
|
+
else
|
32
|
+
saved = []
|
33
|
+
result.each_hash {|h| saved << h }
|
34
|
+
end
|
35
|
+
result.free
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
puts 'waiting on threads'
|
41
|
+
$threads.each{|t| t.join }
|
42
|
+
|
43
|
+
puts Time.now - $start
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'mysqlplus'
|
3
|
+
begin
|
4
|
+
Mysql.real_connect('fakehost','root', '', 'local_leadgen_dev')
|
5
|
+
rescue Mysql::Error
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
Mysql.real_connect('localhost','root', '', 'faketable')
|
9
|
+
rescue Mysql::Error
|
10
|
+
end
|
11
|
+
begin
|
12
|
+
Mysql.real_connect('localhost', 'root', 'pass', 'db', 3307)# bad port
|
13
|
+
rescue Mysql::Error
|
14
|
+
end
|
15
|
+
print "pass"
|
16
|
+
|
17
|
+
|
data/test/test_helper.rb
CHANGED
@@ -12,7 +12,7 @@ class MysqlTest
|
|
12
12
|
:connection_signature,
|
13
13
|
:start,
|
14
14
|
:done,
|
15
|
-
:
|
15
|
+
:query_with,
|
16
16
|
:per_query_overhead,
|
17
17
|
:timeout
|
18
18
|
|
@@ -20,7 +20,7 @@ class MysqlTest
|
|
20
20
|
@queries = queries
|
21
21
|
@context = context
|
22
22
|
@done = []
|
23
|
-
@
|
23
|
+
@query_with = :async_query
|
24
24
|
@per_query_overhead = 3
|
25
25
|
@timeout = 20
|
26
26
|
yield self if block_given?
|
@@ -78,7 +78,7 @@ class MysqlTest
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def c_or_native_ruby_async_query
|
81
|
-
if @c_async_query
|
81
|
+
if @query_with == :c_async_query
|
82
82
|
log "** using C based async_query"
|
83
83
|
else
|
84
84
|
log "** using native Ruby async_query"
|
@@ -86,9 +86,8 @@ class MysqlTest
|
|
86
86
|
yield
|
87
87
|
end
|
88
88
|
|
89
|
-
def
|
90
|
-
|
91
|
-
connection.send( method, sql, timeout )
|
89
|
+
def dispatch_query( connection, sql, timeout = nil )
|
90
|
+
connection.send( @query_with, sql, timeout )
|
92
91
|
end
|
93
92
|
|
94
93
|
end
|
@@ -188,7 +187,7 @@ class ThreadedMysqlTest < MysqlTest
|
|
188
187
|
|
189
188
|
log "sending query on connection #{conn}"
|
190
189
|
|
191
|
-
|
190
|
+
dispatch_query( @connections[conn], "select sleep(#{@per_query_overhead})", @timeout ).each do |result|
|
192
191
|
log "connection #{conn} done"
|
193
192
|
end
|
194
193
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# This is an example of using Mysql::ResultSet#use_result [see docs for what that does]
|
2
|
+
# this function is useful for those who have large query results and want to be able to parse them
|
3
|
+
# as they come in, instead of having to wait for the query to finish before doing parsing
|
4
|
+
# for me, running this on a query with 200_000 lines decreases total time to create an array of results
|
5
|
+
# from .82s to .62s
|
6
|
+
# you can experiment with it by changing the query here to be a long one, and toggling the do_the_use_query_optimization variable
|
7
|
+
# this also has the interesting property of 'freeing' Ruby to do thread changes mid-query.
|
8
|
+
require 'rubygems'
|
9
|
+
require 'mysqlplus'
|
10
|
+
|
11
|
+
do_the_use_query_optimization = true
|
12
|
+
|
13
|
+
$count = 5
|
14
|
+
|
15
|
+
$start = Time.now
|
16
|
+
|
17
|
+
$connections = []
|
18
|
+
$count.times do
|
19
|
+
$connections << Mysql.real_connect('localhost','root', '', 'local_leadgen_dev')
|
20
|
+
end
|
21
|
+
|
22
|
+
puts 'connection pool ready'
|
23
|
+
|
24
|
+
$threads = []
|
25
|
+
$count.times do |i|
|
26
|
+
$threads << Thread.new do
|
27
|
+
|
28
|
+
puts "sending query on connection #{i}"
|
29
|
+
conn = $connections[i]
|
30
|
+
saved = []
|
31
|
+
query = "select * from campus_zips"
|
32
|
+
if do_the_use_query_optimization
|
33
|
+
conn.query_with_result=false
|
34
|
+
result = conn.async_query(query)
|
35
|
+
res = result.use_result
|
36
|
+
res.each_hash { |h| saved << h }
|
37
|
+
res.free
|
38
|
+
else
|
39
|
+
conn.async_query(query).each_hash {|h| saved << h }
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
puts 'waiting on threads'
|
46
|
+
$threads.each{|t| t.join }
|
47
|
+
|
48
|
+
puts Time.now - $start
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sequel'
|
3
|
+
|
4
|
+
require 'mysqlplus'
|
5
|
+
class Mysql
|
6
|
+
unless method_defined? :sync_query
|
7
|
+
alias :sync_query :query
|
8
|
+
alias :query :async_query
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
DB = Sequel.connect('mysql://root@localhost', :max_connections => 20)
|
13
|
+
|
14
|
+
start = Time.now
|
15
|
+
|
16
|
+
(0..10).map do
|
17
|
+
Thread.new do
|
18
|
+
|
19
|
+
p DB['select sleep(2)'].all
|
20
|
+
|
21
|
+
end
|
22
|
+
end.map{|t| t.join }
|
23
|
+
|
24
|
+
p (Time.now - start)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oldmoe-mysqlplus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Muhammad A. Ali
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-03-22 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -22,17 +22,23 @@ extensions:
|
|
22
22
|
extra_rdoc_files:
|
23
23
|
- README
|
24
24
|
files:
|
25
|
-
- mysqlplus.gemspec
|
26
25
|
- README
|
27
26
|
- Rakefile
|
28
|
-
-
|
29
|
-
- test/test_helper.rb
|
30
|
-
- test/native_threaded_test.rb
|
31
|
-
- test/c_threaded_test.rb
|
32
|
-
- test/evented_test.rb
|
27
|
+
- TODO_LIST
|
33
28
|
- ext/error_const.h
|
34
29
|
- ext/extconf.rb
|
35
30
|
- ext/mysql.c
|
31
|
+
- lib/mysqlplus.rb
|
32
|
+
- mysqlplus.gemspec
|
33
|
+
- test/c_threaded_test.rb
|
34
|
+
- test/evented_test.rb
|
35
|
+
- test/native_threaded_test.rb
|
36
|
+
- test/test_all_hashes.rb
|
37
|
+
- test/test_failure.rb
|
38
|
+
- test/test_helper.rb
|
39
|
+
- test/test_many_requests.rb
|
40
|
+
- test/test_parsing_while_response_is_being_read.rb
|
41
|
+
- test/test_threaded_sequel.rb
|
36
42
|
has_rdoc: true
|
37
43
|
homepage: http://github.com/oldmoe/mysqlplus
|
38
44
|
post_install_message:
|