Skip to content

Commit 47a37df

Browse files
committed
Ensure that the socket is always checked in after send_message_with_gle
Previously, unhandled exceptions could cause the driver to leave a pool entry checked out indefinitely and would stall any other attempts from the same thread to check out the item, as the orphaned socket was the thread-affiliated socket. Fix syntax to be 1.8-compatible
1 parent 22f52c4 commit 47a37df

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed

lib/mongo/networking.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,15 @@ def send_message_with_gle(operation, message, db_name, log_message=nil, write_co
8686
sock = checkout_writer
8787
send_message_on_socket(packed_message, sock)
8888
docs, num_received, cursor_id = receive(sock, last_error_id)
89-
checkin(sock)
9089
rescue ConnectionFailure, OperationFailure, OperationTimeout => ex
91-
checkin(sock)
9290
raise ex
9391
rescue SystemStackError, NoMemoryError, SystemCallError => ex
9492
close
93+
sock = nil
9594
raise ex
95+
ensure
96+
checkin(sock) if sock
97+
sock = nil
9698
end
9799

98100
if num_received == 1

test/functional/client_test.rb

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ def test_operation_timeout_with_active
519519
context "Socket pools" do
520520
context "checking out writers" do
521521
setup do
522-
@con = standard_connection(:pool_size => 10, :pool_timeout => 10)
522+
@con = standard_connection(:pool_size => 10, :pool_timeout => 2)
523523
@coll = @con[TEST_DB]['test-connection-exceptions']
524524
end
525525

@@ -533,13 +533,42 @@ def test_operation_timeout_with_active
533533
end
534534
end
535535

536-
should "close the connection on send_message_with_gle for major exceptions" do
537-
@con.stubs(:checkout_writer).raises(SystemStackError)
538-
@con.stubs(:checkout_reader).raises(SystemStackError)
539-
@con.expects(:close)
540-
begin
541-
@coll.insert({:foo => "bar"}, :w => 1)
542-
rescue SystemStackError
536+
context "with GLE" do
537+
setup do
538+
# Force this connection to use send_message_with_gle for these tests
539+
@con.stubs(:use_write_command?).returns(false)
540+
end
541+
542+
should "close the connection on send_message_with_gle for major exceptions" do
543+
@con.stubs(:checkout_writer).raises(SystemStackError)
544+
@con.stubs(:checkout_reader).raises(SystemStackError)
545+
@con.expects(:close)
546+
begin
547+
@coll.insert({:foo => "bar"}, :w => 1)
548+
rescue SystemStackError
549+
end
550+
end
551+
552+
should "release the connection on send_message_with_gle for connection exceptions" do
553+
mock_writer = mock(:close => true)
554+
mock_writer.expects(:read).raises(ConnectionFailure)
555+
@con.expects(:send_message_on_socket)
556+
557+
@con.stubs(:checkout_writer).returns(mock_writer)
558+
@con.expects(:checkin).with(mock_writer)
559+
@coll.insert({:foo => "bar"}, :w => 1) rescue nil
560+
end
561+
562+
should "release the connection on send_message_with_gle for all exceptions" do
563+
mock_writer = mock()
564+
mock_writer.expects(:read).raises(ArgumentError)
565+
@con.expects(:send_message_on_socket)
566+
@con.stubs(:checkout_writer).returns(mock_writer)
567+
@con.expects(:checkin).with(mock_writer).once
568+
begin
569+
@coll.insert({:foo => "bar"}, :w => 1)
570+
rescue ArgumentError
571+
end
543572
end
544573
end
545574

0 commit comments

Comments
 (0)