mongo 2.13.0.beta1 → 2.13.0.rc1
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 +1 -5
- data/Rakefile +15 -9
- data/lib/mongo.rb +4 -2
- data/lib/mongo/auth/aws/request.rb +4 -2
- data/lib/mongo/bulk_write.rb +1 -0
- data/lib/mongo/client.rb +143 -21
- data/lib/mongo/cluster.rb +53 -17
- data/lib/mongo/cluster/sdam_flow.rb +13 -10
- data/lib/mongo/cluster/topology/replica_set_no_primary.rb +3 -2
- data/lib/mongo/cluster/topology/sharded.rb +1 -1
- data/lib/mongo/cluster/topology/single.rb +1 -1
- data/lib/mongo/collection.rb +17 -13
- data/lib/mongo/collection/view/readable.rb +3 -1
- data/lib/mongo/collection/view/writable.rb +41 -5
- data/lib/mongo/database.rb +31 -4
- data/lib/mongo/database/view.rb +19 -4
- data/lib/mongo/distinguishing_semaphore.rb +55 -0
- data/lib/mongo/error.rb +1 -0
- data/lib/mongo/error/invalid_session.rb +2 -1
- data/lib/mongo/error/operation_failure.rb +6 -0
- data/lib/mongo/error/sessions_not_supported.rb +35 -0
- data/lib/mongo/event/base.rb +6 -0
- data/lib/mongo/grid/file.rb +5 -0
- data/lib/mongo/grid/file/chunk.rb +2 -0
- data/lib/mongo/grid/fs_bucket.rb +15 -13
- data/lib/mongo/grid/stream/write.rb +9 -3
- data/lib/mongo/monitoring.rb +38 -0
- data/lib/mongo/monitoring/command_log_subscriber.rb +10 -2
- data/lib/mongo/monitoring/event/command_failed.rb +11 -0
- data/lib/mongo/monitoring/event/command_started.rb +37 -2
- data/lib/mongo/monitoring/event/command_succeeded.rb +11 -0
- data/lib/mongo/monitoring/event/server_closed.rb +1 -1
- data/lib/mongo/monitoring/event/server_description_changed.rb +27 -4
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +9 -2
- data/lib/mongo/monitoring/event/server_heartbeat_started.rb +9 -2
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +9 -2
- data/lib/mongo/monitoring/event/server_opening.rb +1 -1
- data/lib/mongo/monitoring/event/topology_changed.rb +1 -1
- data/lib/mongo/monitoring/event/topology_closed.rb +1 -1
- data/lib/mongo/monitoring/event/topology_opening.rb +1 -1
- data/lib/mongo/monitoring/publishable.rb +6 -3
- data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +9 -1
- data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +1 -1
- data/lib/mongo/protocol/message.rb +36 -8
- data/lib/mongo/protocol/msg.rb +14 -0
- data/lib/mongo/protocol/serializers.rb +5 -2
- data/lib/mongo/server.rb +10 -3
- data/lib/mongo/server/connection.rb +4 -4
- data/lib/mongo/server/connection_base.rb +3 -1
- data/lib/mongo/server/description.rb +5 -0
- data/lib/mongo/server/monitor.rb +76 -44
- data/lib/mongo/server/monitor/connection.rb +55 -7
- data/lib/mongo/server/pending_connection.rb +14 -4
- data/lib/mongo/server/push_monitor.rb +173 -0
- data/{spec/runners/transactions/context.rb → lib/mongo/server/push_monitor/connection.rb} +9 -14
- data/lib/mongo/server_selector.rb +0 -1
- data/lib/mongo/server_selector/base.rb +579 -1
- data/lib/mongo/server_selector/nearest.rb +1 -6
- data/lib/mongo/server_selector/primary.rb +1 -6
- data/lib/mongo/server_selector/primary_preferred.rb +7 -10
- data/lib/mongo/server_selector/secondary.rb +1 -6
- data/lib/mongo/server_selector/secondary_preferred.rb +1 -7
- data/lib/mongo/session.rb +2 -0
- data/lib/mongo/socket.rb +20 -8
- data/lib/mongo/socket/ssl.rb +1 -1
- data/lib/mongo/socket/tcp.rb +1 -1
- data/lib/mongo/topology_version.rb +9 -0
- data/lib/mongo/utils.rb +62 -0
- data/lib/mongo/version.rb +1 -1
- data/spec/README.aws-auth.md +2 -2
- data/spec/integration/awaited_ismaster_spec.rb +28 -0
- data/spec/integration/change_stream_examples_spec.rb +6 -2
- data/spec/integration/check_clean_slate_spec.rb +16 -0
- data/spec/integration/client_construction_spec.rb +1 -0
- data/spec/integration/connect_single_rs_name_spec.rb +5 -2
- data/spec/integration/connection_spec.rb +7 -4
- data/spec/integration/crud_spec.rb +4 -4
- data/spec/integration/docs_examples_spec.rb +6 -0
- data/spec/integration/grid_fs_bucket_spec.rb +48 -0
- data/spec/integration/heartbeat_events_spec.rb +4 -23
- data/spec/integration/read_concern_spec.rb +1 -1
- data/spec/integration/retryable_errors_spec.rb +1 -1
- data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +2 -2
- data/spec/integration/retryable_writes/shared/performs_modern_retries.rb +3 -3
- data/spec/integration/retryable_writes/shared/performs_no_retries.rb +2 -2
- data/spec/integration/sdam_error_handling_spec.rb +37 -15
- data/spec/integration/sdam_events_spec.rb +77 -6
- data/spec/integration/sdam_prose_spec.rb +64 -0
- data/spec/integration/server_monitor_spec.rb +25 -1
- data/spec/integration/size_limit_spec.rb +7 -3
- data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
- data/spec/integration/ssl_uri_options_spec.rb +2 -2
- data/spec/integration/zlib_compression_spec.rb +25 -0
- data/spec/lite_spec_helper.rb +12 -5
- data/spec/mongo/auth/aws/request_spec.rb +76 -0
- data/spec/mongo/auth/scram_spec.rb +1 -1
- data/spec/mongo/client_construction_spec.rb +207 -0
- data/spec/mongo/client_spec.rb +38 -3
- data/spec/mongo/cluster/topology/replica_set_spec.rb +52 -9
- data/spec/mongo/cluster/topology/single_spec.rb +4 -2
- data/spec/mongo/cluster_spec.rb +34 -35
- data/spec/mongo/collection/view/change_stream_resume_spec.rb +6 -6
- data/spec/mongo/collection_spec.rb +500 -0
- data/spec/mongo/database_spec.rb +245 -8
- data/spec/mongo/distinguishing_semaphore_spec.rb +63 -0
- data/spec/mongo/error/operation_failure_spec.rb +40 -0
- data/spec/mongo/index/view_spec.rb +2 -2
- data/spec/mongo/monitoring/event/server_description_changed_spec.rb +1 -4
- data/spec/mongo/protocol/msg_spec.rb +10 -0
- data/spec/mongo/semaphore_spec.rb +51 -0
- data/spec/mongo/server/connection_auth_spec.rb +2 -2
- data/spec/mongo/server_selector/nearest_spec.rb +23 -23
- data/spec/mongo/server_selector/primary_preferred_spec.rb +26 -26
- data/spec/mongo/server_selector/primary_spec.rb +9 -9
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +22 -22
- data/spec/mongo/server_selector/secondary_spec.rb +18 -18
- data/spec/mongo/server_selector_spec.rb +4 -4
- data/spec/mongo/session_spec.rb +35 -0
- data/spec/runners/change_streams/test.rb +2 -2
- data/spec/runners/cmap.rb +1 -1
- data/spec/runners/command_monitoring.rb +3 -34
- data/spec/runners/crud/context.rb +9 -5
- data/spec/runners/crud/operation.rb +59 -27
- data/spec/runners/crud/spec.rb +0 -8
- data/spec/runners/crud/test.rb +1 -1
- data/spec/runners/sdam.rb +2 -2
- data/spec/runners/server_selection.rb +242 -28
- data/spec/runners/transactions.rb +12 -12
- data/spec/runners/transactions/operation.rb +151 -25
- data/spec/runners/transactions/test.rb +60 -16
- data/spec/spec_tests/command_monitoring_spec.rb +22 -12
- data/spec/spec_tests/crud_spec.rb +1 -1
- data/spec/spec_tests/data/change_streams/change-streams-errors.yml +4 -8
- data/spec/spec_tests/data/change_streams/change-streams-resume-whitelist.yml +66 -0
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/MaxStalenessTooSmall.yml +15 -0
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +4 -3
- data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -0
- data/spec/spec_tests/data/sdam_integration/cancel-server-check.yml +96 -0
- data/spec/spec_tests/data/sdam_integration/connectTimeoutMS.yml +88 -0
- data/spec/spec_tests/data/sdam_integration/find-network-error.yml +83 -0
- data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +116 -0
- data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +86 -0
- data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +115 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-command-error.yml +168 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-network-error.yml +162 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-timeout.yml +229 -0
- data/spec/spec_tests/data/sdam_integration/rediscover-quickly-after-step-down.yml +87 -0
- data/spec/spec_tests/max_staleness_spec.rb +4 -142
- data/spec/spec_tests/retryable_reads_spec.rb +2 -2
- data/spec/spec_tests/sdam_integration_spec.rb +13 -0
- data/spec/spec_tests/sdam_monitoring_spec.rb +1 -2
- data/spec/spec_tests/server_selection_spec.rb +4 -116
- data/spec/stress/cleanup_spec.rb +17 -2
- data/spec/stress/connection_pool_stress_spec.rb +10 -8
- data/spec/support/child_process_helper.rb +78 -0
- data/spec/support/client_registry.rb +1 -0
- data/spec/support/cluster_config.rb +4 -0
- data/spec/support/event_subscriber.rb +123 -33
- data/spec/support/keyword_struct.rb +26 -0
- data/spec/support/shared/server_selector.rb +13 -1
- data/spec/support/spec_config.rb +38 -13
- data/spec/support/spec_organizer.rb +129 -0
- data/spec/support/spec_setup.rb +1 -1
- data/spec/support/utils.rb +46 -0
- metadata +992 -942
- metadata.gz.sig +0 -0
- data/lib/mongo/server_selector/selectable.rb +0 -560
- data/spec/runners/sdam_monitoring.rb +0 -89
@@ -36,6 +36,11 @@ module Mongo
|
|
36
36
|
# Alias of error for SDAM spec compliance.
|
37
37
|
alias :failure :error
|
38
38
|
|
39
|
+
# @return [ true | false ] Whether the heartbeat was awaited.
|
40
|
+
def awaited?
|
41
|
+
@awaited
|
42
|
+
end
|
43
|
+
|
39
44
|
# Create the event.
|
40
45
|
#
|
41
46
|
# @example Create the event.
|
@@ -43,13 +48,15 @@ module Mongo
|
|
43
48
|
#
|
44
49
|
# @param [ Address ] address The server address.
|
45
50
|
# @param [ Float ] round_trip_time Duration of ismaster call in seconds.
|
51
|
+
# @param [ true | false ] awaited Whether the heartbeat was awaited.
|
46
52
|
#
|
47
53
|
# @since 2.7.0
|
48
54
|
# @api private
|
49
|
-
def initialize(address, round_trip_time, error)
|
55
|
+
def initialize(address, round_trip_time, error, awaited: false)
|
50
56
|
@address = address
|
51
57
|
@round_trip_time = round_trip_time
|
52
58
|
@error = error
|
59
|
+
@awaited = !!awaited
|
53
60
|
end
|
54
61
|
|
55
62
|
# Returns a concise yet useful summary of the event.
|
@@ -61,7 +68,7 @@ module Mongo
|
|
61
68
|
# @since 2.7.0
|
62
69
|
# @api experimental
|
63
70
|
def summary
|
64
|
-
"#<#{
|
71
|
+
"#<#{short_class_name}" +
|
65
72
|
" address=#{address}" +
|
66
73
|
" error=#{error.inspect}>"
|
67
74
|
end
|
@@ -24,17 +24,24 @@ module Mongo
|
|
24
24
|
# @return [ Address ] address The server address.
|
25
25
|
attr_reader :address
|
26
26
|
|
27
|
+
# @return [ true | false ] Whether the heartbeat was awaited.
|
28
|
+
def awaited?
|
29
|
+
@awaited
|
30
|
+
end
|
31
|
+
|
27
32
|
# Create the event.
|
28
33
|
#
|
29
34
|
# @example Create the event.
|
30
35
|
# ServerHeartbeatStarted.new(address)
|
31
36
|
#
|
32
37
|
# @param [ Address ] address The server address.
|
38
|
+
# @param [ true | false ] awaited Whether the heartbeat was awaited.
|
33
39
|
#
|
34
40
|
# @since 2.7.0
|
35
41
|
# @api private
|
36
|
-
def initialize(address)
|
42
|
+
def initialize(address, awaited: false)
|
37
43
|
@address = address
|
44
|
+
@awaited = !!awaited
|
38
45
|
end
|
39
46
|
|
40
47
|
# Returns a concise yet useful summary of the event.
|
@@ -46,7 +53,7 @@ module Mongo
|
|
46
53
|
# @since 2.7.0
|
47
54
|
# @api experimental
|
48
55
|
def summary
|
49
|
-
"#<#{
|
56
|
+
"#<#{short_class_name}" +
|
50
57
|
" address=#{address}>"
|
51
58
|
end
|
52
59
|
end
|
@@ -30,6 +30,11 @@ module Mongo
|
|
30
30
|
# Alias of round_trip_time.
|
31
31
|
alias :duration :round_trip_time
|
32
32
|
|
33
|
+
# @return [ true | false ] Whether the heartbeat was awaited.
|
34
|
+
def awaited?
|
35
|
+
@awaited
|
36
|
+
end
|
37
|
+
|
33
38
|
# Create the event.
|
34
39
|
#
|
35
40
|
# @example Create the event.
|
@@ -37,12 +42,14 @@ module Mongo
|
|
37
42
|
#
|
38
43
|
# @param [ Address ] address The server address.
|
39
44
|
# @param [ Float ] round_trip_time Duration of ismaster call in seconds.
|
45
|
+
# @param [ true | false ] awaited Whether the heartbeat was awaited.
|
40
46
|
#
|
41
47
|
# @since 2.7.0
|
42
48
|
# @api private
|
43
|
-
def initialize(address, round_trip_time)
|
49
|
+
def initialize(address, round_trip_time, awaited: false)
|
44
50
|
@address = address
|
45
51
|
@round_trip_time = round_trip_time
|
52
|
+
@awaited = !!awaited
|
46
53
|
end
|
47
54
|
|
48
55
|
# Returns a concise yet useful summary of the event.
|
@@ -54,7 +61,7 @@ module Mongo
|
|
54
61
|
# @since 2.7.0
|
55
62
|
# @api experimental
|
56
63
|
def summary
|
57
|
-
"#<#{
|
64
|
+
"#<#{short_class_name}" +
|
58
65
|
" address=#{address}>"
|
59
66
|
end
|
60
67
|
end
|
@@ -32,7 +32,7 @@ module Mongo
|
|
32
32
|
def publish_sdam_event(topic, event)
|
33
33
|
return unless monitoring?
|
34
34
|
|
35
|
-
log_debug("EVENT: #{event.summary}")
|
35
|
+
#log_debug("EVENT: #{event.summary}")
|
36
36
|
monitoring.succeeded(topic, event)
|
37
37
|
end
|
38
38
|
|
@@ -45,13 +45,16 @@ module Mongo
|
|
45
45
|
private
|
46
46
|
|
47
47
|
def command_started(address, operation_id, payload,
|
48
|
-
socket_object_id: nil, connection_id: nil, connection_generation: nil
|
48
|
+
socket_object_id: nil, connection_id: nil, connection_generation: nil,
|
49
|
+
server_connection_id: nil
|
49
50
|
)
|
50
51
|
monitoring.started(
|
51
52
|
Monitoring::COMMAND,
|
52
53
|
Event::CommandStarted.generate(address, operation_id, payload,
|
53
54
|
socket_object_id: socket_object_id, connection_id: connection_id,
|
54
|
-
connection_generation: connection_generation
|
55
|
+
connection_generation: connection_generation,
|
56
|
+
server_connection_id: server_connection_id,
|
57
|
+
)
|
55
58
|
)
|
56
59
|
end
|
57
60
|
|
@@ -25,9 +25,17 @@ module Mongo
|
|
25
25
|
def log_event(event)
|
26
26
|
log_debug(
|
27
27
|
"Server description for #{event.address} changed from " +
|
28
|
-
"'#{event.previous_description.server_type}' to '#{event.new_description.server_type}'."
|
28
|
+
"'#{event.previous_description.server_type}' to '#{event.new_description.server_type}'#{awaited_indicator(event)}."
|
29
29
|
)
|
30
30
|
end
|
31
|
+
|
32
|
+
def awaited_indicator(event)
|
33
|
+
if event.awaited?
|
34
|
+
' [awaited]'
|
35
|
+
else
|
36
|
+
''
|
37
|
+
end
|
38
|
+
end
|
31
39
|
end
|
32
40
|
end
|
33
41
|
end
|
@@ -23,7 +23,7 @@ module Mongo
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def log_event(event)
|
26
|
-
if event.previous_topology != event.new_topology
|
26
|
+
if event.previous_topology.class != event.new_topology.class
|
27
27
|
log_debug(
|
28
28
|
"Topology type '#{event.previous_topology.display_name}' changed to " +
|
29
29
|
"type '#{event.new_topology.display_name}'."
|
@@ -199,10 +199,33 @@ module Mongo
|
|
199
199
|
# @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
|
200
200
|
# this message using BSON types instead of native Ruby types wherever
|
201
201
|
# possible.
|
202
|
+
# @option options [ Numeric ] :socket_timeout The timeout to use for
|
203
|
+
# each read operation.
|
202
204
|
#
|
203
205
|
# @return [ Message ] Instance of a Message class
|
204
|
-
|
205
|
-
|
206
|
+
#
|
207
|
+
# @api private
|
208
|
+
def self.deserialize(io,
|
209
|
+
max_message_size = MAX_MESSAGE_SIZE,
|
210
|
+
expected_response_to = nil,
|
211
|
+
options = {}
|
212
|
+
)
|
213
|
+
# io is usually a Mongo::Socket instance, which supports the
|
214
|
+
# timeout option. For compatibility with whoever might call this
|
215
|
+
# method with some other IO-like object, pass options only when they
|
216
|
+
# are not empty.
|
217
|
+
read_options = {}
|
218
|
+
if timeout = options[:socket_timeout]
|
219
|
+
read_options[:timeout] = timeout
|
220
|
+
end
|
221
|
+
|
222
|
+
if read_options.empty?
|
223
|
+
chunk = io.read(16)
|
224
|
+
else
|
225
|
+
chunk = io.read(16, **read_options)
|
226
|
+
end
|
227
|
+
buf = BSON::ByteBuffer.new(chunk)
|
228
|
+
length, _request_id, response_to, _op_code = deserialize_header(buf)
|
206
229
|
|
207
230
|
# Protection from potential DOS man-in-the-middle attacks. See
|
208
231
|
# DRIVERS-276.
|
@@ -216,14 +239,19 @@ module Mongo
|
|
216
239
|
raise Error::UnexpectedResponse.new(expected_response_to, response_to)
|
217
240
|
end
|
218
241
|
|
219
|
-
|
220
|
-
|
242
|
+
if read_options.empty?
|
243
|
+
chunk = io.read(length - 16)
|
244
|
+
else
|
245
|
+
chunk = io.read(length - 16, **read_options)
|
246
|
+
end
|
247
|
+
buf = BSON::ByteBuffer.new(chunk)
|
221
248
|
|
249
|
+
message = Registry.get(_op_code).allocate
|
222
250
|
message.send(:fields).each do |field|
|
223
251
|
if field[:multi]
|
224
|
-
deserialize_array(message,
|
252
|
+
deserialize_array(message, buf, field, options)
|
225
253
|
else
|
226
|
-
deserialize_field(message,
|
254
|
+
deserialize_field(message, buf, field, options)
|
227
255
|
end
|
228
256
|
end
|
229
257
|
if message.is_a?(Msg)
|
@@ -374,7 +402,7 @@ module Mongo
|
|
374
402
|
# each of the elements in this array using BSON types wherever possible.
|
375
403
|
#
|
376
404
|
# @return [Message] Message with deserialized array.
|
377
|
-
def self.deserialize_array(message, io, field, options)
|
405
|
+
def self.deserialize_array(message, io, field, options = {})
|
378
406
|
elements = []
|
379
407
|
count = message.instance_variable_get(field[:multi])
|
380
408
|
count.times { elements << field[:type].deserialize(io, options) }
|
@@ -392,7 +420,7 @@ module Mongo
|
|
392
420
|
# this field using BSON types wherever possible.
|
393
421
|
#
|
394
422
|
# @return [Message] Message with deserialized field.
|
395
|
-
def self.deserialize_field(message, io, field, options)
|
423
|
+
def self.deserialize_field(message, io, field, options = {})
|
396
424
|
message.instance_variable_set(
|
397
425
|
field[:name],
|
398
426
|
field[:type].deserialize(io, options)
|
data/lib/mongo/protocol/msg.rb
CHANGED
@@ -60,6 +60,13 @@ module Mongo
|
|
60
60
|
#
|
61
61
|
# @since 2.5.0
|
62
62
|
def initialize(flags, options, main_document, *sequences)
|
63
|
+
if flags
|
64
|
+
flags.each do |flag|
|
65
|
+
unless KNOWN_FLAGS.key?(flag)
|
66
|
+
raise ArgumentError, "Unknown flag: #{flag.inspect}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
63
70
|
@flags = flags || []
|
64
71
|
@options = options
|
65
72
|
unless main_document.is_a?(Hash)
|
@@ -313,10 +320,17 @@ module Mongo
|
|
313
320
|
# @since 2.5.0
|
314
321
|
OP_CODE = 2013
|
315
322
|
|
323
|
+
KNOWN_FLAGS = {
|
324
|
+
checksum_present: true,
|
325
|
+
more_to_come: true,
|
326
|
+
exhaust_allowed: true,
|
327
|
+
}
|
328
|
+
|
316
329
|
# Available flags for a OP_MSG message.
|
317
330
|
FLAGS = Array.new(16).tap do |arr|
|
318
331
|
arr[0] = :checksum_present
|
319
332
|
arr[1] = :more_to_come
|
333
|
+
arr[16] = :exhaust_allowed
|
320
334
|
end.freeze
|
321
335
|
|
322
336
|
# @!attribute
|
@@ -440,12 +440,15 @@ module Mongo
|
|
440
440
|
# Deserializes bytes from the byte buffer.
|
441
441
|
#
|
442
442
|
# @param [ BSON::ByteBuffer ] buffer Buffer containing the value to read.
|
443
|
-
# @param [
|
443
|
+
# @param [ Hash ] options The method options.
|
444
|
+
#
|
445
|
+
# @option options [ Integer ] num_bytes Number of bytes to read.
|
444
446
|
#
|
445
447
|
# @return [ String ] The bytes.
|
446
448
|
#
|
447
449
|
# @since 2.5.0
|
448
|
-
def self.deserialize(buffer,
|
450
|
+
def self.deserialize(buffer, options = {})
|
451
|
+
num_bytes = options[:num_bytes]
|
449
452
|
buffer.get_bytes(num_bytes || buffer.length)
|
450
453
|
end
|
451
454
|
end
|
data/lib/mongo/server.rb
CHANGED
@@ -64,7 +64,7 @@ module Mongo
|
|
64
64
|
@connection_id_gen = Class.new do
|
65
65
|
include Id
|
66
66
|
end
|
67
|
-
@scan_semaphore =
|
67
|
+
@scan_semaphore = DistinguishingSemaphore.new
|
68
68
|
@round_trip_time_averager = RoundTripTimeAverager.new
|
69
69
|
@description = Description.new(address, {})
|
70
70
|
@last_scan = nil
|
@@ -432,7 +432,7 @@ module Mongo
|
|
432
432
|
def handle_handshake_failure!
|
433
433
|
yield
|
434
434
|
rescue Mongo::Error::SocketError, Mongo::Error::SocketTimeoutError => e
|
435
|
-
unknown!(generation: e.generation)
|
435
|
+
unknown!(generation: e.generation, stop_push_monitor: true)
|
436
436
|
raise
|
437
437
|
end
|
438
438
|
|
@@ -455,7 +455,7 @@ module Mongo
|
|
455
455
|
raise
|
456
456
|
rescue Mongo::Error::SocketError => e
|
457
457
|
# non-timeout network error
|
458
|
-
unknown!(generation: e.generation)
|
458
|
+
unknown!(generation: e.generation, stop_push_monitor: true)
|
459
459
|
raise
|
460
460
|
rescue Auth::Unauthorized
|
461
461
|
# auth error, keep server description and topology as they are
|
@@ -503,6 +503,8 @@ module Mongo
|
|
503
503
|
# on 4.2+ servers).
|
504
504
|
# @option options [ TopologyVersion ] :topology_version Topology version
|
505
505
|
# of the error response that is causing the server to be marked unknown.
|
506
|
+
# @option options [ true | false ] :stop_push_monitor Whether to stop
|
507
|
+
# the PushMonitor associated with the server, if any.
|
506
508
|
#
|
507
509
|
# @since 2.4.0, SDAM events are sent as of version 2.7.0
|
508
510
|
def unknown!(options = {})
|
@@ -516,6 +518,10 @@ module Mongo
|
|
516
518
|
return
|
517
519
|
end
|
518
520
|
|
521
|
+
if options[:stop_push_monitor]
|
522
|
+
monitor&.stop_push_monitor!
|
523
|
+
end
|
524
|
+
|
519
525
|
# SDAM flow will update description on the server without in-place
|
520
526
|
# mutations and invoke SDAM transitions as needed.
|
521
527
|
config = {}
|
@@ -562,3 +568,4 @@ require 'mongo/server/context'
|
|
562
568
|
require 'mongo/server/description'
|
563
569
|
require 'mongo/server/monitor'
|
564
570
|
require 'mongo/server/round_trip_time_averager'
|
571
|
+
require 'mongo/server/push_monitor'
|
@@ -163,7 +163,7 @@ module Mongo
|
|
163
163
|
unless @socket
|
164
164
|
# When @socket is assigned, the socket should have handshaken and
|
165
165
|
# authenticated and be usable.
|
166
|
-
@socket, @description = do_connect
|
166
|
+
@socket, @description, @compressor = do_connect
|
167
167
|
|
168
168
|
publish_cmap_event(
|
169
169
|
Monitoring::Event::Cmap::ConnectionReady.new(address, id)
|
@@ -194,7 +194,7 @@ module Mongo
|
|
194
194
|
raise
|
195
195
|
end
|
196
196
|
|
197
|
-
[socket, pending_connection.description]
|
197
|
+
[socket, pending_connection.description, pending_connection.compressor]
|
198
198
|
end
|
199
199
|
|
200
200
|
# Disconnect the connection.
|
@@ -220,7 +220,7 @@ module Mongo
|
|
220
220
|
@auth_mechanism = nil
|
221
221
|
@last_checkin = nil
|
222
222
|
if socket
|
223
|
-
socket.close
|
223
|
+
socket.close rescue nil
|
224
224
|
@socket = nil
|
225
225
|
end
|
226
226
|
@closed = true
|
@@ -306,7 +306,7 @@ module Mongo
|
|
306
306
|
yield
|
307
307
|
rescue Error::SocketError => e
|
308
308
|
@error = e
|
309
|
-
@server.unknown!(generation: e.generation)
|
309
|
+
@server.unknown!(generation: e.generation, stop_push_monitor: true)
|
310
310
|
raise
|
311
311
|
rescue Error::SocketTimeoutError => e
|
312
312
|
@error = e
|
@@ -156,7 +156,9 @@ module Mongo
|
|
156
156
|
operation_id = Monitoring.next_operation_id
|
157
157
|
command_started(address, operation_id, message.payload,
|
158
158
|
socket_object_id: socket.object_id, connection_id: id,
|
159
|
-
connection_generation: generation
|
159
|
+
connection_generation: generation,
|
160
|
+
server_connection_id: description.server_connection_id,
|
161
|
+
)
|
160
162
|
start = Time.now
|
161
163
|
result = nil
|
162
164
|
begin
|
@@ -755,6 +755,11 @@ module Mongo
|
|
755
755
|
# @since 2.7.0
|
756
756
|
attr_reader :last_update_time
|
757
757
|
|
758
|
+
# @api experimental
|
759
|
+
def server_connection_id
|
760
|
+
config['connectionId']
|
761
|
+
end
|
762
|
+
|
758
763
|
# Check equality of two descriptions.
|
759
764
|
#
|
760
765
|
# @example Check description equality.
|
data/lib/mongo/server/monitor.rb
CHANGED
@@ -77,7 +77,9 @@ module Mongo
|
|
77
77
|
@monitoring = monitoring
|
78
78
|
@options = options.freeze
|
79
79
|
@mutex = Mutex.new
|
80
|
+
@sdam_mutex = Mutex.new
|
80
81
|
@next_earliest_scan = @next_wanted_scan = Time.now
|
82
|
+
@update_mutex = Mutex.new
|
81
83
|
end
|
82
84
|
|
83
85
|
# @return [ Server ] server The server that this monitor is monitoring.
|
@@ -109,6 +111,14 @@ module Mongo
|
|
109
111
|
# @return [ Monitoring ] monitoring The monitoring.
|
110
112
|
attr_reader :monitoring
|
111
113
|
|
114
|
+
# @return [ Server::PushMonitor | nil ] The push monitor, if one is being
|
115
|
+
# used.
|
116
|
+
def push_monitor
|
117
|
+
@update_mutex.synchronize do
|
118
|
+
@push_monitor
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
112
122
|
# Runs the server monitor. Refreshing happens on a separate thread per
|
113
123
|
# server.
|
114
124
|
#
|
@@ -120,9 +130,19 @@ module Mongo
|
|
120
130
|
# @since 2.0.0
|
121
131
|
def do_work
|
122
132
|
scan!
|
123
|
-
|
124
|
-
|
125
|
-
|
133
|
+
# @next_wanted_scan may be updated by the push monitor.
|
134
|
+
# However we need to check for termination flag so that the monitor
|
135
|
+
# thread exits when requested.
|
136
|
+
loop do
|
137
|
+
delta = @next_wanted_scan - Time.now
|
138
|
+
if delta > 0
|
139
|
+
signaled = server.scan_semaphore.wait(delta)
|
140
|
+
if signaled || @stop_requested
|
141
|
+
break
|
142
|
+
end
|
143
|
+
else
|
144
|
+
break
|
145
|
+
end
|
126
146
|
end
|
127
147
|
end
|
128
148
|
|
@@ -133,6 +153,8 @@ module Mongo
|
|
133
153
|
#
|
134
154
|
# @api public for backwards compatibility only
|
135
155
|
def stop!
|
156
|
+
stop_push_monitor!
|
157
|
+
|
136
158
|
# Forward super's return value
|
137
159
|
super.tap do
|
138
160
|
# Important: disconnect should happen after the background thread
|
@@ -141,6 +163,15 @@ module Mongo
|
|
141
163
|
end
|
142
164
|
end
|
143
165
|
|
166
|
+
def stop_push_monitor!
|
167
|
+
@update_mutex.synchronize do
|
168
|
+
if @push_monitor
|
169
|
+
@push_monitor.stop!
|
170
|
+
@push_monitor = nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
144
175
|
# Perform a check of the server with throttling, and update
|
145
176
|
# the server's description and average round trip time.
|
146
177
|
#
|
@@ -168,19 +199,27 @@ module Mongo
|
|
168
199
|
|
169
200
|
result = do_scan
|
170
201
|
|
202
|
+
run_sdam_flow(result)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def run_sdam_flow(result, awaited: false)
|
207
|
+
@sdam_mutex.synchronize do
|
171
208
|
old_description = server.description
|
172
209
|
|
173
210
|
new_description = Description.new(server.address, result,
|
174
211
|
server.round_trip_time_averager.average_round_trip_time)
|
175
212
|
|
176
|
-
server.cluster.run_sdam_flow(server.description, new_description)
|
213
|
+
server.cluster.run_sdam_flow(server.description, new_description, awaited: awaited)
|
177
214
|
|
178
215
|
server.description.tap do |new_description|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
216
|
+
unless awaited
|
217
|
+
if new_description.unknown? && !old_description.unknown?
|
218
|
+
@next_earliest_scan = @next_wanted_scan = Time.now
|
219
|
+
else
|
220
|
+
@next_earliest_scan = Time.now + MIN_SCAN_INTERVAL
|
221
|
+
@next_wanted_scan = Time.now + heartbeat_interval
|
222
|
+
end
|
184
223
|
end
|
185
224
|
end
|
186
225
|
end
|
@@ -209,44 +248,19 @@ module Mongo
|
|
209
248
|
end
|
210
249
|
|
211
250
|
def do_scan
|
212
|
-
if monitoring.monitoring?
|
213
|
-
monitoring.started(
|
214
|
-
Monitoring::SERVER_HEARTBEAT,
|
215
|
-
Monitoring::Event::ServerHeartbeatStarted.new(server.address)
|
216
|
-
)
|
217
|
-
end
|
218
|
-
|
219
|
-
# The duration we publish in heartbeat succeeded/failed events is
|
220
|
-
# the time spent on the entire heartbeat. This could include time
|
221
|
-
# to connect the socket (including TLS handshake), not just time
|
222
|
-
# spent on ismaster call itself.
|
223
|
-
# The spec at https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring-monitoring.rst
|
224
|
-
# requires that the duration exposed here start from "sending the
|
225
|
-
# message" (ismaster). This requirement does not make sense if,
|
226
|
-
# for example, we were never able to connect to the server at all
|
227
|
-
# and thus ismaster was never sent.
|
228
|
-
start_time = Time.now
|
229
|
-
|
230
251
|
begin
|
231
|
-
|
232
|
-
|
233
|
-
log_warn("Error running ismaster on #{server.address}: #{exc.class}: #{exc}:\n#{exc.backtrace[0..5].join("\n")}")
|
234
|
-
if monitoring.monitoring?
|
235
|
-
monitoring.failed(
|
236
|
-
Monitoring::SERVER_HEARTBEAT,
|
237
|
-
Monitoring::Event::ServerHeartbeatFailed.new(server.address, Time.now-start_time, exc)
|
238
|
-
)
|
239
|
-
end
|
240
|
-
result = {}
|
241
|
-
else
|
242
|
-
if monitoring.monitoring?
|
243
|
-
monitoring.succeeded(
|
244
|
-
Monitoring::SERVER_HEARTBEAT,
|
245
|
-
Monitoring::Event::ServerHeartbeatSucceeded.new(server.address, Time.now-start_time)
|
246
|
-
)
|
252
|
+
monitoring.publish_heartbeat(server) do
|
253
|
+
ismaster
|
247
254
|
end
|
255
|
+
rescue => exc
|
256
|
+
msg = "Error running ismaster on #{server.address}"
|
257
|
+
Utils.warn_monitor_exception(msg, exc,
|
258
|
+
logger: options[:logger],
|
259
|
+
log_prefix: options[:log_prefix],
|
260
|
+
bg_error_backtrace: options[:bg_error_backtrace],
|
261
|
+
)
|
262
|
+
{}
|
248
263
|
end
|
249
|
-
result
|
250
264
|
end
|
251
265
|
|
252
266
|
def ismaster
|
@@ -274,6 +288,24 @@ module Mongo
|
|
274
288
|
connection.handshake!
|
275
289
|
end
|
276
290
|
@connection = connection
|
291
|
+
if result['topologyVersion']
|
292
|
+
# Successful response, server 4.4+
|
293
|
+
@update_mutex.synchronize do
|
294
|
+
@push_monitor ||= PushMonitor.new(
|
295
|
+
self,
|
296
|
+
TopologyVersion.new(result['topologyVersion']),
|
297
|
+
monitoring,
|
298
|
+
**Utils.shallow_symbolize_keys(options.merge(
|
299
|
+
socket_timeout: heartbeat_interval + connection.socket_timeout,
|
300
|
+
)),
|
301
|
+
)
|
302
|
+
end
|
303
|
+
push_monitor.run!
|
304
|
+
else
|
305
|
+
# Failed response or pre-4.4 server
|
306
|
+
stop_push_monitor!
|
307
|
+
end
|
308
|
+
result
|
277
309
|
end
|
278
310
|
result
|
279
311
|
end
|