fix signal handling when waiting on queries
This reverts the single-threaded select() optimization from commits9a63a587c0
and0190457dbd
. Under Ruby 1.9, the reverted optimization caused signal handlers to be delayed until the socket became readable. Under Ruby 1.8, matters are worse as receiving a signal during select() causes Errno::EINTR to be raised. There is now a (somewhat fragile) spec for testing signal handling during a "SELECT sleep(2)" query. Furthermore, the performance difference I measured on benchmark/thread_alone.rb was negligible (over 1000 iterations) between the two: Ruby 1.8.7-p249 Rehearsal ---------------------------------------------------- select 0.040000 0.020000 0.060000 ( 0.119448) rb_thread_select 0.050000 0.020000 0.070000 ( 0.132091) ------------------------------------------- total: 0.130000sec user system total real select 0.030000 0.030000 0.060000 ( 0.116471) rb_thread_select 0.050000 0.020000 0.070000 ( 0.119874) Ruby 1.9.2-p0 Rehearsal ---------------------------------------------------- select 0.050000 0.030000 0.080000 ( 0.134208) rb_thread_select 0.080000 0.000000 0.080000 ( 0.141316) ------------------------------------------- total: 0.160000sec user system total real select 0.050000 0.020000 0.070000 ( 0.123325) rb_thread_select 0.060000 0.010000 0.070000 ( 0.124075) Benchmarks were performed on an _empty_ mysql2_test table to maximize the relative time for the select(2)-related code path (vs reading data). The test was run on Debian Lenny, x86_64 and a stock 2.6.35.2 Linux kernel. Hardware was a Core2 Duo @ 1.6GHz with the performance CPU governor while on AC power to eliminate CPU speed fluctuations during the test.
This commit is contained in:
parent
d990f68320
commit
8bfbfa2708
@ -257,7 +257,6 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
|||||||
int fd, retval;
|
int fd, retval;
|
||||||
int async = 0;
|
int async = 0;
|
||||||
VALUE opts, defaults;
|
VALUE opts, defaults;
|
||||||
int(*selector)(int, fd_set *, fd_set *, fd_set *, struct timeval *) = NULL;
|
|
||||||
GET_CLIENT(self)
|
GET_CLIENT(self)
|
||||||
|
|
||||||
REQUIRE_OPEN_DB(client);
|
REQUIRE_OPEN_DB(client);
|
||||||
@ -299,12 +298,11 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
|||||||
// 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
|
||||||
fd = client->net.fd;
|
fd = client->net.fd;
|
||||||
selector = rb_thread_alone() ? *select : *rb_thread_select;
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
FD_SET(fd, &fdset);
|
FD_SET(fd, &fdset);
|
||||||
|
|
||||||
retval = selector(fd + 1, &fdset, NULL, NULL, NULL);
|
retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, NULL);
|
||||||
|
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
rb_sys_fail(0);
|
rb_sys_fail(0);
|
||||||
|
@ -78,6 +78,33 @@ describe Mysql2::Client do
|
|||||||
@client.query("SELECT 1")
|
@client.query("SELECT 1")
|
||||||
}.should raise_error(Mysql2::Error)
|
}.should raise_error(Mysql2::Error)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# XXX this test is not deterministic (because Unix signal handling is not)
|
||||||
|
# and may fail on a loaded system
|
||||||
|
it "should run signal handlers while waiting for a response" do
|
||||||
|
mark = {}
|
||||||
|
trap(:USR1) { mark[:USR1] = Time.now }
|
||||||
|
begin
|
||||||
|
mark[:START] = Time.now
|
||||||
|
pid = fork do
|
||||||
|
sleep 1 # wait for client "SELECT sleep(2)" query to start
|
||||||
|
Process.kill(:USR1, Process.ppid)
|
||||||
|
sleep # wait for explicit kill to prevent GC disconnect
|
||||||
|
end
|
||||||
|
@client.query("SELECT sleep(2)")
|
||||||
|
mark[:END] = Time.now
|
||||||
|
mark.include?(:USR1).should be_true
|
||||||
|
(mark[:USR1] - mark[:START]).should >= 1
|
||||||
|
(mark[:USR1] - mark[:START]).should < 1.1
|
||||||
|
(mark[:END] - mark[:USR1]).should > 0.9
|
||||||
|
(mark[:END] - mark[:START]).should >= 2
|
||||||
|
(mark[:END] - mark[:START]).should < 2.1
|
||||||
|
Process.kill(:TERM, pid)
|
||||||
|
Process.waitpid2(pid)
|
||||||
|
ensure
|
||||||
|
trap(:USR1, 'DEFAULT')
|
||||||
|
end
|
||||||
|
end if RUBY_PLATFORM !~ /mingw|mswin/
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should respond to #escape" do
|
it "should respond to #escape" do
|
||||||
|
Loading…
Reference in New Issue
Block a user