mongo 2.10.5 → 2.11.0.rc0
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.
- 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
|