merging in latest from master

This commit is contained in:
Brian Lopez 2010-10-17 17:43:24 -07:00
commit 6c4fd8a9ca
10 changed files with 114 additions and 146 deletions

2
.rspec Normal file
View File

@ -0,0 +1,2 @@
--format documentation
--colour

View File

@ -1,49 +1,5 @@
# encoding: UTF-8 # encoding: UTF-8
begin
require 'rubygems'
require 'jeweler'
JEWELER = Jeweler::Tasks.new do |gem|
gem.name = "mysql2"
gem.summary = "A simple, fast Mysql library for Ruby, binding to libmysql"
gem.email = "seniorlopez@gmail.com"
gem.homepage = "http://github.com/brianmario/mysql2"
gem.authors = ["Brian Lopez"]
gem.require_paths = ["lib", "ext"]
gem.extra_rdoc_files = `git ls-files *.rdoc`.split("\n")
gem.files = `git ls-files`.split("\n")
gem.extensions = ["ext/mysql2/extconf.rb"]
gem.files.include %w(lib/jeweler/templates/.document lib/jeweler/templates/.gitignore)
# gem.rubyforge_project = "mysql2"
end
rescue LoadError
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler -s http://gems.github.com"
end
require 'rake' require 'rake'
require 'spec/rake/spectask'
desc "Run all examples with RCov"
Spec::Rake::SpecTask.new('spec:rcov') do |t|
t.spec_files = FileList['spec/']
t.rcov = true
t.rcov_opts = lambda do
IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
end
end
Spec::Rake::SpecTask.new('spec') do |t|
t.spec_files = FileList['spec/']
t.spec_opts << '--options' << 'spec/spec.opts'
t.verbose = true
t.warning = true
end
Spec::Rake::SpecTask.new('spec:gdb') do |t|
t.spec_files = FileList['spec/']
t.spec_opts << '--options' << 'spec/spec.opts'
t.ruby_cmd = "gdb --args #{RUBY}"
end
task :default => :spec
# Load custom tasks # Load custom tasks
Dir['tasks/*.rake'].sort.each { |f| load f } Dir['tasks/*.rake'].sort.each { |f| load f }

View File

@ -1,20 +0,0 @@
# encoding: UTF-8
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
require 'rubygems'
require 'benchmark'
require 'mysql2'
iterations = 1000
client = Mysql2::Client.new(:host => "localhost", :username => "root", :database => "test")
query = lambda{ iterations.times{ client.query("SELECT mysql2_test.* FROM mysql2_test") } }
Benchmark.bmbm do |x|
x.report('select') do
query.call
end
x.report('rb_thread_select') do
thread = Thread.new{ sleep(10) }
query.call
thread.kill
end
end

View File

@ -104,62 +104,56 @@ static VALUE nogvl_connect(void *ptr) {
return client ? Qtrue : Qfalse; return client ? Qtrue : Qfalse;
} }
static void rb_mysql_client_free(void * ptr) { static VALUE nogvl_close(void *ptr) {
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
/*
* we'll send a QUIT message to the server, but that message is more of a
* formality than a hard requirement since the socket is getting shutdown
* anyways, so ensure the socket write does not block our interpreter
*/
int fd = wrapper->client->net.fd;
if (fd >= 0) {
/*
* if the socket is dead we have no chance of blocking,
* so ignore any potential fcntl errors since they don't matter
*/
#ifndef _WIN32
int flags = fcntl(fd, F_GETFL);
if (flags > 0 && !(flags & O_NONBLOCK))
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
u_long iMode = 1;
ioctlsocket(fd, FIONBIO, &iMode);
#endif
}
/* It's safe to call mysql_close() on an already closed connection. */
if (!wrapper->closed) {
mysql_close(wrapper->client);
if (!wrapper->freed) {
free(wrapper->client);
}
}
xfree(ptr);
}
static VALUE nogvl_close(void * ptr) {
mysql_client_wrapper *wrapper = ptr; mysql_client_wrapper *wrapper = ptr;
if (!wrapper->closed) { if (!wrapper->closed) {
wrapper->closed = 1; wrapper->closed = 1;
/*
* we'll send a QUIT message to the server, but that message is more of a
* formality than a hard requirement since the socket is getting shutdown
* anyways, so ensure the socket write does not block our interpreter
*/
int fd = wrapper->client->net.fd;
if (fd >= 0) {
/*
* if the socket is dead we have no chance of blocking,
* so ignore any potential fcntl errors since they don't matter
*/
#ifndef _WIN32
int flags = fcntl(fd, F_GETFL);
if (flags > 0 && !(flags & O_NONBLOCK))
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
u_long iMode = 1;
ioctlsocket(fd, FIONBIO, &iMode);
#endif
}
mysql_close(wrapper->client); mysql_close(wrapper->client);
wrapper->client->net.fd = -1; wrapper->client->net.fd = -1;
if (!wrapper->freed) { free(wrapper->client);
free(wrapper->client);
}
} }
return Qnil; return Qnil;
} }
static void rb_mysql_client_free(void * ptr) {
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
nogvl_close(wrapper);
xfree(ptr);
}
static VALUE allocate(VALUE klass) { static VALUE allocate(VALUE klass) {
VALUE obj; VALUE obj;
mysql_client_wrapper * wrapper; mysql_client_wrapper * wrapper;
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper); obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
wrapper->encoding = Qnil; wrapper->encoding = Qnil;
wrapper->active = 0; wrapper->active = 0;
wrapper->closed = 0; wrapper->closed = 1;
wrapper->freed = 0;
wrapper->client = (MYSQL*)malloc(sizeof(MYSQL)); wrapper->client = (MYSQL*)malloc(sizeof(MYSQL));
return obj; return obj;
} }
@ -523,6 +517,7 @@ static VALUE init_connection(VALUE self) {
return rb_raise_mysql2_error(wrapper->client); return rb_raise_mysql2_error(wrapper->client);
} }
wrapper->closed = 0;
return self; return self;
} }

View File

@ -35,7 +35,6 @@ typedef struct {
VALUE encoding; VALUE encoding;
short int active; short int active;
short int closed; short int closed;
short int freed;
MYSQL *client; MYSQL *client;
} mysql_client_wrapper; } mysql_client_wrapper;

View File

@ -1,45 +1,49 @@
# encoding: UTF-8 # encoding: UTF-8
require 'spec_helper' if defined? EventMachine
require 'mysql2/em' require 'spec_helper'
require 'mysql2/em'
describe Mysql2::EM::Client do describe Mysql2::EM::Client do
it "should support async queries" do it "should support async queries" do
results = [] results = []
EM.run do EM.run do
client1 = Mysql2::EM::Client.new client1 = Mysql2::EM::Client.new
defer1 = client1.query "SELECT sleep(0.1) as first_query" defer1 = client1.query "SELECT sleep(0.1) as first_query"
defer1.callback do |result| defer1.callback do |result|
results << result.first
EM.stop_event_loop
end
client2 = Mysql2::EM::Client.new
defer2 = client2.query "SELECT sleep(0.025) second_query"
defer2.callback do |result|
results << result.first
end
end
results[0].keys.should include("second_query")
results[1].keys.should include("first_query")
end
it "should support queries in callbacks" do
results = []
EM.run do
client = Mysql2::EM::Client.new
defer1 = client.query "SELECT sleep(0.025) as first_query"
defer1.callback do |result|
results << result.first
defer2 = client.query "SELECT sleep(0.025) as second_query"
defer2.callback do |result|
results << result.first results << result.first
EM.stop_event_loop EM.stop_event_loop
end end
client2 = Mysql2::EM::Client.new
defer2 = client2.query "SELECT sleep(0.025) second_query"
defer2.callback do |result|
results << result.first
end
end end
results[0].keys.should include("second_query")
results[1].keys.should include("first_query")
end end
results[0].keys.should include("first_query") it "should support queries in callbacks" do
results[1].keys.should include("second_query") results = []
EM.run do
client = Mysql2::EM::Client.new
defer1 = client.query "SELECT sleep(0.025) as first_query"
defer1.callback do |result|
results << result.first
defer2 = client.query "SELECT sleep(0.025) as second_query"
defer2.callback do |result|
results << result.first
EM.stop_event_loop
end
end
end
results[0].keys.should include("first_query")
results[1].keys.should include("second_query")
end
end end
end else
puts "EventMachine not installed, skipping the specs that use it"
end

View File

@ -1,2 +0,0 @@
--format specdoc
--colour

View File

@ -1,10 +1,11 @@
# encoding: UTF-8 # encoding: UTF-8
require 'rubygems' $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
require 'rspec'
require 'mysql2' require 'mysql2'
require 'timeout' require 'timeout'
Spec::Runner.configure do |config| RSpec.configure do |config|
config.before(:all) do config.before(:all) do
client = Mysql2::Client.new :database => 'test' client = Mysql2::Client.new :database => 'test'
client.query %[ client.query %[

17
tasks/jeweler.rake Normal file
View File

@ -0,0 +1,17 @@
begin
require 'jeweler'
JEWELER = Jeweler::Tasks.new do |gem|
gem.name = "mysql2"
gem.summary = "A simple, fast Mysql library for Ruby, binding to libmysql"
gem.email = "seniorlopez@gmail.com"
gem.homepage = "http://github.com/brianmario/mysql2"
gem.authors = ["Brian Lopez"]
gem.require_paths = ["lib", "ext"]
gem.extra_rdoc_files = `git ls-files *.rdoc`.split("\n")
gem.files = `git ls-files`.split("\n")
gem.extensions = ["ext/mysql2/extconf.rb"]
gem.files.include %w(lib/jeweler/templates/.document lib/jeweler/templates/.gitignore)
end
rescue LoadError
puts "jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
end

16
tasks/rspec.rake Normal file
View File

@ -0,0 +1,16 @@
begin
require 'rspec'
require 'rspec/core/rake_task'
desc "Run all examples with RCov"
RSpec::Core::RakeTask.new('spec:rcov') do |t|
t.rcov = true
end
RSpec::Core::RakeTask.new('spec') do |t|
t.verbose = true
end
task :default => :spec
rescue LoadError
puts "rspec, or one of its dependencies, is not available. Install it with: sudo gem install rspec"
end