mongo 2.24.1 → 2.26.0
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
- data/bin/mongo_console +2 -2
- data/lib/mongo/address/validator.rb +1 -1
- data/lib/mongo/address.rb +1 -3
- data/lib/mongo/auth/aws/conversation.rb +0 -4
- data/lib/mongo/auth/aws/credentials_retriever.rb +3 -8
- data/lib/mongo/auth/base.rb +1 -1
- data/lib/mongo/auth/sasl_conversation_base.rb +1 -1
- data/lib/mongo/auth/scram_conversation_base.rb +1 -8
- data/lib/mongo/auth/stringprep.rb +1 -6
- data/lib/mongo/auth/user/view.rb +1 -1
- data/lib/mongo/bulk_write/combineable.rb +0 -7
- data/lib/mongo/bulk_write/result_combiner.rb +3 -3
- data/lib/mongo/bulk_write/validatable.rb +0 -4
- data/lib/mongo/bulk_write.rb +1 -35
- data/lib/mongo/client.rb +117 -17
- data/lib/mongo/client_encryption.rb +36 -11
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +12 -5
- data/lib/mongo/cluster/sdam_flow.rb +4 -4
- data/lib/mongo/cluster/topology/base.rb +1 -1
- data/lib/mongo/cluster.rb +13 -30
- data/lib/mongo/collection/queryable_encryption.rb +7 -6
- data/lib/mongo/collection/view/aggregation/behavior.rb +1 -1
- data/lib/mongo/collection/view/aggregation.rb +2 -4
- data/lib/mongo/collection/view/builder/aggregation.rb +3 -5
- data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +14 -9
- data/lib/mongo/collection/view/map_reduce.rb +2 -11
- data/lib/mongo/collection/view/readable.rb +11 -7
- data/lib/mongo/collection/view/writable.rb +4 -39
- data/lib/mongo/collection/view.rb +8 -4
- data/lib/mongo/collection.rb +1 -1
- data/lib/mongo/crypt/auto_encrypter.rb +6 -2
- data/lib/mongo/crypt/binary.rb +7 -4
- data/lib/mongo/crypt/binding.rb +154 -11
- data/lib/mongo/crypt/context.rb +50 -19
- data/lib/mongo/crypt/encryption_io.rb +11 -5
- data/lib/mongo/crypt/explicit_encrypter.rb +27 -12
- data/lib/mongo/crypt/explicit_encryption_context.rb +51 -12
- data/lib/mongo/crypt/handle.rb +35 -5
- data/lib/mongo/crypt/kms/credentials.rb +70 -31
- data/lib/mongo/crypt/kms/kmip/master_document.rb +30 -1
- data/lib/mongo/crypt/kms/master_key_document.rb +11 -6
- data/lib/mongo/crypt/kms.rb +12 -1
- data/lib/mongo/cursor.rb +8 -2
- data/lib/mongo/database/cursor_command_view.rb +95 -0
- data/lib/mongo/database.rb +144 -18
- data/lib/mongo/error/invalid_uri.rb +5 -1
- data/lib/mongo/error/operation_failure.rb +2 -2
- data/lib/mongo/error/parser.rb +3 -3
- data/lib/mongo/error/sdam_error_detection.rb +2 -3
- data/lib/mongo/error/unsupported_option.rb +0 -40
- data/lib/mongo/grid/fs_bucket.rb +29 -23
- data/lib/mongo/grid/stream/read.rb +2 -2
- data/lib/mongo/grid/stream/write.rb +3 -3
- data/lib/mongo/index/view.rb +13 -7
- data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_closed.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_created.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_ready.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/pool_closed.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/pool_created.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/pool_ready.rb +1 -0
- data/lib/mongo/monitoring/event/command_failed.rb +1 -0
- data/lib/mongo/monitoring/event/command_started.rb +1 -0
- data/lib/mongo/monitoring/event/command_succeeded.rb +1 -0
- data/lib/mongo/monitoring/event/secure.rb +12 -17
- data/lib/mongo/monitoring/event/server_closed.rb +1 -0
- data/lib/mongo/monitoring/event/server_description_changed.rb +1 -0
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +1 -0
- data/lib/mongo/monitoring/event/server_heartbeat_started.rb +1 -0
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +1 -0
- data/lib/mongo/monitoring/event/server_opening.rb +1 -0
- data/lib/mongo/monitoring/event/topology_changed.rb +1 -0
- data/lib/mongo/monitoring/event/topology_closed.rb +1 -0
- data/lib/mongo/monitoring/event/topology_opening.rb +1 -0
- data/lib/mongo/operation/create/op_msg.rb +1 -0
- data/lib/mongo/operation/create_index/op_msg.rb +2 -1
- data/lib/mongo/operation/cursor_command/op_msg.rb +37 -0
- data/lib/mongo/operation/cursor_command/result.rb +60 -0
- data/lib/mongo/operation/cursor_command.rb +33 -0
- data/lib/mongo/operation/delete/op_msg.rb +1 -0
- data/lib/mongo/operation/drop/op_msg.rb +1 -0
- data/lib/mongo/operation/drop_database/op_msg.rb +1 -0
- data/lib/mongo/operation/drop_index/op_msg.rb +1 -0
- data/lib/mongo/operation/find/builder/command.rb +1 -1
- data/lib/mongo/operation/insert/bulk_result.rb +2 -4
- data/lib/mongo/operation/insert/op_msg.rb +1 -0
- data/lib/mongo/operation/result.rb +21 -25
- data/lib/mongo/operation/shared/causal_consistency_supported.rb +4 -2
- data/lib/mongo/operation/shared/executable.rb +2 -15
- data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
- data/lib/mongo/operation/shared/sessions_supported.rb +3 -5
- data/lib/mongo/operation/update/bulk_result.rb +1 -1
- data/lib/mongo/operation/update/op_msg.rb +1 -0
- data/lib/mongo/operation/write_command/op_msg.rb +2 -0
- data/lib/mongo/operation.rb +1 -0
- data/lib/mongo/options/redacted.rb +2 -2
- data/lib/mongo/protocol/compressed.rb +15 -11
- data/lib/mongo/protocol/message.rb +16 -20
- data/lib/mongo/protocol/msg.rb +1 -12
- data/lib/mongo/protocol/registry.rb +1 -1
- data/lib/mongo/protocol/serializers.rb +1 -3
- data/lib/mongo/query_cache.rb +3 -5
- data/lib/mongo/retryable/backpressure.rb +17 -2
- data/lib/mongo/retryable/read_worker.rb +1 -1
- data/lib/mongo/retryable/retry_policy.rb +2 -2
- data/lib/mongo/retryable/write_worker.rb +2 -2
- data/lib/mongo/retryable.rb +1 -1
- data/lib/mongo/server/app_metadata.rb +1 -1
- data/lib/mongo/server/connection.rb +3 -1
- data/lib/mongo/server/connection_common.rb +9 -1
- data/lib/mongo/server/connection_pool/generation_manager.rb +1 -1
- data/lib/mongo/server/connection_pool.rb +24 -10
- data/lib/mongo/server/description/features.rb +1 -2
- data/lib/mongo/server/description.rb +1 -2
- data/lib/mongo/server/monitor/connection.rb +3 -2
- data/lib/mongo/server/monitor.rb +133 -30
- data/lib/mongo/server/pending_connection.rb +1 -5
- data/lib/mongo/server/push_monitor.rb +16 -2
- data/lib/mongo/server.rb +28 -9
- data/lib/mongo/server_selector/base.rb +3 -6
- data/lib/mongo/server_selector/secondary_preferred.rb +4 -1
- data/lib/mongo/session.rb +25 -26
- data/lib/mongo/socket/ssl.rb +3 -3
- data/lib/mongo/socket.rb +1 -7
- data/lib/mongo/srv/monitor.rb +11 -2
- data/lib/mongo/srv/resolver.rb +1 -1
- data/lib/mongo/srv/result.rb +5 -3
- data/lib/mongo/timeout.rb +10 -15
- data/lib/mongo/tracing/open_telemetry/command_tracer.rb +16 -2
- data/lib/mongo/uri/options_mapper.rb +36 -13
- data/lib/mongo/uri/srv_protocol.rb +4 -4
- data/lib/mongo/uri.rb +56 -8
- data/lib/mongo/utils.rb +1 -1
- data/lib/mongo/version.rb +1 -1
- metadata +6 -4
- data/lib/mongo/auth/stringprep/unicode_normalize/normalize.rb +0 -173
- data/lib/mongo/auth/stringprep/unicode_normalize/tables.rb +0 -1164
|
@@ -869,6 +869,22 @@ module Mongo
|
|
|
869
869
|
end
|
|
870
870
|
end
|
|
871
871
|
|
|
872
|
+
# Returns statistics about the internal state of the connection pool,
|
|
873
|
+
# primarily for testing and debugging purposes.
|
|
874
|
+
#
|
|
875
|
+
# @return [ Hash ] The state of the connection pool
|
|
876
|
+
#
|
|
877
|
+
# @api private
|
|
878
|
+
def state
|
|
879
|
+
@lock.synchronize do
|
|
880
|
+
{ available_connections: @available_connections.length,
|
|
881
|
+
checked_out_connections: @checked_out_connections.length,
|
|
882
|
+
pending_connections: @pending_connections.length,
|
|
883
|
+
interrupt_connections: @interrupt_connections.length,
|
|
884
|
+
connection_requests: @connection_requests }
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
|
|
872
888
|
private
|
|
873
889
|
|
|
874
890
|
# Returns the next available connection, optionally with given
|
|
@@ -946,7 +962,7 @@ module Mongo
|
|
|
946
962
|
|
|
947
963
|
# Removes and disconnects all stale available connections.
|
|
948
964
|
def remove_stale_connection
|
|
949
|
-
return unless conn = @available_connections.detect { |c| connection_stale_unlocked?(c) }
|
|
965
|
+
return unless (conn = @available_connections.detect { |c| connection_stale_unlocked?(c) })
|
|
950
966
|
|
|
951
967
|
conn.disconnect!(reason: :stale)
|
|
952
968
|
@available_connections.delete(conn)
|
|
@@ -958,7 +974,7 @@ module Mongo
|
|
|
958
974
|
return false if @interrupt_connections.empty?
|
|
959
975
|
|
|
960
976
|
gens = Set.new
|
|
961
|
-
while conn = @interrupt_connections.pop
|
|
977
|
+
while (conn = @interrupt_connections.pop)
|
|
962
978
|
if @checked_out_connections.include?(conn)
|
|
963
979
|
# If the connection has been checked out, mark it as interrupted and it will
|
|
964
980
|
# be disconnected on check in.
|
|
@@ -1042,7 +1058,11 @@ module Mongo
|
|
|
1042
1058
|
@server.unknown!(
|
|
1043
1059
|
generation: e.generation,
|
|
1044
1060
|
service_id: e.service_id,
|
|
1045
|
-
stop_push_monitor: true
|
|
1061
|
+
stop_push_monitor: true,
|
|
1062
|
+
# Only a network error makes the monitor connection suspect and
|
|
1063
|
+
# requires cancelling its check; an auth failure does not.
|
|
1064
|
+
network_error: e.is_a?(Mongo::Error::SocketError) ||
|
|
1065
|
+
e.is_a?(Mongo::Error::SocketTimeoutError)
|
|
1046
1066
|
)
|
|
1047
1067
|
end
|
|
1048
1068
|
connection.disconnect!(reason: :error)
|
|
@@ -1146,12 +1166,6 @@ module Mongo
|
|
|
1146
1166
|
raise Error::ConnectionCheckOutTimeout.new(msg, address: @server.address)
|
|
1147
1167
|
end
|
|
1148
1168
|
|
|
1149
|
-
def raise_check_out_timeout_locked!(connection_global_id)
|
|
1150
|
-
@lock.synchronize do
|
|
1151
|
-
raise_check_out_timeout!(connection_global_id)
|
|
1152
|
-
end
|
|
1153
|
-
end
|
|
1154
|
-
|
|
1155
1169
|
def raise_if_pool_closed!
|
|
1156
1170
|
return unless closed?
|
|
1157
1171
|
|
|
@@ -1246,7 +1260,7 @@ module Mongo
|
|
|
1246
1260
|
# @raise [ Timeout::Error ] If the connection pool is at maximum size
|
|
1247
1261
|
# and remains so for longer than the wait timeout.
|
|
1248
1262
|
def get_connection(pid, connection_global_id)
|
|
1249
|
-
if connection = next_available_connection(connection_global_id)
|
|
1263
|
+
if (connection = next_available_connection(connection_global_id))
|
|
1250
1264
|
return nil unless valid_available_connection?(connection, pid, connection_global_id)
|
|
1251
1265
|
|
|
1252
1266
|
# We've got a connection, so we decrement the number of connection
|
|
@@ -24,7 +24,6 @@ module Mongo
|
|
|
24
24
|
# List of features and the wire protocol version they appear in.
|
|
25
25
|
#
|
|
26
26
|
# Wire protocol versions map to server releases as follows:
|
|
27
|
-
# - 8 => 4.2
|
|
28
27
|
# - 9 => 4.4
|
|
29
28
|
# - 13 => 5.0
|
|
30
29
|
# - 14 => 5.1
|
|
@@ -61,7 +60,7 @@ module Mongo
|
|
|
61
60
|
# The wire protocol versions that this version of the driver supports.
|
|
62
61
|
#
|
|
63
62
|
# @since 2.0.0
|
|
64
|
-
DRIVER_WIRE_VERSIONS =
|
|
63
|
+
DRIVER_WIRE_VERSIONS = 9..29
|
|
65
64
|
|
|
66
65
|
# The wire protocol versions that are deprecated in this version of the
|
|
67
66
|
# driver. Support for these versions will be removed in the future.
|
|
@@ -279,7 +279,7 @@ module Mongo
|
|
|
279
279
|
"The server at #{address.seed} did not provide a service id in handshake response"
|
|
280
280
|
end
|
|
281
281
|
|
|
282
|
-
fake_service_id = if process_id = topology_version && topology_version['processId']
|
|
282
|
+
fake_service_id = if (process_id = topology_version && topology_version['processId'])
|
|
283
283
|
"process:#{process_id}"
|
|
284
284
|
else
|
|
285
285
|
"fake:#{rand((2**32) - 1) + 1}"
|
|
@@ -905,7 +905,6 @@ module Mongo
|
|
|
905
905
|
'5.1' => 14,
|
|
906
906
|
'5.0' => 12,
|
|
907
907
|
'4.4' => 9,
|
|
908
|
-
'4.2' => 8,
|
|
909
908
|
}.freeze
|
|
910
909
|
|
|
911
910
|
# @api private
|
|
@@ -54,9 +54,10 @@ module Mongo
|
|
|
54
54
|
#
|
|
55
55
|
# @since 2.0.0
|
|
56
56
|
def initialize(address, options = {})
|
|
57
|
+
super()
|
|
57
58
|
@address = address
|
|
58
59
|
@options = options.dup.freeze
|
|
59
|
-
raise ArgumentError, 'App metadata is required' unless @app_metadata = options[:app_metadata]
|
|
60
|
+
raise ArgumentError, 'App metadata is required' unless (@app_metadata = options[:app_metadata])
|
|
60
61
|
|
|
61
62
|
@socket = nil
|
|
62
63
|
@pid = Process.pid
|
|
@@ -232,7 +233,7 @@ module Mongo
|
|
|
232
233
|
end
|
|
233
234
|
# compressors must be set to maintain correct compression status
|
|
234
235
|
# in the server description. See RUBY-2427
|
|
235
|
-
if compressors = options[:compressors]
|
|
236
|
+
if (compressors = options[:compressors])
|
|
236
237
|
doc = doc.merge(compression: compressors)
|
|
237
238
|
end
|
|
238
239
|
doc
|
data/lib/mongo/server/monitor.rb
CHANGED
|
@@ -86,14 +86,23 @@ module Mongo
|
|
|
86
86
|
@sdam_mutex = Mutex.new
|
|
87
87
|
@next_earliest_scan = @next_wanted_scan = Time.now
|
|
88
88
|
@update_mutex = Mutex.new
|
|
89
|
+
# Guards reads and writes of @connection so the polling connection can
|
|
90
|
+
# be cancelled from another thread. Per the Server Monitoring spec's
|
|
91
|
+
# cancelCheck pseudocode, the lock is only held long enough to copy or
|
|
92
|
+
# assign the reference - never across the blocking check.
|
|
93
|
+
@connection_lock = Mutex.new
|
|
89
94
|
end
|
|
90
95
|
|
|
91
96
|
# @return [ Server ] server The server that this monitor is monitoring.
|
|
92
97
|
# @api private
|
|
93
98
|
attr_reader :server
|
|
94
99
|
|
|
95
|
-
# @return [ Mongo::Server::Monitor::Connection ]
|
|
96
|
-
|
|
100
|
+
# @return [ Mongo::Server::Monitor::Connection | nil ] The connection to
|
|
101
|
+
# use, read under @connection_lock so callers never observe a stale
|
|
102
|
+
# reference after a concurrent cancel_check! clears it.
|
|
103
|
+
def connection
|
|
104
|
+
@connection_lock.synchronize { @connection }
|
|
105
|
+
end
|
|
97
106
|
|
|
98
107
|
# @return [ Hash ] options The server options.
|
|
99
108
|
attr_reader :options
|
|
@@ -159,7 +168,11 @@ module Mongo
|
|
|
159
168
|
end
|
|
160
169
|
end
|
|
161
170
|
|
|
162
|
-
|
|
171
|
+
# @param [ Mongo::Server::Monitor::Connection ] connection The freshly
|
|
172
|
+
# established monitoring connection. Passed explicitly (rather than read
|
|
173
|
+
# from @connection) so a concurrent cancel_check! cannot nil it out from
|
|
174
|
+
# under us between establishing it and building the PushMonitor.
|
|
175
|
+
def create_push_monitor!(topology_version, connection)
|
|
163
176
|
@update_mutex.synchronize do
|
|
164
177
|
@push_monitor = nil if @push_monitor && !@push_monitor.running?
|
|
165
178
|
|
|
@@ -170,7 +183,7 @@ module Mongo
|
|
|
170
183
|
**Utils.shallow_symbolize_keys(options.merge(
|
|
171
184
|
socket_timeout: heartbeat_interval + connection.socket_timeout,
|
|
172
185
|
app_metadata: options[:push_monitor_app_metadata],
|
|
173
|
-
check_document:
|
|
186
|
+
check_document: connection.check_document
|
|
174
187
|
))
|
|
175
188
|
)
|
|
176
189
|
end
|
|
@@ -185,6 +198,31 @@ module Mongo
|
|
|
185
198
|
end
|
|
186
199
|
end
|
|
187
200
|
|
|
201
|
+
# Cancel the in-progress check and close the monitoring connection.
|
|
202
|
+
#
|
|
203
|
+
# Called when the server is marked Unknown from a network error, per the
|
|
204
|
+
# Server Monitoring spec ("hello or legacy hello Cancellation"). Stops the
|
|
205
|
+
# streaming PushMonitor (interrupting its awaited hello read) and closes
|
|
206
|
+
# the polling connection, so the next check must establish a fresh one
|
|
207
|
+
# rather than re-validating the server over a possibly-dead socket.
|
|
208
|
+
#
|
|
209
|
+
# @api private
|
|
210
|
+
def cancel_check!
|
|
211
|
+
stop_push_monitor!
|
|
212
|
+
|
|
213
|
+
# Copy the connection reference under the lock, then interrupt and close
|
|
214
|
+
# it outside the lock. Closing the socket interrupts any in-progress
|
|
215
|
+
# read on the monitor thread; nil-ing the reference forces the next
|
|
216
|
+
# check to reconnect. The monitor thread is the only writer of a new
|
|
217
|
+
# connection, so it is safe for this thread to clear it.
|
|
218
|
+
connection = @connection_lock.synchronize do
|
|
219
|
+
conn = @connection
|
|
220
|
+
@connection = nil
|
|
221
|
+
conn
|
|
222
|
+
end
|
|
223
|
+
connection&.disconnect!
|
|
224
|
+
end
|
|
225
|
+
|
|
188
226
|
# Perform a check of the server with throttling, and update
|
|
189
227
|
# the server's description and average round trip time.
|
|
190
228
|
#
|
|
@@ -210,28 +248,41 @@ module Mongo
|
|
|
210
248
|
@mutex.synchronize do
|
|
211
249
|
throttle_scan_frequency!
|
|
212
250
|
|
|
251
|
+
# When the streaming protocol is active the PushMonitor is the
|
|
252
|
+
# authoritative SDAM source and this scan only measures RTT on the
|
|
253
|
+
# dedicated connection. Per the Server Monitoring spec, an RTT
|
|
254
|
+
# command MUST NOT publish events or update the topology. Compute
|
|
255
|
+
# this before do_scan, which may (re)connect and change the state.
|
|
256
|
+
rtt_only = rtt_measurement_only?
|
|
257
|
+
|
|
213
258
|
begin
|
|
214
|
-
result = do_scan
|
|
259
|
+
result = do_scan(publish_heartbeat: !rtt_only)
|
|
215
260
|
rescue StandardError => e
|
|
216
|
-
run_sdam_flow({}, scan_error: e)
|
|
261
|
+
run_sdam_flow({}, scan_error: e, rtt_only: rtt_only)
|
|
217
262
|
else
|
|
218
|
-
run_sdam_flow(result)
|
|
263
|
+
run_sdam_flow(result, rtt_only: rtt_only)
|
|
219
264
|
end
|
|
220
265
|
end
|
|
221
266
|
end
|
|
222
267
|
|
|
223
|
-
def run_sdam_flow(result, awaited: false, scan_error: nil)
|
|
268
|
+
def run_sdam_flow(result, awaited: false, scan_error: nil, rtt_only: false)
|
|
224
269
|
@sdam_mutex.synchronize do
|
|
225
270
|
old_description = server.description
|
|
226
271
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
272
|
+
# An RTT-only measurement (streaming protocol active) must not update
|
|
273
|
+
# the topology or publish SDAM events. The RTT it gathered is
|
|
274
|
+
# incorporated into the next streaming-hello description via the
|
|
275
|
+
# shared RTT calculator. The scheduling below still runs so the
|
|
276
|
+
# monitor keeps pacing its checks.
|
|
277
|
+
unless rtt_only
|
|
278
|
+
new_description = Description.new(
|
|
279
|
+
server.address,
|
|
280
|
+
result,
|
|
281
|
+
average_round_trip_time: server.round_trip_time_calculator.average_round_trip_time,
|
|
282
|
+
minimum_round_trip_time: server.round_trip_time_calculator.minimum_round_trip_time
|
|
283
|
+
)
|
|
284
|
+
server.cluster.run_sdam_flow(server.description, new_description, awaited: awaited, scan_error: scan_error)
|
|
285
|
+
end
|
|
235
286
|
|
|
236
287
|
server.description.tap do |new_description|
|
|
237
288
|
unless awaited
|
|
@@ -272,8 +323,12 @@ module Mongo
|
|
|
272
323
|
server.scan_semaphore.signal
|
|
273
324
|
end
|
|
274
325
|
|
|
275
|
-
def do_scan
|
|
276
|
-
|
|
326
|
+
def do_scan(publish_heartbeat: true)
|
|
327
|
+
if publish_heartbeat
|
|
328
|
+
monitoring.publish_heartbeat(server) do
|
|
329
|
+
check
|
|
330
|
+
end
|
|
331
|
+
else
|
|
277
332
|
check
|
|
278
333
|
end
|
|
279
334
|
rescue StandardError => e
|
|
@@ -285,24 +340,53 @@ module Mongo
|
|
|
285
340
|
raise e
|
|
286
341
|
end
|
|
287
342
|
|
|
343
|
+
# Returns whether this scan is only an RTT measurement, which is the case
|
|
344
|
+
# when the streaming protocol is active: a dedicated connection is already
|
|
345
|
+
# established and the PushMonitor is running as the authoritative SDAM
|
|
346
|
+
# source. In the polling protocol there is no running PushMonitor, so the
|
|
347
|
+
# connection-reuse check is a real server check and not RTT-only.
|
|
348
|
+
#
|
|
349
|
+
# @return [ true | false ]
|
|
350
|
+
def rtt_measurement_only?
|
|
351
|
+
return false if connection.nil?
|
|
352
|
+
|
|
353
|
+
# Only suppress the check while the server is in a known state and the
|
|
354
|
+
# PushMonitor is the authoritative streaming source. If the server is
|
|
355
|
+
# Unknown (e.g. an operation error or a streaming failure just marked
|
|
356
|
+
# it so), the polling Monitor must run a full check to recover it
|
|
357
|
+
# rather than waiting for the next streaming response - otherwise the
|
|
358
|
+
# server can stay Unknown long enough to fail server selection.
|
|
359
|
+
return false if server.unknown?
|
|
360
|
+
|
|
361
|
+
pm = push_monitor
|
|
362
|
+
!pm.nil? && pm.running?
|
|
363
|
+
end
|
|
364
|
+
|
|
288
365
|
def check
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
366
|
+
# Snapshot the connection under the lock. A concurrent cancel_check!
|
|
367
|
+
# may nil @connection from another thread; working on a local copy keeps
|
|
368
|
+
# this check consistent, and the guarded writeback below never clobbers
|
|
369
|
+
# a connection the monitor thread did not itself establish.
|
|
370
|
+
connection = self.connection
|
|
371
|
+
|
|
372
|
+
if connection && connection.pid != Process.pid
|
|
373
|
+
log_warn("Detected PID change - Mongo client should have been reconnected (old pid #{connection.pid}, new pid #{Process.pid}")
|
|
374
|
+
connection.disconnect!
|
|
375
|
+
clear_connection(connection)
|
|
376
|
+
connection = nil
|
|
293
377
|
end
|
|
294
378
|
|
|
295
|
-
if
|
|
379
|
+
if connection
|
|
296
380
|
result = server.round_trip_time_calculator.measure do
|
|
297
|
-
doc =
|
|
381
|
+
doc = connection.check_document
|
|
298
382
|
cmd = Protocol::Query.new(
|
|
299
383
|
Database::ADMIN, Database::COMMAND, doc, limit: -1
|
|
300
384
|
)
|
|
301
|
-
message =
|
|
385
|
+
message = connection.dispatch_bytes(cmd.serialize.to_s)
|
|
302
386
|
message.documents.first
|
|
303
387
|
rescue Mongo::Error
|
|
304
|
-
|
|
305
|
-
|
|
388
|
+
connection.disconnect!
|
|
389
|
+
clear_connection(connection)
|
|
306
390
|
raise
|
|
307
391
|
end
|
|
308
392
|
else
|
|
@@ -311,10 +395,13 @@ module Mongo
|
|
|
311
395
|
result = server.round_trip_time_calculator.measure do
|
|
312
396
|
connection.handshake!
|
|
313
397
|
end
|
|
314
|
-
|
|
315
|
-
if tv_doc = result['topologyVersion']
|
|
398
|
+
store_connection(connection)
|
|
399
|
+
if (tv_doc = result['topologyVersion'])
|
|
316
400
|
if streaming_enabled?
|
|
317
|
-
|
|
401
|
+
# Run the instance we just created rather than re-reading the
|
|
402
|
+
# push_monitor getter: a concurrent cancel_check! may have nil'd
|
|
403
|
+
# @push_monitor between the two calls.
|
|
404
|
+
push_monitor = create_push_monitor!(TopologyVersion.new(tv_doc), connection)
|
|
318
405
|
push_monitor.run!
|
|
319
406
|
else
|
|
320
407
|
stop_push_monitor!
|
|
@@ -328,6 +415,22 @@ module Mongo
|
|
|
328
415
|
result
|
|
329
416
|
end
|
|
330
417
|
|
|
418
|
+
# Store a freshly established monitoring connection.
|
|
419
|
+
def store_connection(connection)
|
|
420
|
+
@connection_lock.synchronize do
|
|
421
|
+
@connection = connection
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Clear the monitoring connection, but only if it is still the one passed
|
|
426
|
+
# in. A concurrent cancel_check! may have already cleared or replaced it,
|
|
427
|
+
# in which case we must leave the current connection alone.
|
|
428
|
+
def clear_connection(connection)
|
|
429
|
+
@connection_lock.synchronize do
|
|
430
|
+
@connection = nil if @connection.equal?(connection)
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
331
434
|
# @note If the system clock is set to a time in the past, this method
|
|
332
435
|
# can sleep for a very long time.
|
|
333
436
|
def throttle_scan_frequency!
|
|
@@ -23,6 +23,7 @@ module Mongo
|
|
|
23
23
|
extend Forwardable
|
|
24
24
|
|
|
25
25
|
def initialize(socket, server, monitoring, options = {})
|
|
26
|
+
super()
|
|
26
27
|
@socket = socket
|
|
27
28
|
@options = options
|
|
28
29
|
@server = server
|
|
@@ -51,11 +52,6 @@ module Mongo
|
|
|
51
52
|
# SCRAM-SHA-1. The use of SCRAM-SHA-256 by default is thus
|
|
52
53
|
# sensible, and it is also mandated by the speculative auth spec.
|
|
53
54
|
#
|
|
54
|
-
# If no mechanism was specified and we are talking to a 4.2
|
|
55
|
-
# server, we'll send speculative auth document, the server will
|
|
56
|
-
# ignore it and we'll perform authentication using explicit
|
|
57
|
-
# command.
|
|
58
|
-
#
|
|
59
55
|
# If no mechanism was specified and we are talking to a 4.4+
|
|
60
56
|
# server and the user account doesn't allow SCRAM-SHA-256, we will
|
|
61
57
|
# authenticate in a separate command with SCRAM-SHA-1 after
|
|
@@ -72,7 +72,7 @@ module Mongo
|
|
|
72
72
|
# Interrupt any in-progress exhausted hello reads by
|
|
73
73
|
# disconnecting the connection.
|
|
74
74
|
begin
|
|
75
|
-
@connection.
|
|
75
|
+
@connection.interrupt_socket
|
|
76
76
|
rescue StandardError
|
|
77
77
|
nil
|
|
78
78
|
end
|
|
@@ -118,6 +118,13 @@ module Mongo
|
|
|
118
118
|
log_prefix: options[:log_prefix],
|
|
119
119
|
bg_error_backtrace: options[:bg_error_backtrace])
|
|
120
120
|
|
|
121
|
+
# The streaming check is the authoritative SDAM source, so its failure
|
|
122
|
+
# must mark the server Unknown and clear the pool here. While streaming
|
|
123
|
+
# is active the polling Monitor only measures RTT and ignores errors
|
|
124
|
+
# (per the Server Monitoring spec), so it can no longer be relied on to
|
|
125
|
+
# notice the failure.
|
|
126
|
+
monitor.run_sdam_flow({}, scan_error: e, awaited: true)
|
|
127
|
+
|
|
121
128
|
# If a request failed on a connection, stop push monitoring.
|
|
122
129
|
# In case the server is dead we don't want to have two connections
|
|
123
130
|
# trying to connect unsuccessfully at the same time.
|
|
@@ -142,6 +149,13 @@ module Mongo
|
|
|
142
149
|
@server_pushing = false
|
|
143
150
|
connection = PushMonitor::Connection.new(server.address, options)
|
|
144
151
|
connection.connect!
|
|
152
|
+
# Identify the streaming connection to the server with a metadata
|
|
153
|
+
# handshake (carrying the appName) before streaming, mirroring the
|
|
154
|
+
# polling Monitor and the Server Monitoring spec, which establishes
|
|
155
|
+
# the monitoring connection with a handshake before issuing the
|
|
156
|
+
# awaitable hello. Without this, appName-scoped server behaviour
|
|
157
|
+
# never applies to the streaming hello.
|
|
158
|
+
connection.handshake!
|
|
145
159
|
@connection = connection
|
|
146
160
|
end
|
|
147
161
|
end
|
|
@@ -174,7 +188,7 @@ module Mongo
|
|
|
174
188
|
end
|
|
175
189
|
|
|
176
190
|
def read_response
|
|
177
|
-
if timeout = options[:connect_timeout]
|
|
191
|
+
if (timeout = options[:connect_timeout])
|
|
178
192
|
if timeout < 0
|
|
179
193
|
raise Mongo::SocketTimeoutError, 'Requested to read with a negative timeout: '
|
|
180
194
|
elsif timeout > 0
|
data/lib/mongo/server.rb
CHANGED
|
@@ -489,7 +489,8 @@ module Mongo
|
|
|
489
489
|
unknown!(
|
|
490
490
|
generation: e.generation,
|
|
491
491
|
service_id: e.service_id,
|
|
492
|
-
stop_push_monitor: true
|
|
492
|
+
stop_push_monitor: true,
|
|
493
|
+
network_error: true
|
|
493
494
|
)
|
|
494
495
|
end
|
|
495
496
|
raise
|
|
@@ -514,11 +515,13 @@ module Mongo
|
|
|
514
515
|
raise
|
|
515
516
|
rescue Mongo::Error::SocketError, Auth::Unauthorized => e
|
|
516
517
|
# non-timeout network error or auth error, clear the pool and mark the
|
|
517
|
-
# topology as unknown
|
|
518
|
+
# topology as unknown. Only a network error makes the monitor connection
|
|
519
|
+
# suspect; a pure authentication failure must not close it.
|
|
518
520
|
unknown!(
|
|
519
521
|
generation: e.generation,
|
|
520
522
|
service_id: e.service_id,
|
|
521
|
-
stop_push_monitor: true
|
|
523
|
+
stop_push_monitor: true,
|
|
524
|
+
network_error: e.is_a?(Mongo::Error::SocketError)
|
|
522
525
|
)
|
|
523
526
|
raise
|
|
524
527
|
end
|
|
@@ -564,12 +567,18 @@ module Mongo
|
|
|
564
567
|
# @option options [ true | false ] :keep_connection_pool Usually when the
|
|
565
568
|
# new server description is unknown, the connection pool on the
|
|
566
569
|
# respective server is cleared. Set this option to true to keep the
|
|
567
|
-
# existing connection pool (required when handling not master errors
|
|
568
|
-
# on 4.2+ servers).
|
|
570
|
+
# existing connection pool (required when handling not master errors).
|
|
569
571
|
# @option options [ TopologyVersion ] :topology_version Topology version
|
|
570
572
|
# of the error response that is causing the server to be marked unknown.
|
|
571
|
-
# @option options [ true | false ] :stop_push_monitor
|
|
572
|
-
#
|
|
573
|
+
# @option options [ true | false ] :stop_push_monitor Set when the server
|
|
574
|
+
# is marked Unknown from a connection-establishment error (e.g. an
|
|
575
|
+
# authentication failure). Stops the streaming PushMonitor associated with
|
|
576
|
+
# the server, if any.
|
|
577
|
+
# @option options [ true | false ] :network_error Set when the server is
|
|
578
|
+
# marked Unknown from a network error. In addition to stopping the
|
|
579
|
+
# PushMonitor, cancels the monitor's in-progress check and closes its
|
|
580
|
+
# connection so the next check must establish a fresh one, per the Server
|
|
581
|
+
# Monitoring spec.
|
|
573
582
|
# @option options [ Object ] :service_id Discard state for the specified
|
|
574
583
|
# service id only.
|
|
575
584
|
#
|
|
@@ -590,7 +599,7 @@ module Mongo
|
|
|
590
599
|
# for example if there haven't been any successful connections yet to
|
|
591
600
|
# this server, but the server can still be marked unknown if one
|
|
592
601
|
# of such connections failed midway through its establishment.
|
|
593
|
-
if service_id = options[:service_id]
|
|
602
|
+
if (service_id = options[:service_id])
|
|
594
603
|
pool&.disconnect!(service_id: service_id)
|
|
595
604
|
end
|
|
596
605
|
return
|
|
@@ -605,7 +614,17 @@ module Mongo
|
|
|
605
614
|
return
|
|
606
615
|
end
|
|
607
616
|
|
|
608
|
-
|
|
617
|
+
if options[:network_error]
|
|
618
|
+
# A network error implies every connection to the server is suspect
|
|
619
|
+
# (Server Monitoring spec, "hello or legacy hello Cancellation"): cancel
|
|
620
|
+
# the monitor's in-progress check and close its connection so the next
|
|
621
|
+
# check must establish a fresh one.
|
|
622
|
+
monitor&.cancel_check!
|
|
623
|
+
elsif options[:stop_push_monitor]
|
|
624
|
+
# Non-network errors (e.g. an authentication failure) only tear down the
|
|
625
|
+
# streaming PushMonitor; the monitor's connection is not suspect.
|
|
626
|
+
monitor&.stop_push_monitor!
|
|
627
|
+
end
|
|
609
628
|
|
|
610
629
|
# SDAM flow will update description on the server without in-place
|
|
611
630
|
# mutations and invoke SDAM transitions as needed.
|
|
@@ -239,7 +239,7 @@ module Mongo
|
|
|
239
239
|
|
|
240
240
|
session.unpin unless session.in_transaction?
|
|
241
241
|
|
|
242
|
-
if server = session.pinned_server
|
|
242
|
+
if (server = session.pinned_server)
|
|
243
243
|
# Here we assume that a mongos stays in the topology indefinitely.
|
|
244
244
|
# This will no longer be the case once SRV polling is implemented.
|
|
245
245
|
|
|
@@ -398,9 +398,7 @@ module Mongo
|
|
|
398
398
|
# @api private
|
|
399
399
|
def candidates(cluster, deprioritized = [])
|
|
400
400
|
servers = cluster.servers.reject { |s| deprioritized.include?(s) }
|
|
401
|
-
if cluster.single?
|
|
402
|
-
servers
|
|
403
|
-
elsif cluster.sharded?
|
|
401
|
+
if cluster.single? || cluster.sharded?
|
|
404
402
|
servers
|
|
405
403
|
elsif cluster.replica_set?
|
|
406
404
|
select_in_replica_set(servers)
|
|
@@ -689,8 +687,7 @@ module Mongo
|
|
|
689
687
|
msg = ''
|
|
690
688
|
dead_monitors = []
|
|
691
689
|
cluster.servers_list.each do |server|
|
|
692
|
-
|
|
693
|
-
dead_monitors << server if thread.nil? || !thread.alive?
|
|
690
|
+
dead_monitors << server unless server.monitor&.running?
|
|
694
691
|
end
|
|
695
692
|
if dead_monitors.any?
|
|
696
693
|
msg += ". The following servers have dead monitor threads: #{dead_monitors.map(&:summary).join(', ')}"
|
|
@@ -101,7 +101,10 @@ module Mongo
|
|
|
101
101
|
#
|
|
102
102
|
# @since 2.0.0
|
|
103
103
|
def select_in_replica_set(candidates)
|
|
104
|
-
|
|
104
|
+
eligible = secondaries(candidates)
|
|
105
|
+
return near_servers(eligible) unless eligible.empty?
|
|
106
|
+
|
|
107
|
+
primary(candidates)
|
|
105
108
|
end
|
|
106
109
|
|
|
107
110
|
def max_staleness_allowed?
|