mongo 1.6.1 → 1.6.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +17 -16
- data/Rakefile +30 -24
- data/docs/HISTORY.md +10 -0
- data/docs/RELEASES.md +7 -0
- data/docs/REPLICA_SETS.md +2 -2
- data/docs/TUTORIAL.md +181 -84
- data/lib/mongo.rb +0 -3
- data/lib/mongo/collection.rb +1 -1
- data/lib/mongo/connection.rb +28 -20
- data/lib/mongo/db.rb +5 -3
- data/lib/mongo/exceptions.rb +1 -1
- data/lib/mongo/gridfs/grid_file_system.rb +1 -1
- data/lib/mongo/networking.rb +18 -18
- data/lib/mongo/repl_set_connection.rb +24 -3
- data/lib/mongo/util/node.rb +6 -16
- data/lib/mongo/util/pool.rb +8 -11
- data/lib/mongo/util/ssl_socket.rb +34 -12
- data/lib/mongo/util/tcp_socket.rb +92 -3
- data/lib/mongo/util/uri_parser.rb +2 -2
- data/lib/mongo/version.rb +1 -1
- data/test/auxillary/repl_set_auth_test.rb +19 -5
- data/test/bson/bson_test.rb +23 -21
- data/test/bson/json_test.rb +1 -1
- data/test/collection_test.rb +14 -4
- data/test/connection_test.rb +14 -11
- data/test/cursor_test.rb +4 -4
- data/test/grid_file_system_test.rb +3 -1
- data/test/grid_io_test.rb +2 -2
- data/test/grid_test.rb +13 -6
- data/test/pool_test.rb +0 -2
- data/test/replica_sets/basic_test.rb +1 -1
- data/test/replica_sets/complex_connect_test.rb +5 -4
- data/test/replica_sets/connect_test.rb +14 -6
- data/test/replica_sets/pooled_insert_test.rb +1 -1
- data/test/replica_sets/query_test.rb +2 -2
- data/test/replica_sets/read_preference_test.rb +1 -2
- data/test/replica_sets/refresh_test.rb +4 -2
- data/test/replica_sets/refresh_with_threads_test.rb +7 -13
- data/test/replica_sets/rs_test_helper.rb +1 -1
- data/test/test_helper.rb +6 -4
- data/test/threading/threading_with_large_pool_test.rb +1 -1
- data/test/threading_test.rb +2 -2
- data/test/timeout_test.rb +40 -0
- data/test/tools/repl_set_manager.rb +9 -8
- data/test/unit/connection_test.rb +6 -7
- data/test/unit/node_test.rb +1 -0
- data/test/unit/pool_manager_test.rb +2 -1
- data/test/uri_test.rb +1 -2
- metadata +13 -6
data/lib/mongo.rb
CHANGED
data/lib/mongo/collection.rb
CHANGED
@@ -961,7 +961,7 @@ module Mongo
|
|
961
961
|
begin
|
962
962
|
message.put_binary(BSON::BSON_CODER.serialize(doc, check_keys, true, @connection.max_bson_size).to_s)
|
963
963
|
true
|
964
|
-
rescue StandardError
|
964
|
+
rescue StandardError # StandardError will be replaced with BSONError
|
965
965
|
doc.delete(:_id)
|
966
966
|
error_docs << doc
|
967
967
|
false
|
data/lib/mongo/connection.rb
CHANGED
@@ -26,7 +26,7 @@ module Mongo
|
|
26
26
|
include Mongo::Logging
|
27
27
|
include Mongo::Networking
|
28
28
|
|
29
|
-
TCPSocket = ::TCPSocket
|
29
|
+
TCPSocket = Mongo::TCPSocket
|
30
30
|
Mutex = ::Mutex
|
31
31
|
ConditionVariable = ::ConditionVariable
|
32
32
|
|
@@ -67,7 +67,7 @@ module Mongo
|
|
67
67
|
# logging negatively impacts performance; therefore, it should not be used for high-performance apps.
|
68
68
|
# @option opts [Integer] :pool_size (1) The maximum number of socket self.connections allowed per
|
69
69
|
# connection pool. Note: this setting is relevant only for multi-threaded applications.
|
70
|
-
# @option opts [Float] :
|
70
|
+
# @option opts [Float] :timeout (5.0) When all of the self.connections a pool are checked out,
|
71
71
|
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
72
72
|
# Note: this setting is relevant only for multi-threaded applications (which in Ruby are rare).
|
73
73
|
# @option opts [Float] :op_timeout (nil) The number of seconds to wait for a read operation to time out.
|
@@ -480,6 +480,12 @@ module Mongo
|
|
480
480
|
@max_bson_size
|
481
481
|
end
|
482
482
|
|
483
|
+
# Prefer primary pool but fall back to secondary
|
484
|
+
def checkout_best
|
485
|
+
connect unless connected?
|
486
|
+
@primary_pool.checkout
|
487
|
+
end
|
488
|
+
|
483
489
|
# Checkout a socket for reading (i.e., a secondary node).
|
484
490
|
# Note: this is overridden in ReplSetConnection.
|
485
491
|
def checkout_reader
|
@@ -513,6 +519,19 @@ module Mongo
|
|
513
519
|
end
|
514
520
|
end
|
515
521
|
|
522
|
+
# Excecutes block with the best available socket
|
523
|
+
def best_available_socket
|
524
|
+
socket = nil
|
525
|
+
begin
|
526
|
+
socket = checkout_best
|
527
|
+
yield socket
|
528
|
+
ensure
|
529
|
+
if socket
|
530
|
+
socket.pool.checkin(socket)
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
516
535
|
protected
|
517
536
|
|
518
537
|
def valid_opts
|
@@ -603,27 +622,16 @@ module Mongo
|
|
603
622
|
socket = nil
|
604
623
|
config = nil
|
605
624
|
|
606
|
-
|
607
|
-
|
608
|
-
socket = @socket_class.new(host, port)
|
609
|
-
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
610
|
-
end
|
611
|
-
else
|
612
|
-
socket = @socket_class.new(host, port)
|
613
|
-
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
614
|
-
end
|
625
|
+
socket = @socket_class.new(host, port, @op_timeout, @connect_timeout)
|
626
|
+
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
615
627
|
|
616
|
-
|
617
|
-
|
618
|
-
config = self['admin'].command({:ismaster => 1}, :socket => socket)
|
619
|
-
end
|
620
|
-
else
|
621
|
-
config = self['admin'].command({:ismaster => 1}, :socket => socket)
|
622
|
-
end
|
623
|
-
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
|
628
|
+
config = self['admin'].command({:ismaster => 1}, :socket => socket)
|
629
|
+
rescue OperationFailure, SocketError, SystemCallError, IOError
|
624
630
|
close
|
625
631
|
ensure
|
626
|
-
|
632
|
+
if socket
|
633
|
+
socket.close unless socket.closed?
|
634
|
+
end
|
627
635
|
end
|
628
636
|
|
629
637
|
config
|
data/lib/mongo/db.rb
CHANGED
@@ -17,7 +17,6 @@
|
|
17
17
|
# ++
|
18
18
|
|
19
19
|
require 'socket'
|
20
|
-
require 'timeout'
|
21
20
|
require 'thread'
|
22
21
|
|
23
22
|
module Mongo
|
@@ -111,10 +110,13 @@ module Mongo
|
|
111
110
|
if !save_auth
|
112
111
|
raise MongoArgumentError, "If using connection pooling, :save_auth must be set to true."
|
113
112
|
end
|
114
|
-
@connection.authenticate_pools
|
115
113
|
end
|
116
114
|
|
117
|
-
|
115
|
+
@connection.best_available_socket do |socket|
|
116
|
+
issue_authentication(username, password, save_auth, :socket => socket)
|
117
|
+
end
|
118
|
+
|
119
|
+
@connection.authenticate_pools
|
118
120
|
end
|
119
121
|
|
120
122
|
def issue_authentication(username, password, save_auth=true, opts={})
|
data/lib/mongo/exceptions.rb
CHANGED
@@ -71,7 +71,7 @@ module Mongo
|
|
71
71
|
class OperationFailure < MongoDBError; end
|
72
72
|
|
73
73
|
# Raised when a socket read operation times out.
|
74
|
-
class OperationTimeout <
|
74
|
+
class OperationTimeout < SocketError; end
|
75
75
|
|
76
76
|
# Raised when a client attempts to perform an invalid operation.
|
77
77
|
class InvalidOperation < MongoDBError; end
|
@@ -115,7 +115,7 @@ module Mongo
|
|
115
115
|
id = file.close
|
116
116
|
if versions
|
117
117
|
self.delete do
|
118
|
-
@files.find({'filename' => filename, '_id' => {'$ne' => id}}, :fields => ['_id'], :sort => ['uploadDate', -1], :skip => (versions -1))
|
118
|
+
@files.find({'filename' => filename, '_id' => {'$ne' => id}}, :fields => ['_id'], :sort => ['uploadDate', -1], :skip => (versions - 1))
|
119
119
|
end
|
120
120
|
end
|
121
121
|
end
|
data/lib/mongo/networking.rb
CHANGED
@@ -186,7 +186,10 @@ module Mongo
|
|
186
186
|
|
187
187
|
def receive_header(sock, expected_response, exhaust=false)
|
188
188
|
header = receive_message_on_socket(16, sock)
|
189
|
-
|
189
|
+
|
190
|
+
# unpacks to size, request_id, response_to
|
191
|
+
response_to = header.unpack('VVV')[2]
|
192
|
+
|
190
193
|
if !exhaust && expected_response != response_to
|
191
194
|
raise Mongo::ConnectionFailure, "Expected response #{expected_response} but got #{response_to}"
|
192
195
|
end
|
@@ -204,7 +207,10 @@ module Mongo
|
|
204
207
|
raise "Short read for DB response header; " +
|
205
208
|
"expected #{RESPONSE_HEADER_SIZE} bytes, saw #{header_buf.length}"
|
206
209
|
end
|
207
|
-
|
210
|
+
|
211
|
+
# unpacks to flags, cursor_id_a, cursor_id_b, starting_from, number_remaining
|
212
|
+
flags, cursor_id_a, cursor_id_b, _, number_remaining = header_buf.unpack('VVVVV')
|
213
|
+
|
208
214
|
check_response_flags(flags)
|
209
215
|
cursor_id = (cursor_id_b << 32) + cursor_id_a
|
210
216
|
[number_remaining, cursor_id]
|
@@ -294,11 +300,11 @@ module Mongo
|
|
294
300
|
# @return [Integer] number of bytes sent
|
295
301
|
def send_message_on_socket(packed_message, socket)
|
296
302
|
begin
|
297
|
-
total_bytes_sent = socket.send(packed_message
|
303
|
+
total_bytes_sent = socket.send(packed_message)
|
298
304
|
if total_bytes_sent != packed_message.size
|
299
305
|
packed_message.slice!(0, total_bytes_sent)
|
300
306
|
while packed_message.size > 0
|
301
|
-
byte_sent = socket.send(packed_message
|
307
|
+
byte_sent = socket.send(packed_message)
|
302
308
|
total_bytes_sent += byte_sent
|
303
309
|
packed_message.slice!(0, byte_sent)
|
304
310
|
end
|
@@ -314,22 +320,15 @@ module Mongo
|
|
314
320
|
# Requires length and an available socket.
|
315
321
|
def receive_message_on_socket(length, socket)
|
316
322
|
begin
|
317
|
-
if @op_timeout
|
318
|
-
message = nil
|
319
|
-
Mongo::TimeoutHandler.timeout(@op_timeout, OperationTimeout) do
|
320
|
-
message = receive_data(length, socket)
|
321
|
-
end
|
322
|
-
else
|
323
323
|
message = receive_data(length, socket)
|
324
|
-
|
325
|
-
|
326
|
-
close
|
324
|
+
rescue OperationTimeout, ConnectionFailure => ex
|
325
|
+
close
|
327
326
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
327
|
+
if ex.class == OperationTimeout
|
328
|
+
raise OperationTimeout, "Timed out waiting on socket read."
|
329
|
+
else
|
330
|
+
raise ConnectionFailure, "Operation failed with the following exception: #{ex}"
|
331
|
+
end
|
333
332
|
end
|
334
333
|
message
|
335
334
|
end
|
@@ -337,6 +336,7 @@ module Mongo
|
|
337
336
|
def receive_data(length, socket)
|
338
337
|
message = new_binary_string
|
339
338
|
socket.read(length, message)
|
339
|
+
|
340
340
|
raise ConnectionFailure, "connection closed" unless message && message.length > 0
|
341
341
|
if message.length < length
|
342
342
|
chunk = new_binary_string
|
@@ -287,14 +287,18 @@ module Mongo
|
|
287
287
|
end
|
288
288
|
|
289
289
|
def authenticate_pools
|
290
|
-
primary_pool
|
290
|
+
if primary_pool
|
291
|
+
primary_pool.authenticate_existing
|
292
|
+
end
|
291
293
|
secondary_pools.each do |pool|
|
292
294
|
pool.authenticate_existing
|
293
295
|
end
|
294
296
|
end
|
295
297
|
|
296
298
|
def logout_pools(db)
|
297
|
-
primary_pool
|
299
|
+
if primary_pool
|
300
|
+
primary_pool.logout_existing(db)
|
301
|
+
end
|
298
302
|
secondary_pools.each do |pool|
|
299
303
|
pool.logout_existing(db)
|
300
304
|
end
|
@@ -323,6 +327,19 @@ module Mongo
|
|
323
327
|
raise ConnectionFailure.new("Could not checkout a socket.")
|
324
328
|
end
|
325
329
|
end
|
330
|
+
|
331
|
+
# Checkout best available socket by trying primary
|
332
|
+
# pool first and then falling back to secondary.
|
333
|
+
def checkout_best
|
334
|
+
checkout do
|
335
|
+
socket = get_socket_from_pool(:primary)
|
336
|
+
if !socket
|
337
|
+
connect
|
338
|
+
socket = get_socket_from_pool(:secondary)
|
339
|
+
end
|
340
|
+
socket
|
341
|
+
end
|
342
|
+
end
|
326
343
|
|
327
344
|
# Checkout a socket for reading (i.e., a secondary node).
|
328
345
|
# Note that @read_pool might point to the primary pool
|
@@ -459,7 +476,11 @@ module Mongo
|
|
459
476
|
|
460
477
|
# Refresh
|
461
478
|
@refresh_mode = opts.fetch(:refresh_mode, false)
|
462
|
-
@refresh_interval = opts
|
479
|
+
@refresh_interval = opts.fetch(:refresh_interval, 90)
|
480
|
+
|
481
|
+
if @refresh_mode && @refresh_interval < 60
|
482
|
+
@refresh_interval = 60 unless ENV['TEST_MODE'] = 'TRUE'
|
483
|
+
end
|
463
484
|
|
464
485
|
if @refresh_mode == :async
|
465
486
|
warn ":async refresh mode has been deprecated. Refresh
|
data/lib/mongo/util/node.rb
CHANGED
@@ -36,20 +36,16 @@ module Mongo
|
|
36
36
|
def connect
|
37
37
|
begin
|
38
38
|
socket = nil
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
else
|
44
|
-
socket = @connection.socket_class.new(@host, @port)
|
45
|
-
end
|
39
|
+
socket = @connection.socket_class.new(@host, @port,
|
40
|
+
@connection.op_timeout, @connection.connect_timeout
|
41
|
+
)
|
46
42
|
|
47
43
|
if socket.nil?
|
48
44
|
return nil
|
49
45
|
else
|
50
46
|
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
51
47
|
end
|
52
|
-
rescue OperationTimeout, OperationFailure, SocketError, SystemCallError, IOError => ex
|
48
|
+
rescue OperationTimeout, ConnectionFailure, OperationFailure, SocketError, SystemCallError, IOError => ex
|
53
49
|
@connection.log(:debug, "Failed connection to #{host_string} with #{ex.class}, #{ex.message}.")
|
54
50
|
socket.close if socket
|
55
51
|
return nil
|
@@ -74,7 +70,7 @@ module Mongo
|
|
74
70
|
begin
|
75
71
|
result = @connection['admin'].command({:ping => 1}, :socket => @socket)
|
76
72
|
return result['ok'] == 1
|
77
|
-
rescue OperationFailure, SocketError, SystemCallError, IOError
|
73
|
+
rescue OperationFailure, SocketError, SystemCallError, IOError
|
78
74
|
return nil
|
79
75
|
end
|
80
76
|
end
|
@@ -84,13 +80,7 @@ module Mongo
|
|
84
80
|
# matches with the name provided.
|
85
81
|
def set_config
|
86
82
|
begin
|
87
|
-
|
88
|
-
Mongo::TimeoutHandler.timeout(@connection.connect_timeout, OperationTimeout) do
|
89
|
-
@config = @connection['admin'].command({:ismaster => 1}, :socket => @socket)
|
90
|
-
end
|
91
|
-
else
|
92
|
-
@config = @connection['admin'].command({:ismaster => 1}, :socket => @socket)
|
93
|
-
end
|
83
|
+
@config = @connection['admin'].command({:ismaster => 1}, :socket => @socket)
|
94
84
|
|
95
85
|
if @config['msg'] && @logger
|
96
86
|
@connection.log(:warn, "#{config['msg']}")
|
data/lib/mongo/util/pool.rb
CHANGED
@@ -133,7 +133,7 @@ module Mongo
|
|
133
133
|
def ping
|
134
134
|
begin
|
135
135
|
return self.connection['admin'].command({:ping => 1}, :socket => @node.socket)
|
136
|
-
rescue OperationFailure, SocketError, SystemCallError, IOError
|
136
|
+
rescue OperationFailure, SocketError, SystemCallError, IOError
|
137
137
|
return false
|
138
138
|
end
|
139
139
|
end
|
@@ -156,7 +156,7 @@ module Mongo
|
|
156
156
|
# therefore, it runs within a mutex.
|
157
157
|
def checkout_new_socket
|
158
158
|
begin
|
159
|
-
socket =
|
159
|
+
socket = @connection.socket_class.new(@host, @port, @connection.op_timeout)
|
160
160
|
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
161
161
|
socket.pool = self
|
162
162
|
rescue => ex
|
@@ -217,7 +217,9 @@ module Mongo
|
|
217
217
|
if @pids[socket] != Process.pid
|
218
218
|
@pids[socket] = nil
|
219
219
|
@sockets.delete(socket)
|
220
|
-
|
220
|
+
if socket
|
221
|
+
socket.close unless socket.closed?
|
222
|
+
end
|
221
223
|
checkout_new_socket
|
222
224
|
else
|
223
225
|
@checked_out << socket
|
@@ -227,15 +229,10 @@ module Mongo
|
|
227
229
|
end
|
228
230
|
|
229
231
|
def prune_thread_socket_hash
|
230
|
-
|
231
|
-
Thread.list.each do |t|
|
232
|
-
map[t] = 1
|
233
|
-
end
|
232
|
+
current_threads = Set[*Thread.list]
|
234
233
|
|
235
|
-
@threads_to_sockets.
|
236
|
-
|
237
|
-
@threads_to_sockets.delete(key)
|
238
|
-
end
|
234
|
+
@threads_to_sockets.delete_if do |thread, socket|
|
235
|
+
!current_threads.include?(thread)
|
239
236
|
end
|
240
237
|
end
|
241
238
|
|
@@ -1,4 +1,6 @@
|
|
1
|
+
require 'socket'
|
1
2
|
require 'openssl'
|
3
|
+
require 'timeout'
|
2
4
|
|
3
5
|
module Mongo
|
4
6
|
|
@@ -9,31 +11,51 @@ module Mongo
|
|
9
11
|
|
10
12
|
attr_accessor :pool
|
11
13
|
|
12
|
-
def initialize(host, port)
|
13
|
-
@
|
14
|
+
def initialize(host, port, op_timeout=nil, connect_timeout=nil)
|
15
|
+
@op_timeout = op_timeout
|
16
|
+
@connect_timeout = connect_timeout
|
17
|
+
|
18
|
+
@socket = ::TCPSocket.new(host, port)
|
14
19
|
@ssl = OpenSSL::SSL::SSLSocket.new(@socket)
|
15
20
|
@ssl.sync_close = true
|
16
|
-
|
21
|
+
|
22
|
+
connect
|
17
23
|
end
|
18
24
|
|
19
|
-
def
|
20
|
-
@
|
25
|
+
def connect
|
26
|
+
if @connect_timeout
|
27
|
+
Timeout::timeout(@connect_timeout, ConnectionTimeoutError) do
|
28
|
+
@ssl.connect
|
29
|
+
end
|
30
|
+
else
|
31
|
+
@ssl.connect
|
32
|
+
end
|
21
33
|
end
|
22
34
|
|
23
|
-
|
24
|
-
|
25
|
-
# @param buffer a buffer to send.
|
26
|
-
# @param flags socket flags. Because Ruby's SSL
|
27
|
-
def send(buffer, flags=0)
|
28
|
-
@ssl.syswrite(buffer)
|
35
|
+
def send(data)
|
36
|
+
@ssl.syswrite(data)
|
29
37
|
end
|
30
38
|
|
31
39
|
def read(length, buffer)
|
32
|
-
@
|
40
|
+
if @op_timeout
|
41
|
+
Timeout::timeout(@op_timeout, OperationTimeout) do
|
42
|
+
@ssl.sysread(length, buffer)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
@ssl.sysread(length, buffer)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def setsockopt(key, value, n)
|
50
|
+
@ssl.setsockopt(key, value, n)
|
33
51
|
end
|
34
52
|
|
35
53
|
def close
|
36
54
|
@ssl.close
|
37
55
|
end
|
56
|
+
|
57
|
+
def closed?
|
58
|
+
@ssl.closed?
|
59
|
+
end
|
38
60
|
end
|
39
61
|
end
|
@@ -1,6 +1,95 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
1
3
|
module Mongo
|
2
|
-
class
|
3
|
-
|
4
|
+
# Wrapper class for Socket
|
5
|
+
#
|
6
|
+
# Emulates TCPSocket with operation and connection timeout
|
7
|
+
# sans Timeout::timeout
|
8
|
+
#
|
9
|
+
class TCPSocket
|
10
|
+
attr_accessor :pool
|
11
|
+
|
12
|
+
def initialize(host, port, op_timeout=nil, connect_timeout=nil)
|
13
|
+
@op_timeout = op_timeout
|
14
|
+
@connect_timeout = connect_timeout
|
15
|
+
|
16
|
+
# TODO: Prefer ipv6 if server is ipv6 enabled
|
17
|
+
@host = Socket.getaddrinfo(host, nil, Socket::AF_INET).first[3]
|
18
|
+
@port = port
|
19
|
+
@socket_address = Socket.pack_sockaddr_in(@port, @host)
|
20
|
+
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
21
|
+
|
22
|
+
connect
|
23
|
+
end
|
24
|
+
|
25
|
+
def connect
|
26
|
+
# Connect nonblock is broken in current versions of JRuby
|
27
|
+
if RUBY_PLATFORM == 'java'
|
28
|
+
require 'timeout'
|
29
|
+
if @connect_timeout
|
30
|
+
Timeout::timeout(@connect_timeout, OperationTimeout) do
|
31
|
+
@socket.connect(@socket_address)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
@socket.connect(@socket_address)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
# Try to connect for @connect_timeout seconds
|
38
|
+
begin
|
39
|
+
@socket.connect_nonblock(@socket_address)
|
40
|
+
rescue Errno::EINPROGRESS
|
41
|
+
# Block until there is a response or error
|
42
|
+
resp = IO.select([@socket], [@socket], [@socket], @connect_timeout)
|
43
|
+
if resp.nil?
|
44
|
+
raise ConnectionTimeoutError
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# If there was a failure this will raise an Error
|
49
|
+
begin
|
50
|
+
@socket.connect_nonblock(@socket_address)
|
51
|
+
rescue Errno::EISCONN
|
52
|
+
# Successfully connected
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def send(data)
|
58
|
+
@socket.write(data)
|
59
|
+
end
|
60
|
+
|
61
|
+
def read(maxlen, buffer)
|
62
|
+
# Block on data to read for @op_timeout seconds
|
63
|
+
begin
|
64
|
+
ready = IO.select([@socket], nil, [@socket], @op_timeout)
|
65
|
+
rescue IOError
|
66
|
+
raise OperationFailure
|
67
|
+
end
|
68
|
+
if ready
|
69
|
+
begin
|
70
|
+
@socket.readpartial(maxlen, buffer)
|
71
|
+
rescue EOFError
|
72
|
+
return ConnectionError
|
73
|
+
rescue Errno::ENOTCONN, Errno::EBADF, Errno::ECONNRESET, Errno::EPIPE
|
74
|
+
raise ConnectionFailure
|
75
|
+
rescue Errno::EINTR, Errno::EIO, IOError
|
76
|
+
raise OperationFailure
|
77
|
+
end
|
78
|
+
else
|
79
|
+
raise OperationTimeout
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def setsockopt(key, value, n)
|
84
|
+
@socket.setsockopt(key, value, n)
|
85
|
+
end
|
86
|
+
|
87
|
+
def close
|
88
|
+
@socket.close
|
89
|
+
end
|
4
90
|
|
5
|
-
|
91
|
+
def closed?
|
92
|
+
@socket.closed?
|
93
|
+
end
|
94
|
+
end
|
6
95
|
end
|