mongo 1.6.0 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -37,7 +37,7 @@ for much more:
37
37
 
38
38
  ### Ruby Versions
39
39
 
40
- The driver works and is consistently tested on Ruby 1.8.6, 1.8.7, and 1.9.2, and JRuby 1.5.1.
40
+ The driver works and is consistently tested on Ruby 1.8.7 and 1.9.3 as well as JRuby 1.6.6.
41
41
 
42
42
  Note that if you're on 1.8.7, be sure that you're using a patchlevel >= 249. There
43
43
  are some IO bugs in earlier versions.
@@ -198,7 +198,7 @@ Here is a sample primary key factory, taken from the tests:
198
198
 
199
199
  class TestPKFactory
200
200
  def create_pk(row)
201
- row['_id'] ||= Mongo::ObjectID.new
201
+ row['_id'] ||= BSON::ObjectId.new
202
202
  row
203
203
  end
204
204
  end
@@ -212,7 +212,7 @@ ActiveRecord-like framework for non-Rails apps) and the AR Mongo adapter code
212
212
  def create_pk(row)
213
213
  return row if row[:_id]
214
214
  row.delete(:_id) # in case it exists but the value is nil
215
- row['_id'] ||= Mongo::ObjectID.new
215
+ row['_id'] ||= BSON::ObjectId.new
216
216
  row
217
217
  end
218
218
  end
@@ -283,12 +283,9 @@ To run any individual rake tasks with the C extension enabled, just pass C_EXT=t
283
283
 
284
284
  $ rake test:unit C_EXT=true
285
285
 
286
- If you want to test replica set, you can run the following tests
287
- individually:
286
+ If you want to test replica set, you can run the following task:
288
287
 
289
- $ rake test:replica_set_count
290
- $ rake test:replica_set_insert
291
- $ rake test:replica_set_query
288
+ $ rake test:rs
292
289
 
293
290
  ### Shoulda and Mocha
294
291
 
data/Rakefile CHANGED
@@ -3,15 +3,20 @@ if RUBY_VERSION < '1.9.0'
3
3
  require 'rubygems'
4
4
  require 'rubygems/specification'
5
5
  end
6
+
6
7
  require 'fileutils'
7
8
  require 'rake/testtask'
8
- require 'rbconfig'
9
9
  require 'rake'
10
+
11
+ begin
12
+ require 'git'
13
+ rescue LoadError
14
+ end
15
+
10
16
  begin
11
17
  require 'ci/reporter/rake/test_unit'
12
18
  rescue LoadError
13
19
  end
14
- include Config
15
20
 
16
21
  ENV['TEST_MODE'] = 'TRUE'
17
22
 
@@ -210,10 +215,12 @@ namespace :gem do
210
215
 
211
216
  desc "Build all gems"
212
217
  task :build_all do
218
+ `rm *.gem`
213
219
  `gem build mongo.gemspec`
214
220
  `gem build bson.gemspec`
215
221
  `gem build bson.java.gemspec`
216
222
  `gem build bson_ext.gemspec`
223
+ puts `ls *.gem`
217
224
  end
218
225
 
219
226
  end
@@ -228,6 +235,81 @@ namespace :ci do
228
235
  end
229
236
  end
230
237
 
238
+ # Deployment
239
+ VERSION_FILES = %w(lib/bson/version.rb lib/mongo/version.rb ext/cbson/version.h)
240
+ GEMSPECS = %w(bson.gemspec bson.java.gemspec bson_ext.gemspec mongo.gemspec)
241
+
242
+ def gem_list(version)
243
+ files = []
244
+ files << "bson-#{version}.gem"
245
+ files << "bson-#{version}-java.gem"
246
+ files << "bson_ext-#{version}.gem"
247
+ files << "mongo-#{version}.gem"
248
+ return files
249
+ end
250
+
251
+ def check_gem_list_existence(version)
252
+ gem_list(version).each do |filename|
253
+ if !File.exists?(filename)
254
+ raise "#{filename} does not exist!"
255
+ end
256
+ end
257
+ end
258
+
259
+ def check_version(version)
260
+ if !(version =~ /\d\.\d\.\d/)
261
+ raise "Must specify a valid version (e.g., x.y.z)"
262
+ end
263
+ end
264
+
265
+ def current_version
266
+ f = File.open("lib/mongo/version.rb")
267
+ str = f.read
268
+ str =~ /VERSION\s+=\s+([.\d"]+)$/
269
+ return $1
270
+ end
271
+
272
+ def change_version(new_version)
273
+ version = current_version
274
+ VERSION_FILES.each do |filename|
275
+ f = File.open(filename)
276
+ str = f.read
277
+ f.close
278
+ str.gsub!(version, "\"#{new_version}\"")
279
+ File.open(filename, 'w') do |f|
280
+ f.write(str)
281
+ end
282
+ end
283
+ end
284
+
285
+ namespace :deploy do
286
+ task :version, [:version] do |t, args|
287
+ check_version(args[:version])
288
+ puts args[:version]
289
+ change_version(args[:version])
290
+ end
291
+
292
+ task :git_prepare, [:version] do |t, args|
293
+ g = Git.open(Dir.getwd())
294
+ version = args[:version]
295
+ check_version(version)
296
+ g.add(VERSION_FILES)
297
+ g.commit "RELEASE #{version}"
298
+ g.add_tag("#{version}")
299
+ end
300
+
301
+ task :git_push do
302
+ g = Git.open(Dir.getwd())
303
+ g.push
304
+ end
305
+
306
+ task :gems, [:version] do |t, args|
307
+ check_version(args[:version])
308
+ check_gem_list_existence(args[:version])
309
+ gem_list
310
+ end
311
+ end
312
+
231
313
  task :default => :list
232
314
 
233
315
  task :list do
@@ -1,5 +1,13 @@
1
1
  # MongoDB Ruby Driver History
2
2
 
3
+ ### 1.6.1
4
+ 2012-03-07
5
+
6
+ * Added thread affinity to Mongo::Pool
7
+ * Added deploy tasks
8
+ * Added Travis CI support (Cyril Mougel)
9
+ * Logging warning message is only displayed for level :debug
10
+
3
11
  ### 1.6.0
4
12
  2012-02-22
5
13
 
@@ -38,8 +38,16 @@ The driver will essentially cycle through all known seed addresses until a node
38
38
  You can now specify a refresh mode and refresh interval for a replica set connection. This will help to ensure that
39
39
  changes to a replica set's configuration are quickly reflected on the driver side. In particular, if you change
40
40
  the state of any secondary node, the automated refresh will ensure that this state is recorded on the client side.
41
+
42
+ There are two secenarios in which refresh is helpful and does not raise exceptions:
43
+
44
+ # You add a new secondary node to an existing replica set
45
+ # You remove an unused secondary from an existing replica set
46
+
47
+ If using MongoDB earlier than 2.0 any changes to replica set state will raise exceptions therefore refresh mode will not be useful.
48
+
41
49
  If you add a secondary that responds to pings much faster than the existing nodes, then the new secondary will
42
- be used for reads.
50
+ be used for reads if :read_preference is :secondary or :secondary_only
43
51
 
44
52
  Refresh mode is disabled by default.
45
53
 
@@ -61,6 +61,7 @@ require 'mongo/util/pool'
61
61
  require 'mongo/util/pool_manager'
62
62
  require 'mongo/util/server_version'
63
63
  require 'mongo/util/ssl_socket'
64
+ require 'mongo/util/tcp_socket'
64
65
  require 'mongo/util/uri_parser'
65
66
 
66
67
  require 'mongo/collection'
@@ -33,6 +33,8 @@ module Mongo
33
33
  Thread.abort_on_exception = true
34
34
 
35
35
  DEFAULT_PORT = 27017
36
+ GENERIC_OPTS = [:ssl, :auths, :pool_size, :pool_timeout, :timeout, :op_timeout, :connect_timeout, :safe, :logger, :connect]
37
+ CONNECTION_OPTS = [:slave_ok]
36
38
 
37
39
  mongo_thread_local_accessor :connections
38
40
 
@@ -97,10 +99,18 @@ module Mongo
97
99
 
98
100
  # Host and port of current master.
99
101
  @host = @port = nil
102
+
103
+ # Default maximum BSON object size
104
+ @max_bson_size = Mongo::DEFAULT_MAX_BSON_SIZE
105
+
106
+ # Lock for request ids.
107
+ @id_lock = Mutex.new
108
+
109
+ # Connection pool for primay node
110
+ @primary = nil
111
+ @primary_pool = nil
100
112
 
101
- # slave_ok can be true only if one node is specified
102
- @slave_ok = opts[:slave_ok]
103
-
113
+ check_opts(opts)
104
114
  setup(opts)
105
115
  end
106
116
 
@@ -498,32 +508,41 @@ module Mongo
498
508
 
499
509
  # Check a socket back into its pool.
500
510
  def checkin(socket)
501
- if @primary_pool
502
- @primary_pool.checkin(socket)
511
+ if @primary_pool && socket
512
+ socket.pool.checkin(socket)
503
513
  end
504
514
  end
505
515
 
506
516
  protected
507
517
 
508
- # Generic initialization code.
509
- def setup(opts)
510
- # Default maximum BSON object size
511
- @max_bson_size = Mongo::DEFAULT_MAX_BSON_SIZE
518
+ def valid_opts
519
+ GENERIC_OPTS + CONNECTION_OPTS
520
+ end
521
+
522
+ def check_opts(opts)
523
+ bad_opts = opts.keys.reject { |opt| valid_opts.include?(opt) }
524
+
525
+ unless bad_opts.empty?
526
+ bad_opts.each {|opt| warn "#{opt} is not a valid option for #{self.class}"}
527
+ end
528
+ end
512
529
 
530
+ # Parse option hash
531
+ def setup(opts)
532
+ # slave_ok can be true only if one node is specified
533
+ @slave_ok = opts[:slave_ok]
534
+
513
535
  # Determine whether to use SSL.
514
536
  @ssl = opts.fetch(:ssl, false)
515
537
  if @ssl
516
538
  @socket_class = Mongo::SSLSocket
517
539
  else
518
- @socket_class = ::TCPSocket
540
+ @socket_class = Mongo::TCPSocket
519
541
  end
520
542
 
521
543
  # Authentication objects
522
544
  @auths = opts.fetch(:auths, [])
523
545
 
524
- # Lock for request ids.
525
- @id_lock = Mutex.new
526
-
527
546
  # Pool size and timeout.
528
547
  @pool_size = opts[:pool_size] || 1
529
548
  if opts[:timeout]
@@ -540,10 +559,6 @@ module Mongo
540
559
 
541
560
  # Global safe option. This is false by default.
542
561
  @safe = opts[:safe] || false
543
-
544
- # Connection pool for primay node
545
- @primary = nil
546
- @primary_pool = nil
547
562
 
548
563
  @logger = opts.fetch(:logger, nil)
549
564
 
@@ -470,7 +470,7 @@ module Mongo
470
470
  Mongo::Constants::OP_QUERY, message, nil, sock, @command,
471
471
  nil, @options & OP_QUERY_EXHAUST != 0)
472
472
  rescue ConnectionFailure, OperationFailure, OperationTimeout => ex
473
- force_checkin_socket(sock)
473
+ force_checkin_socket(sock) unless @socket
474
474
  raise ex
475
475
  end
476
476
  checkin_socket(sock) unless @socket
@@ -68,7 +68,7 @@ module Mongo
68
68
  # @return [BSON::ObjectId] the file's id.
69
69
  def put(data, opts={})
70
70
  opts = opts.dup
71
- filename = opts[:filename]
71
+ filename = opts.delete(:filename)
72
72
  opts.merge!(default_grid_io_opts)
73
73
  file = GridIO.new(@files, @chunks, filename, 'w', opts)
74
74
  file.write(data)
@@ -21,6 +21,9 @@ module Mongo
21
21
  # Instantiates and manages connections to a MongoDB replica set.
22
22
  class ReplSetConnection < Connection
23
23
 
24
+ REPL_SET_OPTS = [:read, :refresh_mode, :refresh_interval, :require_primary,
25
+ :read_secondary, :rs_name, :name]
26
+
24
27
  attr_reader :replica_set_name, :seeds, :refresh_interval, :refresh_mode,
25
28
  :refresh_version
26
29
 
@@ -33,7 +36,7 @@ module Mongo
33
36
  #
34
37
  # @param [Array] seeds "host:port" strings
35
38
  #
36
- # @option opts [String] :rs_name (nil) The name of the replica set to connect to. You
39
+ # @option opts [String] :name (nil) The name of the replica set to connect to. You
37
40
  # can use this option to verify that you're connecting to the right replica set.
38
41
  # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
39
42
  # propogated to DB objects instantiated off of this Connection. This
@@ -83,11 +86,11 @@ module Mongo
83
86
  else
84
87
  opts = {}
85
88
  end
86
-
89
+
87
90
  unless args.length > 0
88
91
  raise MongoArgumentError, "A ReplSetConnection requires at least one seed node."
89
92
  end
90
-
93
+
91
94
  # This is temporary until support for the old format is dropped
92
95
  @seeds = []
93
96
  if args.first.last.is_a?(Integer)
@@ -106,51 +109,33 @@ module Mongo
106
109
  @seeds.freeze
107
110
 
108
111
  # Refresh
109
- @refresh_mode = opts.fetch(:refresh_mode, false)
110
- @refresh_interval = opts[:refresh_interval] || 90
111
112
  @last_refresh = Time.now
112
113
  @refresh_version = 0
113
114
 
114
115
  # No connection manager by default.
115
116
  @manager = nil
116
- @pool_mutex = Mutex.new
117
+ @old_managers = []
117
118
 
118
- if @refresh_mode == :async
119
- warn ":async refresh mode has been deprecated. Refresh
120
- mode will be disabled."
121
- elsif ![:sync, false].include?(@refresh_mode)
122
- raise MongoArgumentError,
123
- "Refresh mode must be either :sync or false."
124
- end
125
-
126
- # Are we allowing reads from secondaries?
127
- if opts[:read_secondary]
128
- warn ":read_secondary options has now been deprecated and will " +
129
- "be removed in driver v2.0. Use the :read option instead."
130
- @read_secondary = opts.fetch(:read_secondary, false)
131
- @read = :secondary
132
- else
133
- @read = opts.fetch(:read, :primary)
134
- Mongo::Support.validate_read_preference(@read)
135
- end
119
+ # Lock for request ids.
120
+ @id_lock = Mutex.new
136
121
 
122
+ @pool_mutex = Mutex.new
137
123
  @connected = false
138
124
 
139
- # Replica set name
140
- if opts[:rs_name]
141
- warn ":rs_name option has been deprecated and will be removed in v2.0. " +
142
- "Please use :name instead."
143
- @replica_set_name = opts[:rs_name]
144
- else
145
- @replica_set_name = opts[:name]
146
- end
125
+ @safe_mutex_lock = Mutex.new
126
+ @safe_mutexes = Hash.new {|hash, key| hash[key] = Mutex.new}
147
127
 
148
- # Require a primary node to connect?
149
- @require_primary = opts.fetch(:require_primary, true)
128
+ @connect_mutex = Mutex.new
129
+ @refresh_mutex = Mutex.new
150
130
 
131
+ check_opts(opts)
151
132
  setup(opts)
152
133
  end
153
134
 
135
+ def valid_opts
136
+ GENERIC_OPTS + REPL_SET_OPTS
137
+ end
138
+
154
139
  def inspect
155
140
  "<Mongo::ReplSetConnection:0x#{self.object_id.to_s(16)} @seeds=#{@seeds.inspect} " +
156
141
  "@connected=#{@connected}>"
@@ -159,22 +144,26 @@ module Mongo
159
144
  # Initiate a connection to the replica set.
160
145
  def connect
161
146
  log(:info, "Connecting...")
162
- return if @connected
163
-
164
- discovered_seeds = @manager ? @manager.seeds : []
165
- @manager = PoolManager.new(self, discovered_seeds)
166
-
167
- @manager.connect
168
- @refresh_version += 1
169
-
170
- if @require_primary && self.primary.nil? #TODO: in v2.0, we'll let this be optional and do a lazy connect.
171
- close
172
- raise ConnectionFailure, "Failed to connect to primary node."
173
- elsif self.read_pool.nil?
174
- close
175
- raise ConnectionFailure, "Failed to connect to any node."
176
- else
177
- @connected = true
147
+ @connect_mutex.synchronize do
148
+ return if @connected
149
+
150
+ discovered_seeds = @manager ? @manager.seeds : []
151
+ @manager = PoolManager.new(self, discovered_seeds)
152
+
153
+ Thread.current[:manager] = @manager
154
+
155
+ @manager.connect
156
+ @refresh_version += 1
157
+
158
+ if @require_primary && @manager.primary.nil? #TODO: in v2.0, we'll let this be optional and do a lazy connect.
159
+ close
160
+ raise ConnectionFailure, "Failed to connect to primary node."
161
+ elsif @manager.read_pool.nil?
162
+ close
163
+ raise ConnectionFailure, "Failed to connect to any node."
164
+ else
165
+ @connected = true
166
+ end
178
167
  end
179
168
  end
180
169
 
@@ -211,19 +200,21 @@ module Mongo
211
200
  def hard_refresh!
212
201
  log(:info, "Initiating hard refresh...")
213
202
  discovered_seeds = @manager ? @manager.seeds : []
214
- background_manager = PoolManager.new(self, discovered_seeds | @seeds)
215
- background_manager.connect
203
+ new_manager = PoolManager.new(self, discovered_seeds | @seeds)
204
+ new_manager.connect
205
+
206
+ Thread.current[:manager] = new_manager
216
207
 
217
208
  # TODO: make sure that connect has succeeded
218
- old_manager = @manager
219
- @manager = background_manager
220
- old_manager.close(:soft => true)
209
+ @old_managers << @manager
210
+ @manager = new_manager
211
+
221
212
  @refresh_version += 1
222
213
  return true
223
214
  end
224
215
 
225
216
  def connected?
226
- @connected && (self.primary_pool || self.read_pool)
217
+ @connected && (@manager.primary_pool || @manager.read_pool)
227
218
  end
228
219
 
229
220
  # @deprecated
@@ -236,14 +227,14 @@ module Mongo
236
227
  #
237
228
  # @return [String]
238
229
  def host
239
- self.primary_pool.host
230
+ @manager.primary_pool.host
240
231
  end
241
232
 
242
233
  # The replica set primary's port.
243
234
  #
244
235
  # @return [Integer]
245
236
  def port
246
- self.primary_pool.port
237
+ @manager.primary_pool.port
247
238
  end
248
239
 
249
240
  def nodes
@@ -257,7 +248,7 @@ module Mongo
257
248
  #
258
249
  # @return [Boolean]
259
250
  def read_primary?
260
- self.read_pool == self.primary_pool
251
+ @manager.read_pool == @manager.primary_pool
261
252
  end
262
253
  alias :primary? :read_primary?
263
254
 
@@ -296,105 +287,84 @@ module Mongo
296
287
  end
297
288
 
298
289
  def authenticate_pools
299
- self.primary_pool.authenticate_existing
300
- self.secondary_pools.each do |pool|
290
+ primary_pool.authenticate_existing
291
+ secondary_pools.each do |pool|
301
292
  pool.authenticate_existing
302
293
  end
303
294
  end
304
295
 
305
296
  def logout_pools(db)
306
- self.primary_pool.logout_existing(db)
307
- self.secondary_pools.each do |pool|
297
+ primary_pool.logout_existing(db)
298
+ secondary_pools.each do |pool|
308
299
  pool.logout_existing(db)
309
300
  end
310
301
  end
311
302
 
312
- # Checkout a socket for reading (i.e., a secondary node).
313
- # Note that @read_pool might point to the primary pool
314
- # if no read pool has been defined.
315
- def checkout_reader
303
+ # Generic socket checkout
304
+ # Takes a block that returns a socket from pool
305
+ def checkout(&block)
316
306
  if connected?
317
307
  sync_refresh
318
308
  else
319
309
  connect
320
310
  end
311
+
321
312
  begin
322
- socket = get_socket_from_pool(self.read_pool)
323
- if !socket
324
- connect
325
- socket = get_socket_from_pool(self.primary_pool)
326
- end
313
+ socket = block.call
327
314
  rescue => ex
328
315
  checkin(socket) if socket
329
316
  raise ex
330
317
  end
331
-
318
+
332
319
  if socket
333
320
  socket
334
321
  else
335
- raise ConnectionFailure.new("Could not connect to a node for reading.")
322
+ @connected = false
323
+ raise ConnectionFailure.new("Could not checkout a socket.")
336
324
  end
337
325
  end
338
326
 
339
- def checkout_secondary
340
- if connected?
341
- sync_refresh
342
- else
343
- connect
344
- end
345
- begin
346
- socket = get_socket_from_pool(self.secondary_pool)
347
- rescue => ex
348
- checkin(socket) if socket
349
- raise ex
327
+ # Checkout a socket for reading (i.e., a secondary node).
328
+ # Note that @read_pool might point to the primary pool
329
+ # if no read pool has been defined.
330
+ def checkout_reader
331
+ checkout do
332
+ socket = get_socket_from_pool(:read)
333
+ if !socket
334
+ connect
335
+ socket = get_socket_from_pool(:primary)
336
+ end
337
+ socket
350
338
  end
339
+ end
351
340
 
352
- if socket
353
- socket
354
- else
355
- raise ConnectionFailure.new("Could not connect to a secondary for reading.")
341
+ # Checkout a socket from a secondary
342
+ # For :read_preference => :secondary_only
343
+ def checkout_secondary
344
+ checkout do
345
+ get_socket_from_pool(:secondary)
356
346
  end
357
347
  end
358
348
 
359
349
  # Checkout a socket for writing (i.e., a primary node).
360
350
  def checkout_writer
361
- if connected?
362
- sync_refresh
363
- else
364
- connect
365
- end
366
- begin
367
- socket = get_socket_from_pool(self.primary_pool)
368
-
369
- if !socket
370
- connect
371
- socket = get_socket_from_pool(self.primary_pool)
372
- end
373
- rescue => ex
374
- checkin(socket)
375
- raise ex
376
- end
377
-
378
- if socket
379
- socket
380
- else
381
- raise ConnectionFailure.new("Could not connect to primary node.")
351
+ checkout do
352
+ get_socket_from_pool(:primary)
382
353
  end
383
354
  end
384
355
 
385
356
  # Checkin a socket used for reading.
386
357
  def checkin_reader(socket)
387
- if !((self.read_pool && self.read_pool.checkin(socket)) ||
388
- (self.primary_pool && self.primary_pool.checkin(socket)))
389
- close_socket(socket)
358
+ if socket
359
+ socket.pool.checkin(socket)
390
360
  end
391
361
  sync_refresh
392
362
  end
393
363
 
394
364
  # Checkin a socket used for writing.
395
365
  def checkin_writer(socket)
396
- if !self.primary_pool || !self.primary_pool.checkin(socket)
397
- close_socket(socket)
366
+ if socket
367
+ socket.pool.checkin(socket)
398
368
  end
399
369
  sync_refresh
400
370
  end
@@ -407,58 +377,74 @@ module Mongo
407
377
  end
408
378
  end
409
379
 
410
- def get_socket_from_pool(pool)
380
+ def get_socket_from_pool(pool_type)
381
+ if Thread.current[:manager] != @manager
382
+ Thread.current[:manager] = @manager
383
+ end
384
+
385
+ pool = case pool_type
386
+ when :primary
387
+ primary_pool
388
+ when :secondary
389
+ secondary_pool
390
+ when :read
391
+ read_pool
392
+ end
393
+
411
394
  begin
412
395
  if pool
413
- socket = pool.checkout
414
- socket
396
+ pool.checkout
415
397
  end
416
398
  rescue ConnectionFailure => ex
417
399
  log(:info, "Failed to checkout from #{pool} with #{ex.class}; #{ex.message}")
418
400
  return nil
419
401
  end
420
402
  end
403
+
404
+ def local_manager
405
+ Thread.current[:manager]
406
+ end
421
407
 
422
408
  def arbiters
423
- @manager.arbiters.nil? ? [] : @manager.arbiters
409
+ local_manager.arbiters.nil? ? [] : local_manager.arbiters
424
410
  end
425
411
 
426
412
  def primary
427
- @manager ? @manager.primary : nil
413
+ local_manager ? local_manager.primary : nil
428
414
  end
429
415
 
430
416
  # Note: might want to freeze these after connecting.
431
417
  def secondaries
432
- @manager ? @manager.secondaries : []
418
+ local_manager ? local_manager.secondaries : []
433
419
  end
434
420
 
435
421
  def hosts
436
- @manager ? @manager.hosts : []
422
+ local_manager ? local_manager.hosts : []
437
423
  end
438
424
 
439
425
  def primary_pool
440
- @manager ? @manager.primary_pool : nil
426
+ local_manager ? local_manager.primary_pool : nil
441
427
  end
442
428
 
443
429
  def read_pool
444
- @manager ? @manager.read_pool : nil
430
+ local_manager ? local_manager.read_pool : nil
445
431
  end
446
-
432
+
447
433
  def secondary_pool
448
- @manager ? @manager.secondary_pool : nil
434
+ local_manager ? local_manager.secondary_pool : nil
449
435
  end
450
436
 
451
437
  def secondary_pools
452
- @manager ? @manager.secondary_pools : []
438
+ local_manager ? local_manager.secondary_pools : []
453
439
  end
454
440
 
455
441
  def tag_map
456
- @manager ? @manager.tag_map : {}
442
+ local_manager ? local_manager.tag_map : {}
457
443
  end
458
444
 
459
445
  def max_bson_size
460
- if @manager && @manager.max_bson_size
461
- @manager.max_bson_size
446
+ if local_manager && local_manager.max_bson_size
447
+ local_manager.max_bson_size
462
448
  else
463
449
  Mongo::DEFAULT_MAX_BSON_SIZE
464
450
  end
@@ -466,13 +452,45 @@ module Mongo
466
452
 
467
453
  private
468
454
 
469
- # Generic initialization code.
455
+ # Parse option hash
470
456
  def setup(opts)
471
- @safe_mutex_lock = Mutex.new
472
- @safe_mutexes = Hash.new {|hash, key| hash[key] = Mutex.new}
473
-
457
+ # Require a primary node to connect?
458
+ @require_primary = opts.fetch(:require_primary, true)
459
+
460
+ # Refresh
461
+ @refresh_mode = opts.fetch(:refresh_mode, false)
462
+ @refresh_interval = opts[:refresh_interval] || 90
463
+
464
+ if @refresh_mode == :async
465
+ warn ":async refresh mode has been deprecated. Refresh
466
+ mode will be disabled."
467
+ elsif ![:sync, false].include?(@refresh_mode)
468
+ raise MongoArgumentError,
469
+ "Refresh mode must be either :sync or false."
470
+ end
471
+
472
+ # Are we allowing reads from secondaries?
473
+ if opts[:read_secondary]
474
+ warn ":read_secondary options has now been deprecated and will " +
475
+ "be removed in driver v2.0. Use the :read option instead."
476
+ @read_secondary = opts.fetch(:read_secondary, false)
477
+ @read = :secondary
478
+ else
479
+ @read = opts.fetch(:read, :primary)
480
+ Mongo::Support.validate_read_preference(@read)
481
+ end
482
+
483
+ # Replica set name
484
+ if opts[:rs_name]
485
+ warn ":rs_name option has been deprecated and will be removed in v2.0. " +
486
+ "Please use :name instead."
487
+ @replica_set_name = opts[:rs_name]
488
+ else
489
+ @replica_set_name = opts[:name]
490
+ end
491
+
474
492
  opts[:connect_timeout] = opts[:connect_timeout] || 30
475
-
493
+
476
494
  super opts
477
495
  end
478
496
 
@@ -493,12 +511,32 @@ module Mongo
493
511
  raise NodeWithTagsNotFound,
494
512
  "Could not find a connection tagged with #{tags}."
495
513
  end
514
+
515
+ def prune_managers
516
+ @old_managers.each do |manager|
517
+ if manager != @manager
518
+ if manager.closed?
519
+ @old_managers.delete(manager)
520
+ else
521
+ manager.close(:soft => true)
522
+ end
523
+ end
524
+ end
525
+ end
496
526
 
497
527
  def sync_refresh
498
528
  if @refresh_mode == :sync &&
499
529
  ((Time.now - @last_refresh) > @refresh_interval)
500
530
  @last_refresh = Time.now
501
- refresh
531
+
532
+ if @refresh_mutex.try_lock
533
+ begin
534
+ refresh
535
+ prune_managers
536
+ ensure
537
+ @refresh_mutex.unlock
538
+ end
539
+ end
502
540
  end
503
541
  end
504
542
  end