mongo 2.13.0.beta1 → 2.13.0.rc1
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 +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
|