mongo 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +5 -8
- data/Rakefile +84 -2
- data/docs/HISTORY.md +8 -0
- data/docs/REPLICA_SETS.md +9 -1
- data/lib/mongo.rb +1 -0
- data/lib/mongo/connection.rb +32 -17
- data/lib/mongo/cursor.rb +1 -1
- data/lib/mongo/gridfs/grid.rb +1 -1
- data/lib/mongo/repl_set_connection.rb +174 -136
- data/lib/mongo/util/logging.rb +5 -2
- data/lib/mongo/util/node.rb +2 -2
- data/lib/mongo/util/pool.rb +80 -46
- data/lib/mongo/util/pool_manager.rb +8 -0
- data/lib/mongo/util/ssl_socket.rb +2 -1
- data/lib/mongo/util/tcp_socket.rb +6 -0
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +1 -1
- data/test/connection_test.rb +2 -2
- data/test/pool_test.rb +57 -0
- data/test/replica_sets/pooled_insert_test.rb +1 -1
- data/test/replica_sets/read_preference_test.rb +2 -2
- data/test/replica_sets/refresh_with_threads_test.rb +10 -2
- data/test/unit/connection_test.rb +31 -3
- data/test/unit/read_test.rb +5 -3
- metadata +10 -7
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.
|
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'] ||=
|
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'] ||=
|
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
|
287
|
-
individually:
|
286
|
+
If you want to test replica set, you can run the following task:
|
288
287
|
|
289
|
-
$ rake test:
|
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
|
data/docs/HISTORY.md
CHANGED
@@ -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
|
|
data/docs/REPLICA_SETS.md
CHANGED
@@ -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
|
|
data/lib/mongo.rb
CHANGED
data/lib/mongo/connection.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
511
|
+
if @primary_pool && socket
|
512
|
+
socket.pool.checkin(socket)
|
503
513
|
end
|
504
514
|
end
|
505
515
|
|
506
516
|
protected
|
507
517
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
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
|
|
data/lib/mongo/cursor.rb
CHANGED
@@ -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
|
data/lib/mongo/gridfs/grid.rb
CHANGED
@@ -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
|
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] :
|
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
|
-
@
|
117
|
+
@old_managers = []
|
117
118
|
|
118
|
-
|
119
|
-
|
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
|
-
|
140
|
-
|
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
|
-
|
149
|
-
@
|
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
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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
|
-
|
215
|
-
|
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
|
-
|
219
|
-
@manager =
|
220
|
-
|
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 && (
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
300
|
-
|
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
|
-
|
307
|
-
|
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
|
-
#
|
313
|
-
#
|
314
|
-
|
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 =
|
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
|
-
|
322
|
+
@connected = false
|
323
|
+
raise ConnectionFailure.new("Could not checkout a socket.")
|
336
324
|
end
|
337
325
|
end
|
338
326
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
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
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
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
|
-
|
362
|
-
|
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
|
388
|
-
|
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
|
397
|
-
|
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(
|
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
|
-
|
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
|
-
|
409
|
+
local_manager.arbiters.nil? ? [] : local_manager.arbiters
|
424
410
|
end
|
425
411
|
|
426
412
|
def primary
|
427
|
-
|
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
|
-
|
418
|
+
local_manager ? local_manager.secondaries : []
|
433
419
|
end
|
434
420
|
|
435
421
|
def hosts
|
436
|
-
|
422
|
+
local_manager ? local_manager.hosts : []
|
437
423
|
end
|
438
424
|
|
439
425
|
def primary_pool
|
440
|
-
|
426
|
+
local_manager ? local_manager.primary_pool : nil
|
441
427
|
end
|
442
428
|
|
443
429
|
def read_pool
|
444
|
-
|
430
|
+
local_manager ? local_manager.read_pool : nil
|
445
431
|
end
|
446
|
-
|
432
|
+
|
447
433
|
def secondary_pool
|
448
|
-
|
434
|
+
local_manager ? local_manager.secondary_pool : nil
|
449
435
|
end
|
450
436
|
|
451
437
|
def secondary_pools
|
452
|
-
|
438
|
+
local_manager ? local_manager.secondary_pools : []
|
453
439
|
end
|
454
440
|
|
455
441
|
def tag_map
|
456
|
-
|
442
|
+
local_manager ? local_manager.tag_map : {}
|
457
443
|
end
|
458
444
|
|
459
445
|
def max_bson_size
|
460
|
-
if
|
461
|
-
|
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
|
-
#
|
455
|
+
# Parse option hash
|
470
456
|
def setup(opts)
|
471
|
-
|
472
|
-
@
|
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
|
-
|
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
|