mongo 2.10.5 → 2.11.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CONTRIBUTING.md +1 -1
- data/lib/mongo.rb +2 -0
- data/lib/mongo/address.rb +4 -0
- data/lib/mongo/address/validator.rb +99 -0
- data/lib/mongo/auth.rb +7 -2
- data/lib/mongo/auth/user.rb +1 -7
- data/lib/mongo/background_thread.rb +135 -0
- data/lib/mongo/bulk_write/transformable.rb +3 -3
- data/lib/mongo/client.rb +74 -16
- data/lib/mongo/cluster.rb +193 -41
- data/lib/mongo/cluster/periodic_executor.rb +31 -43
- data/lib/mongo/cluster/sdam_flow.rb +26 -3
- data/lib/mongo/cluster/srv_monitor.rb +127 -0
- data/lib/mongo/collection/view/readable.rb +3 -5
- data/lib/mongo/collection/view/writable.rb +3 -3
- data/lib/mongo/cursor/builder/get_more_command.rb +1 -4
- data/lib/mongo/cursor/builder/kill_cursors_command.rb +5 -23
- data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
- data/lib/mongo/cursor/builder/op_kill_cursors.rb +5 -24
- data/lib/mongo/error.rb +1 -0
- data/lib/mongo/error/auth_error.rb +1 -1
- data/lib/mongo/error/connection_check_out_timeout.rb +7 -8
- data/lib/mongo/error/invalid_address.rb +24 -0
- data/lib/mongo/error/notable.rb +2 -2
- data/lib/mongo/error/operation_failure.rb +3 -3
- data/lib/mongo/error/pool_closed_error.rb +11 -4
- data/lib/mongo/event.rb +1 -1
- data/lib/mongo/grid/file.rb +0 -5
- data/lib/mongo/grid/file/chunk.rb +0 -2
- data/lib/mongo/grid/fs_bucket.rb +13 -15
- data/lib/mongo/grid/stream/write.rb +3 -9
- data/lib/mongo/loggable.rb +5 -1
- data/lib/mongo/monitoring.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +7 -0
- data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +11 -3
- data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +11 -3
- data/lib/mongo/monitoring/event/cmap/pool_closed.rb +11 -3
- data/lib/mongo/monitoring/event/cmap/pool_created.rb +12 -3
- data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +62 -0
- data/lib/mongo/operation/shared/executable.rb +5 -10
- data/lib/mongo/operation/shared/sessions_supported.rb +1 -5
- data/lib/mongo/protocol/get_more.rb +1 -2
- data/lib/mongo/protocol/kill_cursors.rb +13 -6
- data/lib/mongo/protocol/serializers.rb +4 -20
- data/lib/mongo/retryable.rb +9 -34
- data/lib/mongo/semaphore.rb +1 -1
- data/lib/mongo/server.rb +113 -42
- data/lib/mongo/server/connection.rb +12 -5
- data/lib/mongo/server/connection_pool.rb +250 -40
- data/lib/mongo/server/connection_pool/populator.rb +58 -0
- data/lib/mongo/server/description.rb +9 -2
- data/lib/mongo/server/monitor.rb +68 -93
- data/lib/mongo/server/monitor/connection.rb +2 -0
- data/lib/mongo/server_selector/selectable.rb +13 -5
- data/lib/mongo/session.rb +0 -13
- data/lib/mongo/srv.rb +17 -0
- data/lib/mongo/srv/monitor.rb +96 -0
- data/lib/mongo/srv/resolver.rb +130 -0
- data/lib/mongo/srv/result.rb +126 -0
- data/lib/mongo/srv/warning_result.rb +35 -0
- data/lib/mongo/uri.rb +45 -55
- data/lib/mongo/uri/srv_protocol.rb +89 -42
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +3 -4
- data/spec/README.md +6 -1
- data/spec/enterprise_auth/kerberos_spec.rb +7 -6
- data/spec/integration/change_stream_examples_spec.rb +0 -4
- data/spec/integration/client_construction_spec.rb +14 -2
- data/spec/integration/connect_single_rs_name_spec.rb +2 -2
- data/spec/integration/connection_pool_populator_spec.rb +296 -0
- data/spec/integration/connection_spec.rb +31 -22
- data/spec/integration/cursor_reaping_spec.rb +1 -2
- data/spec/integration/docs_examples_spec.rb +0 -4
- data/spec/integration/heartbeat_events_spec.rb +17 -15
- data/spec/integration/reconnect_spec.rb +144 -1
- data/spec/integration/retryable_writes_errors_spec.rb +0 -4
- data/spec/integration/retryable_writes_spec.rb +36 -36
- data/spec/integration/sdam_error_handling_spec.rb +31 -25
- data/spec/integration/sdam_events_spec.rb +2 -6
- data/spec/integration/server_monitor_spec.rb +28 -0
- data/spec/integration/server_selector_spec.rb +7 -5
- data/spec/integration/srv_monitoring_spec.rb +360 -0
- data/spec/integration/step_down_spec.rb +4 -6
- data/spec/lite_spec_helper.rb +22 -0
- data/spec/mongo/address/validator_spec.rb +51 -0
- data/spec/mongo/auth/cr_spec.rb +1 -29
- data/spec/mongo/auth/ldap_spec.rb +1 -29
- data/spec/mongo/auth/scram/conversation_spec.rb +0 -2
- data/spec/mongo/auth/scram/negotiation_spec.rb +1 -1
- data/spec/mongo/auth/scram_spec.rb +1 -29
- data/spec/mongo/auth/user/view_spec.rb +1 -36
- data/spec/mongo/auth/user_spec.rb +0 -12
- data/spec/mongo/auth/x509_spec.rb +1 -29
- data/spec/mongo/bulk_write_spec.rb +2 -2
- data/spec/mongo/client_construction_spec.rb +56 -15
- data/spec/mongo/client_spec.rb +31 -27
- data/spec/mongo/cluster/periodic_executor_spec.rb +16 -0
- data/spec/mongo/cluster/srv_monitor_spec.rb +214 -0
- data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -11
- data/spec/mongo/cluster/topology/sharded_spec.rb +12 -9
- data/spec/mongo/cluster/topology/single_spec.rb +20 -11
- data/spec/mongo/cluster_spec.rb +45 -29
- data/spec/mongo/collection/view/map_reduce_spec.rb +14 -9
- data/spec/mongo/collection/view/readable_spec.rb +0 -16
- data/spec/mongo/collection_spec.rb +0 -44
- data/spec/mongo/cursor/builder/get_more_command_spec.rb +2 -4
- data/spec/mongo/cursor/builder/op_get_more_spec.rb +2 -4
- data/spec/mongo/cursor_spec.rb +27 -7
- data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +10 -3
- data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +10 -3
- data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +10 -3
- data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +10 -3
- data/spec/mongo/operation/delete/op_msg_spec.rb +17 -8
- data/spec/mongo/operation/insert/op_msg_spec.rb +50 -35
- data/spec/mongo/operation/update/op_msg_spec.rb +14 -7
- data/spec/mongo/retryable_spec.rb +52 -31
- data/spec/mongo/server/app_metadata_spec.rb +0 -8
- data/spec/mongo/server/connection_auth_spec.rb +5 -2
- data/spec/mongo/server/connection_pool/populator_spec.rb +101 -0
- data/spec/mongo/server/connection_pool_spec.rb +256 -107
- data/spec/mongo/server/connection_spec.rb +22 -33
- data/spec/mongo/server/description_spec.rb +42 -4
- data/spec/mongo/server/monitor/connection_spec.rb +22 -11
- data/spec/mongo/server/monitor_spec.rb +66 -107
- data/spec/mongo/server_spec.rb +82 -60
- data/spec/mongo/session/session_pool_spec.rb +1 -5
- data/spec/mongo/session_spec.rb +0 -4
- data/spec/mongo/socket/ssl_spec.rb +2 -2
- data/spec/mongo/srv/monitor_spec.rb +211 -0
- data/spec/mongo/srv/result_spec.rb +54 -0
- data/spec/mongo/uri/srv_protocol_spec.rb +30 -15
- data/spec/mongo/uri_spec.rb +125 -4
- data/spec/spec_helper.rb +6 -0
- data/spec/spec_tests/auth_spec.rb +39 -0
- data/spec/spec_tests/cmap_spec.rb +55 -8
- data/spec/spec_tests/connection_string_spec.rb +6 -31
- data/spec/spec_tests/data/auth/connection-string.yml +297 -0
- data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +4 -1
- data/spec/spec_tests/data/cmap/pool-create-with-options.yml +1 -0
- data/spec/spec_tests/data/command_monitoring/insertMany.yml +1 -1
- data/spec/spec_tests/data/connection_string/invalid-uris.yml +20 -0
- data/spec/spec_tests/data/connection_string/valid-auth.yml +16 -0
- data/spec/spec_tests/data/connection_string/valid-warnings.yml +26 -30
- data/spec/spec_tests/data/transactions/abort.yml +3 -3
- data/spec/spec_tests/data/transactions/error-labels.yml +3 -3
- data/spec/spec_tests/data/transactions_api/callback-retry.yml +3 -3
- data/spec/spec_tests/data/uri_options/auth-options.yml +1 -1
- data/spec/spec_tests/max_staleness_spec.rb +7 -2
- data/spec/spec_tests/retryable_reads_spec.rb +0 -31
- data/spec/spec_tests/sdam_monitoring_spec.rb +12 -12
- data/spec/spec_tests/sdam_spec.rb +4 -7
- data/spec/spec_tests/server_selection_spec.rb +6 -2
- data/spec/spec_tests/transactions_spec.rb +0 -2
- data/spec/spec_tests/uri_options_spec.rb +4 -2
- data/spec/stress/connection_pool_stress_spec.rb +203 -0
- data/spec/stress/connection_pool_timing_spec.rb +181 -0
- data/spec/support/auth.rb +113 -0
- data/spec/support/background_thread_registry.rb +63 -0
- data/spec/support/client_registry.rb +11 -2
- data/spec/support/cluster_config.rb +65 -46
- data/spec/support/cluster_tools.rb +2 -2
- data/spec/support/cmap.rb +13 -14
- data/spec/support/cmap/verifier.rb +4 -5
- data/spec/support/command_monitoring.rb +0 -5
- data/spec/support/common_shortcuts.rb +101 -1
- data/spec/support/constraints.rb +25 -0
- data/spec/support/dns.rb +13 -0
- data/spec/support/event_subscriber.rb +0 -7
- data/spec/support/json_ext_formatter.rb +5 -1
- data/spec/support/lite_constraints.rb +22 -6
- data/spec/support/local_resource_registry.rb +34 -0
- data/spec/support/sdam_monitoring.rb +115 -0
- data/spec/support/spec_config.rb +20 -6
- data/spec/support/spec_setup.rb +2 -2
- data/spec/support/transactions.rb +1 -1
- data/spec/support/transactions/test.rb +1 -1
- data/spec/support/utils.rb +1 -16
- metadata +685 -659
- metadata.gz.sig +0 -0
- data/lib/mongo/event/description_changed.rb +0 -52
- data/spec/integration/bson_symbol_spec.rb +0 -34
- data/spec/integration/crud_spec.rb +0 -45
- data/spec/integration/get_more_spec.rb +0 -32
- data/spec/integration/grid_fs_bucket_spec.rb +0 -48
- data/spec/integration/retryable_errors_spec.rb +0 -265
- data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +0 -98
- data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -56
- data/spec/runners/sdam/verifier.rb +0 -88
@@ -123,6 +123,14 @@ module Mongo
|
|
123
123
|
options[:generation]
|
124
124
|
end
|
125
125
|
|
126
|
+
# The connection pool from which this connection was created.
|
127
|
+
# May be nil.
|
128
|
+
#
|
129
|
+
# @api private
|
130
|
+
def connection_pool
|
131
|
+
options[:connection_pool]
|
132
|
+
end
|
133
|
+
|
126
134
|
# Whether the connection was closed.
|
127
135
|
#
|
128
136
|
# Closed connections should no longer be used. Instead obtain a new
|
@@ -151,7 +159,7 @@ module Mongo
|
|
151
159
|
def connect!
|
152
160
|
if closed?
|
153
161
|
if Lint.enabled?
|
154
|
-
raise Error::LintError, "Reconnecting closed connections is no longer supported"
|
162
|
+
raise Error::LintError, "Reconnecting closed connections is no longer supported (for #{address})"
|
155
163
|
else
|
156
164
|
log_warn("Reconnecting closed connections is deprecated (for #{address})")
|
157
165
|
end
|
@@ -290,14 +298,14 @@ module Mongo
|
|
290
298
|
|
291
299
|
def handshake!(socket)
|
292
300
|
unless socket
|
293
|
-
raise Error::HandshakeError, "Cannot handshake because there is no usable socket"
|
301
|
+
raise Error::HandshakeError, "Cannot handshake because there is no usable socket (for #{address})"
|
294
302
|
end
|
295
303
|
|
296
304
|
response = average_rtt = nil
|
297
305
|
@server.handle_handshake_failure! do
|
298
306
|
begin
|
299
307
|
response, exc, rtt, average_rtt =
|
300
|
-
@server.
|
308
|
+
@server.round_trip_time_averager.measure do
|
301
309
|
socket.write(app_metadata.ismaster_bytes)
|
302
310
|
Protocol::Message.deserialize(socket, max_message_size).documents[0]
|
303
311
|
end
|
@@ -349,7 +357,7 @@ module Mongo
|
|
349
357
|
end
|
350
358
|
|
351
359
|
new_description = Description.new(address, response, average_rtt)
|
352
|
-
@server.
|
360
|
+
@server.cluster.run_sdam_flow(@server.description, new_description)
|
353
361
|
end
|
354
362
|
|
355
363
|
def authenticate!(pending_connection)
|
@@ -376,7 +384,6 @@ module Mongo
|
|
376
384
|
# Important: timeout errors are not handled here
|
377
385
|
rescue Error::SocketError
|
378
386
|
@server.unknown!
|
379
|
-
@server.pool.disconnect!
|
380
387
|
raise
|
381
388
|
end
|
382
389
|
end
|
@@ -11,6 +11,7 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
+
require 'mongo/server/connection_pool/populator'
|
14
15
|
|
15
16
|
module Mongo
|
16
17
|
class Server
|
@@ -35,8 +36,21 @@ module Mongo
|
|
35
36
|
|
36
37
|
# The default timeout, in seconds, to wait for a connection.
|
37
38
|
#
|
39
|
+
# This timeout applies while in flow threads are waiting for background
|
40
|
+
# threads to establish connections (and hence they must connect, handshake
|
41
|
+
# and auth in the allotted time).
|
42
|
+
#
|
43
|
+
# It is currently set to 10 seconds. The default connect timeout is
|
44
|
+
# 10 seconds by itself, but setting large timeouts can get applications
|
45
|
+
# in trouble if their requests get timed out by the reverse proxy,
|
46
|
+
# thus anything over 15 seconds is potentially dangerous.
|
47
|
+
#
|
38
48
|
# @since 2.9.0
|
39
|
-
DEFAULT_WAIT_TIMEOUT =
|
49
|
+
DEFAULT_WAIT_TIMEOUT = 10.freeze
|
50
|
+
|
51
|
+
# Condition variable broadcast when the size of the pool changes
|
52
|
+
# to wake up the populator
|
53
|
+
attr_reader :populate_semaphore
|
40
54
|
|
41
55
|
# Create the new connection pool.
|
42
56
|
#
|
@@ -58,6 +72,9 @@ module Mongo
|
|
58
72
|
# are given, their values must be identical.
|
59
73
|
# @option options [ Float ] :max_idle_time The time, in seconds,
|
60
74
|
# after which idle connections should be closed by the pool.
|
75
|
+
# Note: Additionally, options for connections created by this pool should
|
76
|
+
# be included in the options passed here, and they will be forwarded to
|
77
|
+
# any connections created by the pool.
|
61
78
|
#
|
62
79
|
# @since 2.0.0, API changed in 2.9.0
|
63
80
|
def initialize(server, options = {})
|
@@ -99,6 +116,7 @@ module Mongo
|
|
99
116
|
# or in the checked out connections set.
|
100
117
|
@available_connections = available_connections = []
|
101
118
|
@checked_out_connections = Set.new
|
119
|
+
@pending_connections = Set.new
|
102
120
|
|
103
121
|
# Mutex used for synchronizing access to @available_connections and
|
104
122
|
# @checked_out_connections. The pool object is thread-safe, thus
|
@@ -111,25 +129,26 @@ module Mongo
|
|
111
129
|
# available connection when pool is at max size
|
112
130
|
@available_semaphore = Semaphore.new
|
113
131
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
# Those would have to be garbage collected on their own
|
121
|
-
# and that should close them.
|
122
|
-
end
|
123
|
-
ObjectSpace.define_finalizer(self, finalizer)
|
132
|
+
# Background thread reponsible for maintaining the size of
|
133
|
+
# the pool to at least min_size
|
134
|
+
@populator = Populator.new(self, options)
|
135
|
+
@populate_semaphore = Semaphore.new
|
136
|
+
|
137
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(@available_connections, @pending_connections, @populator))
|
124
138
|
|
125
139
|
publish_cmap_event(
|
126
|
-
Monitoring::Event::Cmap::PoolCreated.new(@server.address, options)
|
140
|
+
Monitoring::Event::Cmap::PoolCreated.new(@server.address, options, self)
|
127
141
|
)
|
142
|
+
|
143
|
+
@populator.run! if min_size > 0
|
128
144
|
end
|
129
145
|
|
130
146
|
# @return [ Hash ] options The pool options.
|
131
147
|
attr_reader :options
|
132
148
|
|
149
|
+
# @api private
|
150
|
+
def_delegators :@server, :address
|
151
|
+
|
133
152
|
# Get the maximum size of the connection pool.
|
134
153
|
#
|
135
154
|
# @return [ Integer ] The maximum size of the connection pool.
|
@@ -194,7 +213,7 @@ module Mongo
|
|
194
213
|
# already holding the lock as Ruby does not allow a thread holding a
|
195
214
|
# lock to acquire this lock again.
|
196
215
|
def unsynchronized_size
|
197
|
-
@available_connections.length + @checked_out_connections.
|
216
|
+
@available_connections.length + @checked_out_connections.length + @pending_connections.length
|
198
217
|
end
|
199
218
|
private :unsynchronized_size
|
200
219
|
|
@@ -220,9 +239,23 @@ module Mongo
|
|
220
239
|
!!@closed
|
221
240
|
end
|
222
241
|
|
242
|
+
# @note This method is experimental and subject to change.
|
243
|
+
#
|
244
|
+
# @api experimental
|
245
|
+
# @since 2.11.0
|
246
|
+
def summary
|
247
|
+
@lock.synchronize do
|
248
|
+
"#<ConnectionPool size=#{unsynchronized_size} (#{min_size}-#{max_size}) " +
|
249
|
+
"used=#{@checked_out_connections.length} avail=#{@available_connections.length} pending=#{@pending_connections.length}>"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
223
253
|
# @since 2.9.0
|
224
254
|
def_delegators :@server, :monitoring
|
225
255
|
|
256
|
+
# @api private
|
257
|
+
attr_reader :populator
|
258
|
+
|
226
259
|
# Checks a connection out of the pool.
|
227
260
|
#
|
228
261
|
# If there are active connections in the pool, the most recently used
|
@@ -236,17 +269,26 @@ module Mongo
|
|
236
269
|
# checked back in via the check_in method.
|
237
270
|
#
|
238
271
|
# @return [ Mongo::Server::Connection ] The checked out connection.
|
272
|
+
# @raise [ Error::PoolClosedError ] If the pool has been closed.
|
239
273
|
# @raise [ Timeout::Error ] If the connection pool is at maximum size
|
240
274
|
# and remains so for longer than the wait timeout.
|
241
275
|
#
|
242
276
|
# @since 2.9.0
|
243
277
|
def check_out
|
244
|
-
raise_if_closed!
|
245
|
-
|
246
278
|
publish_cmap_event(
|
247
279
|
Monitoring::Event::Cmap::ConnectionCheckOutStarted.new(@server.address)
|
248
280
|
)
|
249
281
|
|
282
|
+
if closed?
|
283
|
+
publish_cmap_event(
|
284
|
+
Monitoring::Event::Cmap::ConnectionCheckOutFailed.new(
|
285
|
+
@server.address,
|
286
|
+
Monitoring::Event::Cmap::ConnectionCheckOutFailed::POOL_CLOSED
|
287
|
+
),
|
288
|
+
)
|
289
|
+
raise Error::PoolClosedError.new(@server.address, self)
|
290
|
+
end
|
291
|
+
|
250
292
|
deadline = Time.now + wait_timeout
|
251
293
|
connection = nil
|
252
294
|
# It seems that synchronize sets up its own loop, thus a simple break
|
@@ -264,6 +306,7 @@ module Mongo
|
|
264
306
|
# Stale connections should be disconnected in the clear
|
265
307
|
# method, but if any don't, check again here
|
266
308
|
connection.disconnect!(reason: :stale)
|
309
|
+
@populate_semaphore.signal
|
267
310
|
next
|
268
311
|
end
|
269
312
|
|
@@ -271,19 +314,19 @@ module Mongo
|
|
271
314
|
Time.now - connection.last_checkin > max_idle_time
|
272
315
|
then
|
273
316
|
connection.disconnect!(reason: :idle)
|
317
|
+
@populate_semaphore.signal
|
274
318
|
next
|
275
319
|
end
|
276
320
|
|
321
|
+
@pending_connections << connection
|
277
322
|
throw(:done)
|
278
323
|
end
|
279
324
|
|
280
325
|
# Ruby does not allow a thread to lock a mutex which it already
|
281
326
|
# holds.
|
282
327
|
if unsynchronized_size < max_size
|
283
|
-
# This does not currently connect the socket and handshake,
|
284
|
-
# but if it did, it would be performing i/o under our lock,
|
285
|
-
# which is bad. Fix in the future.
|
286
328
|
connection = create_connection
|
329
|
+
@pending_connections << connection
|
287
330
|
throw(:done)
|
288
331
|
end
|
289
332
|
end
|
@@ -296,15 +339,45 @@ module Mongo
|
|
296
339
|
Monitoring::Event::Cmap::ConnectionCheckOutFailed::TIMEOUT,
|
297
340
|
),
|
298
341
|
)
|
299
|
-
|
342
|
+
|
343
|
+
msg = @lock.synchronize do
|
344
|
+
"Timed out attempting to check out a connection " +
|
345
|
+
"from pool for #{@server.address} after #{wait_timeout} sec. " +
|
346
|
+
"Connections in pool: #{@available_connections.length} available, " +
|
347
|
+
"#{@checked_out_connections.length} checked out, " +
|
348
|
+
"#{@pending_connections.length} pending"
|
349
|
+
end
|
350
|
+
raise Error::ConnectionCheckOutTimeout.new(msg, address: @server.address)
|
300
351
|
end
|
301
352
|
@available_semaphore.wait(wait)
|
302
353
|
end
|
303
354
|
end
|
304
355
|
|
305
|
-
|
356
|
+
begin
|
357
|
+
connect_connection(connection)
|
358
|
+
rescue Exception
|
359
|
+
# Handshake or authentication failed
|
360
|
+
@lock.synchronize do
|
361
|
+
@pending_connections.delete(connection)
|
362
|
+
end
|
363
|
+
@populate_semaphore.signal
|
364
|
+
|
365
|
+
publish_cmap_event(
|
366
|
+
Monitoring::Event::Cmap::ConnectionCheckOutFailed.new(
|
367
|
+
@server.address,
|
368
|
+
Monitoring::Event::Cmap::ConnectionCheckOutFailed::CONNECTION_ERROR
|
369
|
+
),
|
370
|
+
)
|
371
|
+
raise
|
372
|
+
end
|
373
|
+
|
374
|
+
@lock.synchronize do
|
375
|
+
@checked_out_connections << connection
|
376
|
+
@pending_connections.delete(connection)
|
377
|
+
end
|
378
|
+
|
306
379
|
publish_cmap_event(
|
307
|
-
Monitoring::Event::Cmap::ConnectionCheckedOut.new(@server.address, connection.id),
|
380
|
+
Monitoring::Event::Cmap::ConnectionCheckedOut.new(@server.address, connection.id, self),
|
308
381
|
)
|
309
382
|
connection
|
310
383
|
end
|
@@ -318,19 +391,23 @@ module Mongo
|
|
318
391
|
# @since 2.9.0
|
319
392
|
def check_in(connection)
|
320
393
|
@lock.synchronize do
|
321
|
-
unless
|
322
|
-
raise ArgumentError, "Trying to check in a connection which
|
394
|
+
unless connection.connection_pool == self
|
395
|
+
raise ArgumentError, "Trying to check in a connection which was not checked out by this pool: #{connection} checked out from pool #{connection.connection_pool} (for #{self})"
|
323
396
|
end
|
324
397
|
|
325
|
-
@checked_out_connections.
|
398
|
+
unless @checked_out_connections.include?(connection)
|
399
|
+
raise ArgumentError, "Trying to check in a connection which is not currently checked out by this pool: #{connection} (for #{self})"
|
400
|
+
end
|
326
401
|
|
327
402
|
# Note: if an event handler raises, resource will not be signaled.
|
328
403
|
# This means threads waiting for a connection to free up when
|
329
404
|
# the pool is at max size may time out.
|
330
405
|
# Threads that begin waiting after this method completes (with
|
331
406
|
# the exception) should be fine.
|
407
|
+
|
408
|
+
@checked_out_connections.delete(connection)
|
332
409
|
publish_cmap_event(
|
333
|
-
Monitoring::Event::Cmap::ConnectionCheckedIn.new(@server.address, connection.id)
|
410
|
+
Monitoring::Event::Cmap::ConnectionCheckedIn.new(@server.address, connection.id, self)
|
334
411
|
)
|
335
412
|
|
336
413
|
if closed?
|
@@ -341,8 +418,10 @@ module Mongo
|
|
341
418
|
if connection.closed?
|
342
419
|
# Connection was closed - for example, because it experienced
|
343
420
|
# a network error. Nothing else needs to be done here.
|
421
|
+
@populate_semaphore.signal
|
344
422
|
elsif connection.generation != @generation
|
345
423
|
connection.disconnect!(reason: :stale)
|
424
|
+
@populate_semaphore.signal
|
346
425
|
else
|
347
426
|
connection.record_checkin!
|
348
427
|
@available_connections << connection
|
@@ -362,6 +441,8 @@ module Mongo
|
|
362
441
|
# @option options [ true | false ] :lazy If true, do not close any of
|
363
442
|
# the idle connections and instead let them be closed during a
|
364
443
|
# subsequent check out operation.
|
444
|
+
# @option options [ true | false ] :stop_populator Whether to stop
|
445
|
+
# the populator background thread. For internal driver use only.
|
365
446
|
#
|
366
447
|
# @return [ true ] true.
|
367
448
|
#
|
@@ -369,6 +450,10 @@ module Mongo
|
|
369
450
|
def clear(options = nil)
|
370
451
|
raise_if_closed!
|
371
452
|
|
453
|
+
if options && options[:stop_populator]
|
454
|
+
stop_populator
|
455
|
+
end
|
456
|
+
|
372
457
|
@lock.synchronize do
|
373
458
|
@generation += 1
|
374
459
|
|
@@ -380,6 +465,7 @@ module Mongo
|
|
380
465
|
until @available_connections.empty?
|
381
466
|
connection = @available_connections.pop
|
382
467
|
connection.disconnect!(reason: :stale)
|
468
|
+
@populate_semaphore.signal
|
383
469
|
end
|
384
470
|
end
|
385
471
|
end
|
@@ -400,31 +486,37 @@ module Mongo
|
|
400
486
|
# @option options [ true | false ] :force Also close all checked out
|
401
487
|
# connections.
|
402
488
|
#
|
403
|
-
# @return [ true ] true.
|
489
|
+
# @return [ true ] Always true.
|
404
490
|
#
|
405
491
|
# @since 2.9.0
|
406
492
|
def close(options = nil)
|
407
493
|
return if closed?
|
408
494
|
|
495
|
+
options ||= {}
|
496
|
+
|
497
|
+
stop_populator
|
498
|
+
|
409
499
|
@lock.synchronize do
|
410
500
|
until @available_connections.empty?
|
411
501
|
connection = @available_connections.pop
|
412
502
|
connection.disconnect!(reason: :pool_closed)
|
413
503
|
end
|
414
504
|
|
415
|
-
if options
|
505
|
+
if options[:force]
|
416
506
|
until @checked_out_connections.empty?
|
417
507
|
connection = @checked_out_connections.take(1).first
|
418
508
|
connection.disconnect!(reason: :pool_closed)
|
419
509
|
@checked_out_connections.delete(connection)
|
420
510
|
end
|
421
511
|
end
|
422
|
-
end
|
423
512
|
|
424
|
-
|
513
|
+
# mark pool as closed before releasing lock so
|
514
|
+
# no connections can be created, checked in, or checked out
|
515
|
+
@closed = true
|
516
|
+
end
|
425
517
|
|
426
518
|
publish_cmap_event(
|
427
|
-
Monitoring::Event::Cmap::PoolClosed.new(@server.address)
|
519
|
+
Monitoring::Event::Cmap::PoolClosed.new(@server.address, self)
|
428
520
|
)
|
429
521
|
|
430
522
|
true
|
@@ -485,6 +577,7 @@ module Mongo
|
|
485
577
|
if (Time.now - last_checkin) > max_idle_time
|
486
578
|
connection.disconnect!(reason: :idle)
|
487
579
|
@available_connections.delete_at(i)
|
580
|
+
@populate_semaphore.signal
|
488
581
|
next
|
489
582
|
end
|
490
583
|
end
|
@@ -493,25 +586,131 @@ module Mongo
|
|
493
586
|
end
|
494
587
|
end
|
495
588
|
|
496
|
-
#
|
589
|
+
# Stop the background populator thread and clean up any connections created
|
590
|
+
# which have not been connected yet.
|
497
591
|
#
|
498
|
-
# Used
|
592
|
+
# Used when closing the pool or when terminating the bg thread for testing
|
593
|
+
# purposes. In the latter case, this method must be called before the pool
|
594
|
+
# is used, to ensure no connections in pending_connections were created in-flow
|
595
|
+
# by the check_out method.
|
596
|
+
#
|
597
|
+
# @api private
|
598
|
+
def stop_populator
|
599
|
+
@populator.stop!
|
600
|
+
|
601
|
+
@lock.synchronize do
|
602
|
+
# If stop_populator is called while populate is running, there may be
|
603
|
+
# connections waiting to be connected, connections which have not yet
|
604
|
+
# been moved to available_connections, or connections moved to available_connections
|
605
|
+
# but not deleted from pending_connections. These should be cleaned up.
|
606
|
+
until @pending_connections.empty?
|
607
|
+
connection = @pending_connections.take(1).first
|
608
|
+
connection.disconnect!
|
609
|
+
@pending_connections.delete(connection)
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
# Creates and adds a connection to the pool, if the pool's size is below
|
615
|
+
# min_size. Retries once if a socket-related error is encountered during
|
616
|
+
# this process and raises if a second error or a non socket-related error occurs.
|
617
|
+
#
|
618
|
+
# Used by the pool populator background thread.
|
619
|
+
#
|
620
|
+
# @return [ true | false ] Whether this method should be called again
|
621
|
+
# to create more connections.
|
622
|
+
# @raise [ Error::AuthError, Error ] The second socket-related error raised if a retry
|
623
|
+
# occured, or the non socket-related error
|
499
624
|
#
|
500
625
|
# @api private
|
501
626
|
def populate
|
502
|
-
|
503
|
-
|
627
|
+
return false if closed?
|
628
|
+
|
629
|
+
begin
|
630
|
+
return create_and_add_connection
|
631
|
+
rescue Error::SocketError, Error::SocketTimeoutError => e
|
632
|
+
# an error was encountered while connecting the connection,
|
633
|
+
# ignore this first error and try again.
|
634
|
+
log_warn("Populator failed to connect a connection for #{address}: #{e.class}: #{e}. It will retry.")
|
635
|
+
end
|
636
|
+
|
637
|
+
return create_and_add_connection
|
638
|
+
rescue Error::AuthError, Error
|
639
|
+
# wake up one thread waiting for connections, since one could not
|
640
|
+
# be created here, and can instead be created in flow
|
641
|
+
@available_semaphore.signal
|
642
|
+
raise
|
643
|
+
end
|
644
|
+
|
645
|
+
# Finalize the connection pool for garbage collection.
|
646
|
+
#
|
647
|
+
# @param [ List<Mongo::Connection> ] available_connections The available connections.
|
648
|
+
# @param [ List<Mongo::Connection> ] pending_connections The pending connections.
|
649
|
+
# @param [ Populator ] populator The populator.
|
650
|
+
#
|
651
|
+
# @return [ Proc ] The Finalizer.
|
652
|
+
def self.finalize(available_connections, pending_connections, populator)
|
653
|
+
proc do
|
654
|
+
populator.stop!
|
655
|
+
|
656
|
+
available_connections.each do |connection|
|
657
|
+
connection.disconnect!(reason: :pool_closed)
|
658
|
+
end
|
659
|
+
available_connections.clear
|
660
|
+
|
661
|
+
pending_connections.each do |connection|
|
662
|
+
connection.disconnect!(reason: :pool_closed)
|
663
|
+
end
|
664
|
+
pending_connections.clear
|
665
|
+
|
666
|
+
# Finalizer does not close checked out connections.
|
667
|
+
# Those would have to be garbage collected on their own
|
668
|
+
# and that should close them.
|
504
669
|
end
|
505
670
|
end
|
506
671
|
|
507
672
|
private
|
508
673
|
|
509
674
|
def create_connection
|
510
|
-
connection = Connection.new(@server, options.merge(generation: generation
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
675
|
+
connection = Connection.new(@server, options.merge(generation: generation,
|
676
|
+
connection_pool: self))
|
677
|
+
end
|
678
|
+
|
679
|
+
# Create a connection, connect it, and add it to the pool.
|
680
|
+
#
|
681
|
+
# @return [ true | false ] True if a connection was created and
|
682
|
+
# added to the pool, false otherwise
|
683
|
+
# @raise [ Mongo::Error ] An error encountered during connection connect
|
684
|
+
def create_and_add_connection
|
685
|
+
connection = nil
|
686
|
+
|
687
|
+
@lock.synchronize do
|
688
|
+
if !closed? && unsynchronized_size < min_size
|
689
|
+
connection = create_connection
|
690
|
+
@pending_connections << connection
|
691
|
+
else
|
692
|
+
return false
|
693
|
+
end
|
694
|
+
end
|
695
|
+
|
696
|
+
begin
|
697
|
+
connect_connection(connection)
|
698
|
+
rescue Exception
|
699
|
+
@lock.synchronize do
|
700
|
+
@pending_connections.delete(connection)
|
701
|
+
end
|
702
|
+
raise
|
703
|
+
end
|
704
|
+
|
705
|
+
@lock.synchronize do
|
706
|
+
@available_connections << connection
|
707
|
+
@pending_connections.delete(connection)
|
708
|
+
|
709
|
+
# wake up one thread waiting for connections, since one was created
|
710
|
+
@available_semaphore.signal
|
711
|
+
end
|
712
|
+
|
713
|
+
true
|
515
714
|
end
|
516
715
|
|
517
716
|
# Asserts that the pool has not been closed.
|
@@ -521,7 +720,18 @@ module Mongo
|
|
521
720
|
# @since 2.9.0
|
522
721
|
def raise_if_closed!
|
523
722
|
if closed?
|
524
|
-
raise Error::PoolClosedError.new(@server.address)
|
723
|
+
raise Error::PoolClosedError.new(@server.address, self)
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
# Attempts to connect (handshake and auth) the connection. If an error is
|
728
|
+
# encountered, closes the connection and raises the error.
|
729
|
+
def connect_connection(connection)
|
730
|
+
begin
|
731
|
+
connection.connect!
|
732
|
+
rescue Exception
|
733
|
+
connection.disconnect!(reason: :error)
|
734
|
+
raise
|
525
735
|
end
|
526
736
|
end
|
527
737
|
end
|