From 19b4b10d27d34a90c71ffb9b09dd52956b49c3f9 Mon Sep 17 00:00:00 2001 From: Lourens Naude Date: Fri, 5 Sep 2008 23:55:00 +0100 Subject: [PATCH 1/4] Sneak in optional timeout argument as a stub to the C version of Mysql.send_query --- ext/mysql.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ext/mysql.c b/ext/mysql.c index fb7536a..eba94e2 100644 --- a/ext/mysql.c +++ b/ext/mysql.c @@ -756,10 +756,14 @@ static VALUE socket(VALUE obj) return INT2NUM(vio_fd(m->net.vio)); } -/* send_query */ -static VALUE send_query(VALUE obj, VALUE sql) +/* send_query(sql,timeout=nil) */ +static VALUE send_query(int argc, VALUE* argv, VALUE obj) { MYSQL* m = GetHandler(obj); + VALUE sql, timeout; + + rb_scan_args(argc, argv, "11", &sql, &timeout); + Check_Type(sql, T_STRING); if (GetMysqlStruct(obj)->connection == Qfalse) { rb_raise(eMysql, "query: not connected"); @@ -2086,7 +2090,7 @@ void Init_mysql(void) rb_define_method(cMysql, "query", query, 1); rb_define_method(cMysql, "real_query", query, 1); /*rb_define_method(cMysql, "async_query", async_query, 1);*/ - rb_define_method(cMysql, "send_query", send_query, 1); + rb_define_method(cMysql, "send_query", send_query, -1); rb_define_method(cMysql, "get_result", get_result, 0); rb_define_method(cMysql, "socket", socket, 0); rb_define_method(cMysql, "refresh", refresh, 1); From 951fa1d2729c898376a6f73c6ab29e1c7299eafe Mon Sep 17 00:00:00 2001 From: Lourens Naude Date: Sat, 6 Sep 2008 00:01:09 +0100 Subject: [PATCH 2/4] Access the file descriptor directly from the MySQL net structure --- ext/mysql.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mysql.c b/ext/mysql.c index eba94e2..95f95fe 100644 --- a/ext/mysql.c +++ b/ext/mysql.c @@ -753,7 +753,7 @@ static VALUE query(VALUE obj, VALUE sql) static VALUE socket(VALUE obj) { MYSQL* m = GetHandler(obj); - return INT2NUM(vio_fd(m->net.vio)); + return INT2NUM(m->net.fd); } /* send_query(sql,timeout=nil) */ From 91d9096b14014f6535595afecea45c31f2c867e3 Mon Sep 17 00:00:00 2001 From: Lourens Naude Date: Sat, 6 Sep 2008 00:54:48 +0100 Subject: [PATCH 3/4] Extract base klasses for cleaner implementation testing; DRY up existing threaded && evented tests --- test/evented_test.rb | 30 +-------- test/test_helper.rb | 152 +++++++++++++++++++++++++++++++++++++++++- test/threaded_test.rb | 32 ++------- 3 files changed, 158 insertions(+), 56 deletions(-) diff --git a/test/evented_test.rb b/test/evented_test.rb index 83ddf14..ec8ad3d 100644 --- a/test/evented_test.rb +++ b/test/evented_test.rb @@ -1,30 +1,6 @@ require File.dirname(__FILE__) + '/test_helper' -@count = 10 -@connections = {} -@count.times do - c = Mysql.real_connect('localhost','root','3421260') - @connections[IO.new(c.socket)] = c -end - -@sockets = @connections.keys - -@done = 0 -@t = Time.now -@connections.each_value do |c| - c.send_query('select sleep(1)') -end - -loop do - res = select(@sockets,nil,nil,nil) - if res - res.first.each do |c| - @connections[c].get_result.each{|r| p r} - @done = @done + 1 - if @done == @count - puts Time.now - @t - exit - end - end - end +EventedMysqlTest.new( 10 ) do |test| + test.setup{ Mysql.real_connect('localhost','root') } + test.run! end \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index b257359..3f5078c 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,2 +1,152 @@ require 'rubygems' -require 'mysqlplus' \ No newline at end of file +require 'mysqlplus' + +class MysqlTest + + class NotImplemented < StandardError + end + + attr_accessor :queries, + :connections, + :connection_signature, + :start, + :done + + def initialize( queries ) + @queries = queries + @done = [] + yield self if block_given? + end + + def setup( &block ) + @start = Time.now + @connection_signature = block + end + + def run! + raise NotImplemented + end + + def prepare + raise NotImplemented + end + + def teardown + raise NotImplemented + end + + def log( message, prefix = '' ) + puts "[#{timestamp}] #{prefix} #{message}" + end + + def with_logging( message ) + log( message, 'Start' ) + yield + log( message, 'End' ) + end + + def timestamp + Time.now - @start + end + +end + +class EventedMysqlTest < MysqlTest + + attr_accessor :sockets + + def initialize( queries ) + @sockets = [] + @connections = {} + super( queries ) + end + + def setup( &block ) + super( &block ) + with_logging 'Setup connection pool' do + @queries.times do + connection = @connection_signature.call + @connections[ IO.new(connection.socket) ] = connection + @sockets = @connections.keys + end + end + end + + def run! + prepare + + loop do + result = select( @sockets,nil,nil,nil ) + if result + result.first.each do |conn| + @connections[conn].get_result.each{|res| log( "Result for socket #{conn.fileno} : #{res}" ) } + @done << nil + teardown if done? + end + end + end + end + + def prepare + @connections.each_value do |conn| + conn.send_query( "select sleep(3)" ) + end + end + + def teardown + log "done" + exit + end + + protected + + def done? + @done.size == @queries + end + +end + +class ThreadedMysqlTest < MysqlTest + + attr_accessor :threads + + def initialize( queries ) + @connections = [] + @threads = [] + super( queries ) + end + + def setup( &block ) + super( &block ) + with_logging "Setup connection pool" do + @queries.times do + @connections << @connection_signature.call + end + end + end + + def run! + prepare + + with_logging "waiting on threads" do + @threads.each{|t| t.join } + end + end + + def prepare + with_logging "prepare" do + @queries.times do |conn| + @threads << Thread.new do + + log "sending query on connection #{conn}" + + @connections[conn].async_query( "select sleep(3)" ).each do |result| + log "connection #{conn} done" + end + + end + end + end + end + +end \ No newline at end of file diff --git a/test/threaded_test.rb b/test/threaded_test.rb index 3bc75c3..7a18a26 100644 --- a/test/threaded_test.rb +++ b/test/threaded_test.rb @@ -1,30 +1,6 @@ require File.dirname(__FILE__) + '/test_helper' -$count = 10 - -$start = Time.now - -$connections = [] -$count.times do - $connections << Mysql.real_connect('localhost','root','3421260') -end - -puts 'connection pool ready' - -$threads = [] -$count.times do |i| - $threads << Thread.new do - - puts "sending query on connection #{i}" - - $connections[i].async_query("select sleep(3)").each{ |r| - puts "connection #{i} done" - } - - end -end - -puts 'waiting on threads' -$threads.each{|t| t.join } - -puts Time.now - $start \ No newline at end of file +ThreadedMysqlTest.new( 10 ) do |test| + test.setup{ Mysql.real_connect('localhost','root') } + test.run! +end \ No newline at end of file From 8e1cd8ea20bcbbdc6dd3da136c197c49f0c81001 Mon Sep 17 00:00:00 2001 From: oldmoe Date: Sat, 6 Sep 2008 03:59:20 +0200 Subject: [PATCH 4/4] fix for corrupted utf-8 results --- ext/mysql.c | 5 +++-- lib/mysqlplus.rb | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ext/mysql.c b/ext/mysql.c index fb7536a..09acf28 100644 --- a/ext/mysql.c +++ b/ext/mysql.c @@ -1272,7 +1272,8 @@ static VALUE each_hash(int argc, VALUE* argv, VALUE obj) rb_scan_args(argc, argv, "01", &with_table); if (with_table == Qnil) with_table = Qfalse; - process_all_hashes(obj, with_table, 0, 1); + while ((hash = fetch_hash2(obj, with_table)) != Qnil) + rb_yield(hash); return obj; } @@ -2240,7 +2241,7 @@ void Init_mysql(void) rb_define_method(cMysqlRes, "row_tell", row_tell, 0); rb_define_method(cMysqlRes, "each", each, 0); rb_define_method(cMysqlRes, "each_hash", each_hash, -1); - rb_define_method(cMysqlRes, "all_hashes", all_hashes, -1); + /*rb_define_method(cMysqlRes, "all_hashes", all_hashes, -1);*/ /* MysqlField object method */ rb_define_method(cMysqlField, "name", field_name, 0); diff --git a/lib/mysqlplus.rb b/lib/mysqlplus.rb index 76bad4c..474eeb3 100644 --- a/lib/mysqlplus.rb +++ b/lib/mysqlplus.rb @@ -7,3 +7,11 @@ class Mysql get_result end end + +class Mysql::Result + def all_hashes + rows = [] + each_hash { |row| rows << row } + rows + end +end