add support for :read_timeout to be set on a connection

This commit is contained in:
Brian Lopez 2010-11-09 12:27:04 -08:00
parent 99766a2303
commit d48846f13b
3 changed files with 41 additions and 2 deletions

View File

@ -264,7 +264,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
fd_set fdset; fd_set fdset;
int fd, retval; int fd, retval;
int async = 0; int async = 0;
VALUE opts, defaults; VALUE opts, defaults, read_timeout;
GET_CLIENT(self); GET_CLIENT(self);
REQUIRE_OPEN_DB(wrapper); REQUIRE_OPEN_DB(wrapper);
@ -303,6 +303,23 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
return rb_raise_mysql2_error(wrapper->client); return rb_raise_mysql2_error(wrapper->client);
} }
read_timeout = rb_iv_get(self, "@read_timeout");
struct timeval tv;
struct timeval* tvp = NULL;
if (!NIL_P(read_timeout)) {
Check_Type(read_timeout, T_FIXNUM);
tvp = &tv;
long int sec = FIX2INT(read_timeout);
// TODO: support partial seconds?
// also, this check is here for sanity, we also check up in Ruby
if (sec >= 0) {
tvp->tv_sec = sec;
} else {
rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %d", sec);
}
tvp->tv_usec = 0;
}
if (!async) { if (!async) {
// the below code is largely from do_mysql // the below code is largely from do_mysql
// http://github.com/datamapper/do // http://github.com/datamapper/do
@ -311,7 +328,11 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(fd, &fdset); FD_SET(fd, &fdset);
retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, NULL); retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, tvp);
if (retval == 0) {
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
}
if (retval < 0) { if (retval < 0) {
rb_sys_fail(0); rb_sys_fail(0);

View File

@ -24,6 +24,11 @@ module Mysql2
# force the encoding to utf8 # force the encoding to utf8
self.charset_name = opts[:encoding] || 'utf8' self.charset_name = opts[:encoding] || 'utf8'
@read_timeout = opts[:read_timeout]
if @read_timeout and @read_timeout < 0
raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
end
ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper)) ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper))
user = opts[:username] user = opts[:username]

View File

@ -85,6 +85,12 @@ describe Mysql2::Client do
@client.should respond_to(:query) @client.should respond_to(:query)
end end
it "should expect read_timeout to be a positive integer" do
lambda {
Mysql2::Client.new(:read_timeout => -1)
}.should raise_error(Mysql2::Error)
end
context "#query" do context "#query" do
it "should only accept strings as the query parameter" do it "should only accept strings as the query parameter" do
lambda { lambda {
@ -124,6 +130,13 @@ describe Mysql2::Client do
}.should raise_error(Mysql2::Error) }.should raise_error(Mysql2::Error)
end end
it "should timeout if we wait longer than :read_timeout" do
client = Mysql2::Client.new(:read_timeout => 1)
lambda {
client.query("SELECT sleep(2)")
}.should raise_error(Mysql2::Error)
end
# XXX this test is not deterministic (because Unix signal handling is not) # XXX this test is not deterministic (because Unix signal handling is not)
# and may fail on a loaded system # and may fail on a loaded system
if RUBY_PLATFORM !~ /mingw|mswin/ if RUBY_PLATFORM !~ /mingw|mswin/