mongo 1.8.0 → 1.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +14 -29
- data/VERSION +1 -1
- data/lib/mongo.rb +3 -0
- data/lib/mongo/collection.rb +99 -49
- data/lib/mongo/cursor.rb +17 -17
- data/lib/mongo/db.rb +30 -14
- data/lib/mongo/gridfs/grid.rb +5 -3
- data/lib/mongo/gridfs/grid_file_system.rb +5 -3
- data/lib/mongo/gridfs/grid_io.rb +5 -3
- data/lib/mongo/legacy.rb +9 -2
- data/lib/mongo/mongo_client.rb +100 -72
- data/lib/mongo/mongo_replica_set_client.rb +46 -60
- data/lib/mongo/mongo_sharded_client.rb +5 -66
- data/lib/mongo/networking.rb +2 -1
- data/lib/mongo/util/node.rb +41 -42
- data/lib/mongo/util/pool.rb +15 -43
- data/lib/mongo/util/pool_manager.rb +16 -65
- data/lib/mongo/util/read_preference.rb +82 -0
- data/lib/mongo/util/sharding_pool_manager.rb +0 -86
- data/lib/mongo/util/ssl_socket.rb +2 -1
- data/lib/mongo/util/support.rb +8 -18
- data/lib/mongo/util/tcp_socket.rb +5 -4
- data/lib/mongo/util/thread_local_variable_manager.rb +29 -0
- data/lib/mongo/util/unix_socket.rb +23 -0
- data/lib/mongo/util/uri_parser.rb +31 -18
- data/lib/mongo/util/write_concern.rb +7 -2
- data/mongo.gemspec +1 -1
- data/test/auxillary/repl_set_auth_test.rb +2 -2
- data/test/bson/bson_test.rb +1 -1
- data/test/bson/byte_buffer_test.rb +24 -26
- data/test/bson/hash_with_indifferent_access_test.rb +11 -1
- data/test/functional/collection_test.rb +16 -16
- data/test/functional/connection_test.rb +1 -4
- data/test/functional/db_api_test.rb +14 -10
- data/test/functional/pool_test.rb +23 -31
- data/test/functional/timeout_test.rb +3 -5
- data/test/functional/uri_test.rb +10 -5
- data/test/replica_set/basic_test.rb +3 -8
- data/test/replica_set/client_test.rb +47 -31
- data/test/replica_set/complex_connect_test.rb +12 -10
- data/test/replica_set/connection_test.rb +8 -151
- data/test/replica_set/count_test.rb +9 -5
- data/test/replica_set/cursor_test.rb +17 -27
- data/test/replica_set/insert_test.rb +5 -10
- data/test/replica_set/query_test.rb +4 -9
- data/test/replica_set/read_preference_test.rb +200 -0
- data/test/replica_set/refresh_test.rb +54 -65
- data/test/replica_set/replication_ack_test.rb +16 -14
- data/test/sharded_cluster/basic_test.rb +30 -0
- data/test/test_helper.rb +33 -15
- data/test/threading/basic_test.rb +79 -0
- data/test/tools/mongo_config.rb +62 -22
- data/test/unit/client_test.rb +36 -14
- data/test/unit/collection_test.rb +23 -0
- data/test/unit/connection_test.rb +30 -14
- data/test/unit/cursor_test.rb +137 -7
- data/test/unit/db_test.rb +17 -4
- data/test/unit/grid_test.rb +2 -2
- data/test/unit/node_test.rb +2 -1
- data/test/unit/pool_manager_test.rb +29 -1
- data/test/unit/read_test.rb +15 -15
- data/test/unit/safe_test.rb +4 -4
- data/test/unit/write_concern_test.rb +4 -4
- metadata +134 -143
- data/examples/admin.rb +0 -43
- data/examples/capped.rb +0 -22
- data/examples/cursor.rb +0 -48
- data/examples/gridfs.rb +0 -44
- data/examples/index_test.rb +0 -126
- data/examples/info.rb +0 -31
- data/examples/queries.rb +0 -74
- data/examples/replica_set.rb +0 -26
- data/examples/simple.rb +0 -25
- data/examples/strict.rb +0 -35
- data/examples/types.rb +0 -36
- data/examples/web/thin/load.rb +0 -23
- data/examples/web/unicorn/load.rb +0 -25
- data/test/support/hash_with_indifferent_access.rb +0 -186
- data/test/support/keys.rb +0 -45
- data/test/threading/threading_with_large_pool_test.rb +0 -90
data/lib/mongo/util/pool.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
# --
|
4
2
|
# Copyright (C) 2008-2012 10gen Inc.
|
5
3
|
#
|
@@ -19,7 +17,7 @@ module Mongo
|
|
19
17
|
class Pool
|
20
18
|
PING_ATTEMPTS = 6
|
21
19
|
MAX_PING_TIME = 1_000_000
|
22
|
-
|
20
|
+
include ThreadLocalVariableManager
|
23
21
|
|
24
22
|
attr_accessor :host,
|
25
23
|
:port,
|
@@ -58,12 +56,10 @@ module Mongo
|
|
58
56
|
@socket_ops = Hash.new { |h, k| h[k] = [] }
|
59
57
|
|
60
58
|
@sockets = []
|
61
|
-
@pids = {}
|
62
59
|
@checked_out = []
|
63
60
|
@ping_time = nil
|
64
61
|
@last_ping = nil
|
65
62
|
@closed = false
|
66
|
-
@threads_to_sockets = {}
|
67
63
|
@checkout_counter = 0
|
68
64
|
end
|
69
65
|
|
@@ -205,9 +201,9 @@ module Mongo
|
|
205
201
|
@client.apply_saved_authentication(:socket => socket)
|
206
202
|
|
207
203
|
@sockets << socket
|
208
|
-
@pids[socket] = Process.pid
|
209
204
|
@checked_out << socket
|
210
|
-
|
205
|
+
|
206
|
+
thread_local[:sockets][self.object_id] = socket
|
211
207
|
socket
|
212
208
|
end
|
213
209
|
|
@@ -249,8 +245,7 @@ module Mongo
|
|
249
245
|
socket = (@sockets - @checked_out).first
|
250
246
|
end
|
251
247
|
|
252
|
-
if
|
253
|
-
@pids[socket] = nil
|
248
|
+
if socket.pid != Process.pid
|
254
249
|
@sockets.delete(socket)
|
255
250
|
if socket
|
256
251
|
socket.close unless socket.closed?
|
@@ -258,19 +253,11 @@ module Mongo
|
|
258
253
|
checkout_new_socket
|
259
254
|
else
|
260
255
|
@checked_out << socket
|
261
|
-
|
256
|
+
thread_local[:sockets][self.object_id] = socket
|
262
257
|
socket
|
263
258
|
end
|
264
259
|
end
|
265
260
|
|
266
|
-
def prune_thread_socket_hash
|
267
|
-
current_threads = Set[*Thread.list]
|
268
|
-
|
269
|
-
@threads_to_sockets.delete_if do |thread, socket|
|
270
|
-
!current_threads.include?(thread)
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
261
|
# Check out an existing socket or create a new socket if the maximum
|
275
262
|
# pool size has not been exceeded. Otherwise, wait for the next
|
276
263
|
# available socket.
|
@@ -278,32 +265,16 @@ module Mongo
|
|
278
265
|
@client.connect if !@client.connected?
|
279
266
|
start_time = Time.now
|
280
267
|
loop do
|
281
|
-
if (Time.now - start_time) > @timeout
|
282
|
-
raise ConnectionTimeoutError, "could not obtain connection within " +
|
283
|
-
"#{@timeout} seconds. The max pool size is currently #{@size}; " +
|
284
|
-
"consider increasing the pool size or timeout."
|
285
|
-
end
|
286
|
-
|
287
268
|
@connection_mutex.synchronize do
|
288
|
-
if
|
289
|
-
@checkout_counter = 0
|
290
|
-
prune_thread_socket_hash
|
291
|
-
else
|
292
|
-
@checkout_counter += 1
|
293
|
-
end
|
294
|
-
|
295
|
-
if socket_for_thread = @threads_to_sockets[Thread.current]
|
269
|
+
if socket_for_thread = thread_local[:sockets][self.object_id]
|
296
270
|
if !@checked_out.include?(socket_for_thread)
|
297
271
|
socket = checkout_existing_socket(socket_for_thread)
|
298
272
|
end
|
299
|
-
else
|
300
|
-
|
301
|
-
if (thread_length <= @sockets.size) && (@sockets.size < @size)
|
273
|
+
else
|
274
|
+
if @sockets.size < @size
|
302
275
|
socket = checkout_new_socket
|
303
276
|
elsif @checked_out.size < @sockets.size
|
304
277
|
socket = checkout_existing_socket
|
305
|
-
elsif @sockets.size < @size
|
306
|
-
socket = checkout_new_socket
|
307
278
|
end
|
308
279
|
end
|
309
280
|
|
@@ -318,12 +289,7 @@ module Mongo
|
|
318
289
|
if socket.closed?
|
319
290
|
@checked_out.delete(socket)
|
320
291
|
@sockets.delete(socket)
|
321
|
-
|
322
|
-
if v == socket
|
323
|
-
@threads_to_sockets.delete(k)
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
292
|
+
thread_local[:sockets].delete self.object_id
|
327
293
|
socket = checkout_new_socket
|
328
294
|
end
|
329
295
|
|
@@ -333,6 +299,12 @@ module Mongo
|
|
333
299
|
@queue.wait(@connection_mutex)
|
334
300
|
end
|
335
301
|
end
|
302
|
+
|
303
|
+
if (Time.now - start_time) > @timeout
|
304
|
+
raise ConnectionTimeoutError, "could not obtain connection within " +
|
305
|
+
"#{@timeout} seconds. The max pool size is currently #{@size}; " +
|
306
|
+
"consider increasing the pool size or timeout."
|
307
|
+
end
|
336
308
|
end
|
337
309
|
end
|
338
310
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Mongo
|
2
2
|
class PoolManager
|
3
|
+
include Mongo::ReadPreference
|
4
|
+
include ThreadLocalVariableManager
|
3
5
|
|
4
6
|
attr_reader :client, :arbiters, :primary, :secondaries, :primary_pool,
|
5
7
|
:secondary_pool, :secondary_pools, :hosts, :nodes, :members, :seeds,
|
6
8
|
:max_bson_size
|
7
9
|
|
8
|
-
attr_accessor :pinned_pools
|
9
|
-
|
10
10
|
# Create a new set of connection pools.
|
11
11
|
#
|
12
12
|
# The pool manager will by default use the original seed list passed
|
@@ -15,7 +15,6 @@ module Mongo
|
|
15
15
|
# time. The union of these lists will be used when attempting to connect,
|
16
16
|
# with the newly-discovered nodes being used first.
|
17
17
|
def initialize(client, seeds=[])
|
18
|
-
@pinned_pools = {}
|
19
18
|
@client = client
|
20
19
|
@seeds = seeds
|
21
20
|
@previously_connected = false
|
@@ -49,8 +48,8 @@ module Mongo
|
|
49
48
|
return
|
50
49
|
end
|
51
50
|
|
52
|
-
config = seed.
|
53
|
-
if
|
51
|
+
config = seed.config
|
52
|
+
if config
|
54
53
|
@refresh_required = true
|
55
54
|
seed.close
|
56
55
|
return
|
@@ -99,30 +98,16 @@ module Mongo
|
|
99
98
|
read_pool.host_port
|
100
99
|
end
|
101
100
|
|
102
|
-
def read_pool(mode=@client.
|
101
|
+
def read_pool(mode=@client.read,
|
103
102
|
tags=@client.tag_sets,
|
104
103
|
acceptable_latency=@client.acceptable_latency)
|
105
104
|
|
106
|
-
|
107
|
-
raise MongoArgumentError, "Read preferecy :primary cannot be combined with tags"
|
108
|
-
end
|
105
|
+
pinned = thread_local[:pinned_pools][self.object_id]
|
109
106
|
|
110
|
-
pinned = @pinned_pools[Thread.current]
|
111
107
|
if pinned && pinned.matches_mode(mode) && pinned.matches_tag_sets(tags) && pinned.up?
|
112
108
|
pool = pinned
|
113
109
|
else
|
114
|
-
pool =
|
115
|
-
when :primary
|
116
|
-
@primary_pool
|
117
|
-
when :primary_preferred
|
118
|
-
@primary_pool || select_pool(@secondary_pools, tags, acceptable_latency)
|
119
|
-
when :secondary
|
120
|
-
select_pool(@secondary_pools, tags, acceptable_latency)
|
121
|
-
when :secondary_preferred
|
122
|
-
select_pool(@secondary_pools, tags, acceptable_latency) || @primary_pool
|
123
|
-
when :nearest
|
124
|
-
select_pool(pools, tags, acceptable_latency)
|
125
|
-
end
|
110
|
+
pool = select_pool(mode, tags, acceptable_latency)
|
126
111
|
end
|
127
112
|
|
128
113
|
unless pool
|
@@ -140,8 +125,8 @@ module Mongo
|
|
140
125
|
private
|
141
126
|
|
142
127
|
def validate_existing_member(member)
|
143
|
-
config = member.
|
144
|
-
if
|
128
|
+
config = member.config
|
129
|
+
if config
|
145
130
|
return false
|
146
131
|
else
|
147
132
|
if member.primary?
|
@@ -165,13 +150,12 @@ module Mongo
|
|
165
150
|
@read = nil
|
166
151
|
@read_pool = nil
|
167
152
|
@arbiters = []
|
168
|
-
@secondaries =
|
153
|
+
@secondaries = Set.new
|
169
154
|
@secondary_pool = nil
|
170
155
|
@secondary_pools = []
|
171
156
|
@hosts = Set.new
|
172
157
|
@members = Set.new
|
173
158
|
@refresh_required = false
|
174
|
-
@pinned_pools = {}
|
175
159
|
end
|
176
160
|
|
177
161
|
# Connect to each member of the replica set
|
@@ -184,9 +168,8 @@ module Mongo
|
|
184
168
|
|
185
169
|
seed.node_list.each do |host|
|
186
170
|
node = Mongo::Node.new(self.client, host)
|
187
|
-
|
188
|
-
|
189
|
-
end
|
171
|
+
node.connect
|
172
|
+
members << node if node.healthy?
|
190
173
|
end
|
191
174
|
seed.close
|
192
175
|
|
@@ -201,10 +184,10 @@ module Mongo
|
|
201
184
|
def initialize_pools(members)
|
202
185
|
members.each do |member|
|
203
186
|
@hosts << member.host_string
|
204
|
-
|
205
187
|
if member.primary?
|
206
188
|
assign_primary(member)
|
207
|
-
elsif member.secondary?
|
189
|
+
elsif member.secondary?
|
190
|
+
# member could be not primary but secondary still is false
|
208
191
|
assign_secondary(member)
|
209
192
|
end
|
210
193
|
end
|
@@ -235,33 +218,6 @@ module Mongo
|
|
235
218
|
@secondary_pools << pool
|
236
219
|
end
|
237
220
|
|
238
|
-
def select_pool(candidates, tag_sets, acceptable_latency)
|
239
|
-
tag_sets = [tag_sets] unless tag_sets.is_a?(Array)
|
240
|
-
|
241
|
-
if !tag_sets.empty?
|
242
|
-
matches = []
|
243
|
-
tag_sets.detect do |tag_set|
|
244
|
-
matches = candidates.select do |candidate|
|
245
|
-
tag_set.none? { |k,v| candidate.tags[k.to_s] != v } &&
|
246
|
-
candidate.ping_time
|
247
|
-
end
|
248
|
-
!matches.empty?
|
249
|
-
end
|
250
|
-
else
|
251
|
-
matches = candidates
|
252
|
-
end
|
253
|
-
|
254
|
-
matches.empty? ? nil : near_pool(matches, acceptable_latency)
|
255
|
-
end
|
256
|
-
|
257
|
-
def near_pool(pool_set, acceptable_latency)
|
258
|
-
nearest_pool = pool_set.min_by { |pool| pool.ping_time }
|
259
|
-
near_pools = pool_set.select do |pool|
|
260
|
-
(pool.ping_time - nearest_pool.ping_time) <= acceptable_latency
|
261
|
-
end
|
262
|
-
near_pools[ rand(near_pools.length) ]
|
263
|
-
end
|
264
|
-
|
265
221
|
# Iterate through the list of provided seed
|
266
222
|
# nodes until we've gotten a response from the
|
267
223
|
# replica set we're trying to connect to.
|
@@ -270,13 +226,8 @@ module Mongo
|
|
270
226
|
def get_valid_seed_node
|
271
227
|
@seeds.each do |seed|
|
272
228
|
node = Mongo::Node.new(self.client, seed)
|
273
|
-
|
274
|
-
|
275
|
-
elsif node.set_config && node.healthy?
|
276
|
-
return node
|
277
|
-
else
|
278
|
-
node.close
|
279
|
-
end
|
229
|
+
node.connect
|
230
|
+
return node if node.healthy?
|
280
231
|
end
|
281
232
|
|
282
233
|
raise ConnectionFailure, "Cannot connect to a replica set using seeds " +
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Mongo
|
2
|
+
module ReadPreference
|
3
|
+
READ_PREFERENCES = [
|
4
|
+
:primary,
|
5
|
+
:primary_preferred,
|
6
|
+
:secondary,
|
7
|
+
:secondary_preferred,
|
8
|
+
:nearest
|
9
|
+
]
|
10
|
+
|
11
|
+
MONGOS_MODES = {
|
12
|
+
:primary => :primary,
|
13
|
+
:primary_preferred => :primaryPreferred,
|
14
|
+
:secondary => :secondary,
|
15
|
+
:secondary_preferred => :secondaryPreferred,
|
16
|
+
:nearest => :nearest
|
17
|
+
}
|
18
|
+
|
19
|
+
def self.mongos(mode, tag_sets)
|
20
|
+
if mode != :secondary_preferred || !tag_sets.empty?
|
21
|
+
mongos_read_preference = BSON::OrderedHash[:mode => MONGOS_MODES[mode]]
|
22
|
+
mongos_read_preference[:tags] = tag_sets if !tag_sets.empty?
|
23
|
+
end
|
24
|
+
mongos_read_preference
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.validate(value)
|
28
|
+
if READ_PREFERENCES.include?(value)
|
29
|
+
return true
|
30
|
+
else
|
31
|
+
raise MongoArgumentError, "#{value} is not a valid read preference. " +
|
32
|
+
"Please specify one of the following read preferences as a symbol: #{READ_PREFERENCES}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def select_pool(mode, tags, latency)
|
37
|
+
if mode == :primary && !tags.empty?
|
38
|
+
raise MongoArgumentError, "Read preferecy :primary cannot be combined with tags"
|
39
|
+
end
|
40
|
+
|
41
|
+
case mode
|
42
|
+
when :primary
|
43
|
+
primary_pool
|
44
|
+
when :primary_preferred
|
45
|
+
primary_pool || select_secondary_pool(secondary_pools, tags, latency)
|
46
|
+
when :secondary
|
47
|
+
select_secondary_pool(secondary_pools, tags, latency)
|
48
|
+
when :secondary_preferred
|
49
|
+
select_secondary_pool(secondary_pools, tags, latency) || primary_pool
|
50
|
+
when :nearest
|
51
|
+
select_secondary_pool(pools, tags, latency)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def select_secondary_pool(candidates, tag_sets, latency)
|
56
|
+
tag_sets = [tag_sets] unless tag_sets.is_a?(Array)
|
57
|
+
|
58
|
+
if !tag_sets.empty?
|
59
|
+
matches = []
|
60
|
+
tag_sets.detect do |tag_set|
|
61
|
+
matches = candidates.select do |candidate|
|
62
|
+
tag_set.none? { |k,v| candidate.tags[k.to_s] != v } &&
|
63
|
+
candidate.ping_time
|
64
|
+
end
|
65
|
+
!matches.empty?
|
66
|
+
end
|
67
|
+
else
|
68
|
+
matches = candidates
|
69
|
+
end
|
70
|
+
|
71
|
+
matches.empty? ? nil : select_near_pool(matches, latency)
|
72
|
+
end
|
73
|
+
|
74
|
+
def select_near_pool(candidates, latency)
|
75
|
+
nearest_pool = candidates.min_by { |candidate| candidate.ping_time }
|
76
|
+
near_pools = candidates.select do |candidate|
|
77
|
+
(candidate.ping_time - nearest_pool.ping_time) <= latency
|
78
|
+
end
|
79
|
+
near_pools[ rand(near_pools.length) ]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -1,42 +1,5 @@
|
|
1
1
|
|
2
2
|
module Mongo
|
3
|
-
module ShardingNode
|
4
|
-
def set_config
|
5
|
-
begin
|
6
|
-
@config = @client['admin'].command({:ismaster => 1}, :socket => @socket)
|
7
|
-
|
8
|
-
# warning: instance variable @logger not initialized
|
9
|
-
#if @config['msg'] && @logger
|
10
|
-
# @client.log(:warn, "#{config['msg']}")
|
11
|
-
#end
|
12
|
-
|
13
|
-
rescue ConnectionFailure, OperationFailure, OperationTimeout, SocketError, SystemCallError, IOError => ex
|
14
|
-
@client.log(:warn, "Attempted connection to node #{host_string} raised " +
|
15
|
-
"#{ex.class}: #{ex.message}")
|
16
|
-
|
17
|
-
# Socket may already be nil from issuing command
|
18
|
-
if @socket && !@socket.closed?
|
19
|
-
@socket.close
|
20
|
-
end
|
21
|
-
|
22
|
-
return nil
|
23
|
-
end
|
24
|
-
|
25
|
-
@config
|
26
|
-
end
|
27
|
-
|
28
|
-
# Return a list of sharded cluster nodes from the config - currently just the current node.
|
29
|
-
def node_list
|
30
|
-
connect unless connected?
|
31
|
-
set_config unless @config
|
32
|
-
|
33
|
-
return [] unless config
|
34
|
-
|
35
|
-
["#{@host}:#{@port}"]
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
3
|
class ShardingPoolManager < PoolManager
|
41
4
|
|
42
5
|
attr_reader :client, :primary, :primary_pool, :hosts, :nodes,
|
@@ -90,54 +53,5 @@ module Mongo
|
|
90
53
|
@refresh_required = true
|
91
54
|
end
|
92
55
|
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
# Connect to each member of the sharded cluster
|
97
|
-
# as reported by the given seed node, and return
|
98
|
-
# as a list of Mongo::Node objects.
|
99
|
-
def connect_to_members
|
100
|
-
members = []
|
101
|
-
|
102
|
-
seed = get_valid_seed_node
|
103
|
-
|
104
|
-
seed.node_list.each do |host|
|
105
|
-
node = Mongo::Node.new(self.client, host)
|
106
|
-
node.extend ShardingNode
|
107
|
-
if node.connect && node.set_config
|
108
|
-
members << node
|
109
|
-
end
|
110
|
-
end
|
111
|
-
seed.close
|
112
|
-
|
113
|
-
if members.empty?
|
114
|
-
raise ConnectionFailure, "Failed to connect to any given member."
|
115
|
-
end
|
116
|
-
|
117
|
-
members
|
118
|
-
end
|
119
|
-
|
120
|
-
# Iterate through the list of provided seed
|
121
|
-
# nodes until we've gotten a response from the
|
122
|
-
# sharded cluster we're trying to connect to.
|
123
|
-
#
|
124
|
-
# If we don't get a response, raise an exception.
|
125
|
-
def get_valid_seed_node
|
126
|
-
@seeds.each do |seed|
|
127
|
-
node = Mongo::Node.new(self.client, seed)
|
128
|
-
node.extend ShardingNode
|
129
|
-
if !node.connect
|
130
|
-
next
|
131
|
-
elsif node.set_config && node.healthy?
|
132
|
-
return node
|
133
|
-
else
|
134
|
-
node.close
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
raise ConnectionFailure, "Cannot connect to a sharded cluster using seeds " +
|
139
|
-
"#{@seeds.map {|s| "#{s[0]}:#{s[1]}" }.join(', ')}"
|
140
|
-
end
|
141
|
-
|
142
56
|
end
|
143
57
|
end
|