mongo 2.24.0 → 2.25.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/result.rb +10 -2
- data/lib/mongo/bulk_write/result_combiner.rb +11 -4
- data/lib/mongo/bulk_write.rb +1 -1
- data/lib/mongo/client.rb +82 -12
- 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 +12 -28
- 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 -4
- data/lib/mongo/collection/view.rb +8 -4
- data/lib/mongo/collection.rb +1 -1
- data/lib/mongo/config.rb +5 -0
- data/lib/mongo/crypt/auto_encrypter.rb +1 -1
- data/lib/mongo/crypt/binary.rb +7 -4
- data/lib/mongo/crypt/binding.rb +88 -10
- data/lib/mongo/crypt/context.rb +50 -19
- data/lib/mongo/crypt/encryption_io.rb +11 -5
- data/lib/mongo/crypt/handle.rb +17 -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/bulk_write_error.rb +29 -1
- data/lib/mongo/error/invalid_server_preference.rb +3 -0
- data/lib/mongo/error/invalid_uri.rb +5 -1
- data/lib/mongo/error/operation_failure.rb +42 -3
- data/lib/mongo/error/parser.rb +3 -3
- data/lib/mongo/error/sdam_error_detection.rb +2 -3
- data/lib/mongo/grid/fs_bucket.rb +27 -21
- data/lib/mongo/grid/stream/write.rb +2 -2
- 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/monitoring/server_description_changed_log_subscriber.rb +2 -0
- data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +3 -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 +14 -26
- data/lib/mongo/operation/shared/causal_consistency_supported.rb +4 -2
- data/lib/mongo/operation/shared/executable.rb +2 -10
- 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 -16
- 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/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 +79 -18
- data/lib/mongo/server/description/features.rb +2 -2
- data/lib/mongo/server/description.rb +24 -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 -0
- data/lib/mongo/server/push_monitor.rb +16 -2
- data/lib/mongo/server.rb +27 -7
- data/lib/mongo/server_selector/base.rb +16 -6
- data/lib/mongo/server_selector/nearest.rb +3 -0
- data/lib/mongo/server_selector/primary.rb +3 -0
- data/lib/mongo/server_selector/primary_preferred.rb +3 -0
- data/lib/mongo/server_selector/secondary.rb +3 -0
- data/lib/mongo/server_selector/secondary_preferred.rb +7 -1
- data/lib/mongo/session.rb +56 -24
- 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 +43 -2
- data/lib/mongo/uri/options_mapper.rb +21 -9
- 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
- data/lib/mongo.rb +1 -0
- 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
|
@@ -37,6 +37,8 @@ module Mongo
|
|
|
37
37
|
# reads on the server. Hedged reads are not enabled by default. When
|
|
38
38
|
# specifying this option, it must be in the format: { enabled: true },
|
|
39
39
|
# where the value of the :enabled key is a boolean value.
|
|
40
|
+
# @deprecated Hedged reads are deprecated in MongoDB Server 8.0 and will
|
|
41
|
+
# be removed in a future version.
|
|
40
42
|
#
|
|
41
43
|
# @raise [ Error::InvalidServerPreference ] If tag sets are specified
|
|
42
44
|
# but not allowed.
|
|
@@ -51,6 +53,14 @@ module Mongo
|
|
|
51
53
|
@hedge = options[:hedge]
|
|
52
54
|
|
|
53
55
|
validate!
|
|
56
|
+
|
|
57
|
+
return if @hedge.nil?
|
|
58
|
+
|
|
59
|
+
Mongo::Deprecations.warn(
|
|
60
|
+
:hedge_read_preference,
|
|
61
|
+
'The hedge read preference option is deprecated. Hedged reads are ' \
|
|
62
|
+
'deprecated in MongoDB Server 8.0 and will be removed in a future version.'
|
|
63
|
+
)
|
|
54
64
|
end
|
|
55
65
|
|
|
56
66
|
# @return [ Hash ] options The options.
|
|
@@ -67,6 +77,9 @@ module Mongo
|
|
|
67
77
|
|
|
68
78
|
# @return [ Hash | nil ] hedge The document specifying whether to enable
|
|
69
79
|
# hedged reads.
|
|
80
|
+
#
|
|
81
|
+
# @deprecated Hedged reads are deprecated in MongoDB Server 8.0 and will
|
|
82
|
+
# be removed in a future version.
|
|
70
83
|
attr_reader :hedge
|
|
71
84
|
|
|
72
85
|
# Get the timeout for server selection.
|
|
@@ -226,7 +239,7 @@ module Mongo
|
|
|
226
239
|
|
|
227
240
|
session.unpin unless session.in_transaction?
|
|
228
241
|
|
|
229
|
-
if server = session.pinned_server
|
|
242
|
+
if (server = session.pinned_server)
|
|
230
243
|
# Here we assume that a mongos stays in the topology indefinitely.
|
|
231
244
|
# This will no longer be the case once SRV polling is implemented.
|
|
232
245
|
|
|
@@ -385,9 +398,7 @@ module Mongo
|
|
|
385
398
|
# @api private
|
|
386
399
|
def candidates(cluster, deprioritized = [])
|
|
387
400
|
servers = cluster.servers.reject { |s| deprioritized.include?(s) }
|
|
388
|
-
if cluster.single?
|
|
389
|
-
servers
|
|
390
|
-
elsif cluster.sharded?
|
|
401
|
+
if cluster.single? || cluster.sharded?
|
|
391
402
|
servers
|
|
392
403
|
elsif cluster.replica_set?
|
|
393
404
|
select_in_replica_set(servers)
|
|
@@ -676,8 +687,7 @@ module Mongo
|
|
|
676
687
|
msg = ''
|
|
677
688
|
dead_monitors = []
|
|
678
689
|
cluster.servers_list.each do |server|
|
|
679
|
-
|
|
680
|
-
dead_monitors << server if thread.nil? || !thread.alive?
|
|
690
|
+
dead_monitors << server unless server.monitor&.running?
|
|
681
691
|
end
|
|
682
692
|
if dead_monitors.any?
|
|
683
693
|
msg += ". The following servers have dead monitor threads: #{dead_monitors.map(&:summary).join(', ')}"
|
|
@@ -59,6 +59,9 @@ module Mongo
|
|
|
59
59
|
# Whether the hedge option is allowed to be defined for this server preference.
|
|
60
60
|
#
|
|
61
61
|
# @return [ true ] true
|
|
62
|
+
#
|
|
63
|
+
# @deprecated Hedged reads are deprecated in MongoDB Server 8.0 and will
|
|
64
|
+
# be removed in a future version.
|
|
62
65
|
def hedge_allowed?
|
|
63
66
|
true
|
|
64
67
|
end
|
|
@@ -59,6 +59,9 @@ module Mongo
|
|
|
59
59
|
# Whether the hedge option is allowed to be defined for this server preference.
|
|
60
60
|
#
|
|
61
61
|
# @return [ false ] false
|
|
62
|
+
#
|
|
63
|
+
# @deprecated Hedged reads are deprecated in MongoDB Server 8.0 and will
|
|
64
|
+
# be removed in a future version.
|
|
62
65
|
def hedge_allowed?
|
|
63
66
|
false
|
|
64
67
|
end
|
|
@@ -59,6 +59,9 @@ module Mongo
|
|
|
59
59
|
# Whether the hedge option is allowed to be defined for this server preference.
|
|
60
60
|
#
|
|
61
61
|
# @return [ true ] true
|
|
62
|
+
#
|
|
63
|
+
# @deprecated Hedged reads are deprecated in MongoDB Server 8.0 and will
|
|
64
|
+
# be removed in a future version.
|
|
62
65
|
def hedge_allowed?
|
|
63
66
|
true
|
|
64
67
|
end
|
|
@@ -59,6 +59,9 @@ module Mongo
|
|
|
59
59
|
# Whether the hedge option is allowed to be defined for this server preference.
|
|
60
60
|
#
|
|
61
61
|
# @return [ true ] true
|
|
62
|
+
#
|
|
63
|
+
# @deprecated Hedged reads are deprecated in MongoDB Server 8.0 and will
|
|
64
|
+
# be removed in a future version.
|
|
62
65
|
def hedge_allowed?
|
|
63
66
|
true
|
|
64
67
|
end
|
|
@@ -59,6 +59,9 @@ module Mongo
|
|
|
59
59
|
# Whether the hedge option is allowed to be defined for this server preference.
|
|
60
60
|
#
|
|
61
61
|
# @return [ true ] true
|
|
62
|
+
#
|
|
63
|
+
# @deprecated Hedged reads are deprecated in MongoDB Server 8.0 and will
|
|
64
|
+
# be removed in a future version.
|
|
62
65
|
def hedge_allowed?
|
|
63
66
|
true
|
|
64
67
|
end
|
|
@@ -98,7 +101,10 @@ module Mongo
|
|
|
98
101
|
#
|
|
99
102
|
# @since 2.0.0
|
|
100
103
|
def select_in_replica_set(candidates)
|
|
101
|
-
|
|
104
|
+
eligible = secondaries(candidates)
|
|
105
|
+
return near_servers(eligible) unless eligible.empty?
|
|
106
|
+
|
|
107
|
+
primary(candidates)
|
|
102
108
|
end
|
|
103
109
|
|
|
104
110
|
def max_staleness_allowed?
|
data/lib/mongo/session.rb
CHANGED
|
@@ -74,6 +74,8 @@ module Mongo
|
|
|
74
74
|
# and *:nearest*.
|
|
75
75
|
# @option options [ true | false ] :snapshot Set up the session for
|
|
76
76
|
# snapshot reads.
|
|
77
|
+
# @option options [ BSON::Timestamp ] :snapshot_time The desired snapshot
|
|
78
|
+
# time for snapshot reads. Only valid when :snapshot is true.
|
|
77
79
|
#
|
|
78
80
|
# @since 2.5.0
|
|
79
81
|
# @api private
|
|
@@ -82,6 +84,14 @@ module Mongo
|
|
|
82
84
|
raise ArgumentError, ':causal_consistency and :snapshot options cannot be both set on a session'
|
|
83
85
|
end
|
|
84
86
|
|
|
87
|
+
if options[:snapshot_time] && !options[:snapshot]
|
|
88
|
+
raise ArgumentError, ':snapshot_time can only be set when :snapshot is true'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
if options[:snapshot_time] && !options[:snapshot_time].is_a?(BSON::Timestamp)
|
|
92
|
+
raise ArgumentError, ':snapshot_time must be a BSON::Timestamp'
|
|
93
|
+
end
|
|
94
|
+
|
|
85
95
|
if options[:implicit]
|
|
86
96
|
unless server_session.nil?
|
|
87
97
|
raise ArgumentError, 'Implicit session cannot reference server session during construction'
|
|
@@ -104,6 +114,7 @@ module Mongo
|
|
|
104
114
|
@with_transaction_deadline = nil
|
|
105
115
|
@with_transaction_timeout_ms = nil
|
|
106
116
|
@inside_with_transaction = false
|
|
117
|
+
@snapshot_timestamp = options[:snapshot_time]
|
|
107
118
|
end
|
|
108
119
|
|
|
109
120
|
# @return [ Hash ] The options for this session.
|
|
@@ -448,13 +459,9 @@ module Mongo
|
|
|
448
459
|
@inside_with_transaction = true
|
|
449
460
|
@with_transaction_timeout_ms = options&.dig(:timeout_ms) || @options[:default_timeout_ms] || @client.timeout_ms
|
|
450
461
|
@with_transaction_deadline = calculate_with_transaction_deadline(options)
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
else
|
|
455
|
-
# CSOT not enabled, so we use the default deadline, 120 seconds.
|
|
456
|
-
Utils.monotonic_time + 120
|
|
457
|
-
end
|
|
462
|
+
# When CSOT is enabled we have a customer defined deadline; otherwise
|
|
463
|
+
# fall back to the default deadline, 120 seconds.
|
|
464
|
+
deadline = @with_transaction_deadline || (Utils.monotonic_time + 120)
|
|
458
465
|
transaction_in_progress = false
|
|
459
466
|
transaction_attempt = 0
|
|
460
467
|
last_error = nil
|
|
@@ -936,6 +943,13 @@ module Mongo
|
|
|
936
943
|
#
|
|
937
944
|
# @api private
|
|
938
945
|
def unpin(connection = nil)
|
|
946
|
+
# Idempotent: if there is no pinned state to clear, do nothing. Nested
|
|
947
|
+
# unpin_maybe handlers (e.g. in BulkWrite#execute_operation wrapping an
|
|
948
|
+
# OpMsg execution that already calls unpin_maybe in its own do_execute)
|
|
949
|
+
# can call this method twice for the same error; checking the connection
|
|
950
|
+
# back into the pool a second time would raise from the pool.
|
|
951
|
+
return if @pinned_server.nil? && @pinned_connection.nil? && @pinned_connection_global_id.nil?
|
|
952
|
+
|
|
939
953
|
@pinned_server = nil
|
|
940
954
|
@pinned_connection_global_id = nil
|
|
941
955
|
conn = connection || @pinned_connection
|
|
@@ -1036,7 +1050,7 @@ module Mongo
|
|
|
1036
1050
|
# even if transaction's read concern is not set.
|
|
1037
1051
|
# Read concern here is the one sent to the server and may
|
|
1038
1052
|
# include afterClusterTime.
|
|
1039
|
-
if rc = c[:readConcern]
|
|
1053
|
+
if (rc = c[:readConcern])
|
|
1040
1054
|
rc = rc.dup
|
|
1041
1055
|
rc.delete(:level)
|
|
1042
1056
|
end
|
|
@@ -1183,7 +1197,7 @@ module Mongo
|
|
|
1183
1197
|
def process(result)
|
|
1184
1198
|
unless implicit?
|
|
1185
1199
|
set_operation_time(result)
|
|
1186
|
-
if cluster_time_doc = result.cluster_time
|
|
1200
|
+
if (cluster_time_doc = result.cluster_time)
|
|
1187
1201
|
advance_cluster_time(cluster_time_doc)
|
|
1188
1202
|
end
|
|
1189
1203
|
end
|
|
@@ -1266,8 +1280,23 @@ module Mongo
|
|
|
1266
1280
|
@server_session.txn_num
|
|
1267
1281
|
end
|
|
1268
1282
|
|
|
1283
|
+
# @return [ BSON::Timestamp | nil ] The snapshot time for this session.
|
|
1284
|
+
# nil if the session is not a snapshot session, or if it is a snapshot
|
|
1285
|
+
# session for which no :snapshot_time option was provided and no read
|
|
1286
|
+
# has yet captured atClusterTime from the server.
|
|
1287
|
+
attr_reader :snapshot_timestamp
|
|
1288
|
+
|
|
1289
|
+
# Sets the snapshot time for the session. Once set, subsequent
|
|
1290
|
+
# assignments are ignored: snapshotTime is established at most once per
|
|
1291
|
+
# session, either from the :snapshot_time option at construction or from
|
|
1292
|
+
# the atClusterTime returned by the first find/aggregate/distinct
|
|
1293
|
+
# response. This keeps the property effectively read-only for callers,
|
|
1294
|
+
# per the snapshot-sessions spec rationale.
|
|
1295
|
+
#
|
|
1269
1296
|
# @api private
|
|
1270
|
-
|
|
1297
|
+
def snapshot_timestamp=(value)
|
|
1298
|
+
@snapshot_timestamp ||= value
|
|
1299
|
+
end
|
|
1271
1300
|
|
|
1272
1301
|
# @return [ Integer | nil ] The deadline for the current transaction, if any.
|
|
1273
1302
|
# @api private
|
|
@@ -1279,8 +1308,6 @@ module Mongo
|
|
|
1279
1308
|
@inside_with_transaction
|
|
1280
1309
|
end
|
|
1281
1310
|
|
|
1282
|
-
private
|
|
1283
|
-
|
|
1284
1311
|
# Get the read concern the session will use when starting a transaction.
|
|
1285
1312
|
#
|
|
1286
1313
|
# This is a driver style hash with underscore keys.
|
|
@@ -1291,11 +1318,24 @@ module Mongo
|
|
|
1291
1318
|
# @return [ Hash ] The read concern used for starting transactions.
|
|
1292
1319
|
#
|
|
1293
1320
|
# @since 2.9.0
|
|
1321
|
+
# @api private
|
|
1294
1322
|
def txn_read_concern
|
|
1295
1323
|
# Read concern is inherited from client but not db or collection.
|
|
1296
1324
|
txn_options[:read_concern] || @client.read_concern
|
|
1297
1325
|
end
|
|
1298
1326
|
|
|
1327
|
+
# Returns causal consistency document if the last operation time is
|
|
1328
|
+
# known and causal consistency is enabled, otherwise returns nil.
|
|
1329
|
+
#
|
|
1330
|
+
# @api private
|
|
1331
|
+
def causal_consistency_doc
|
|
1332
|
+
return unless operation_time && causal_consistency?
|
|
1333
|
+
|
|
1334
|
+
{ afterClusterTime: operation_time }
|
|
1335
|
+
end
|
|
1336
|
+
|
|
1337
|
+
private
|
|
1338
|
+
|
|
1299
1339
|
def within_states?(*states)
|
|
1300
1340
|
states.include?(@state)
|
|
1301
1341
|
end
|
|
@@ -1313,14 +1353,6 @@ module Mongo
|
|
|
1313
1353
|
(@client.write_concern && @client.write_concern.options)
|
|
1314
1354
|
end
|
|
1315
1355
|
|
|
1316
|
-
# Returns causal consistency document if the last operation time is
|
|
1317
|
-
# known and causal consistency is enabled, otherwise returns nil.
|
|
1318
|
-
def causal_consistency_doc
|
|
1319
|
-
return unless operation_time && causal_consistency?
|
|
1320
|
-
|
|
1321
|
-
{ afterClusterTime: operation_time }
|
|
1322
|
-
end
|
|
1323
|
-
|
|
1324
1356
|
def causal_consistency?
|
|
1325
1357
|
@causal_consistency ||= if @options.key?(:causal_consistency)
|
|
1326
1358
|
!!@options[:causal_consistency]
|
|
@@ -1358,9 +1390,9 @@ module Mongo
|
|
|
1358
1390
|
raise Mongo::Error::InvalidTransactionOperation,
|
|
1359
1391
|
'timeoutMS cannot be overridden inside a withTransaction callback'
|
|
1360
1392
|
end
|
|
1361
|
-
elsif timeout_ms = opts[:timeout_ms]
|
|
1393
|
+
elsif (timeout_ms = opts[:timeout_ms])
|
|
1362
1394
|
result[:operation_timeout_ms] = timeout_ms
|
|
1363
|
-
elsif default_timeout_ms = options[:default_timeout_ms]
|
|
1395
|
+
elsif (default_timeout_ms = options[:default_timeout_ms])
|
|
1364
1396
|
result[:operation_timeout_ms] = default_timeout_ms
|
|
1365
1397
|
end
|
|
1366
1398
|
end
|
|
@@ -1374,9 +1406,9 @@ module Mongo
|
|
|
1374
1406
|
Utils.monotonic_time + (timeout / 1000.0)
|
|
1375
1407
|
end
|
|
1376
1408
|
}
|
|
1377
|
-
if timeout_ms = opts&.dig(:timeout_ms)
|
|
1409
|
+
if (timeout_ms = opts&.dig(:timeout_ms))
|
|
1378
1410
|
calc.call(timeout_ms)
|
|
1379
|
-
elsif default_timeout_ms = @options[:default_timeout_ms]
|
|
1411
|
+
elsif (default_timeout_ms = @options[:default_timeout_ms])
|
|
1380
1412
|
calc.call(default_timeout_ms)
|
|
1381
1413
|
elsif @client.timeout_ms
|
|
1382
1414
|
calc.call(@client.timeout_ms)
|
data/lib/mongo/socket/ssl.rb
CHANGED
|
@@ -359,7 +359,7 @@ module Mongo
|
|
|
359
359
|
if options[:ssl_cert]
|
|
360
360
|
cert_text = File.read(options[:ssl_cert])
|
|
361
361
|
cert_object = nil
|
|
362
|
-
elsif cert_text = options[:ssl_cert_string]
|
|
362
|
+
elsif (cert_text = options[:ssl_cert_string])
|
|
363
363
|
cert_object = nil
|
|
364
364
|
else
|
|
365
365
|
cert_object = options[:ssl_cert_object]
|
|
@@ -421,13 +421,13 @@ module Mongo
|
|
|
421
421
|
# https://github.com/jruby/jruby-openssl/issues/176
|
|
422
422
|
if BSON::Environment.jruby?
|
|
423
423
|
[ OpenSSL::PKey::RSA, OpenSSL::PKey::DSA ].each do |cls|
|
|
424
|
-
return cls.
|
|
424
|
+
return cls.new(*args)
|
|
425
425
|
rescue OpenSSL::PKey::PKeyError
|
|
426
426
|
# ignore
|
|
427
427
|
end
|
|
428
428
|
# Neither RSA nor DSA worked, fall through to trying PKey
|
|
429
429
|
end
|
|
430
|
-
OpenSSL::PKey.
|
|
430
|
+
OpenSSL::PKey.read(*args)
|
|
431
431
|
end
|
|
432
432
|
|
|
433
433
|
def set_cert_verification(context, options)
|
data/lib/mongo/socket.rb
CHANGED
|
@@ -547,10 +547,6 @@ module Mongo
|
|
|
547
547
|
!rv.nil?
|
|
548
548
|
end
|
|
549
549
|
|
|
550
|
-
def unix_socket?(sock)
|
|
551
|
-
defined?(UNIXSocket) && sock.is_a?(UNIXSocket)
|
|
552
|
-
end
|
|
553
|
-
|
|
554
550
|
DEFAULT_TCP_KEEPINTVL = 10
|
|
555
551
|
|
|
556
552
|
DEFAULT_TCP_KEEPCNT = 9
|
|
@@ -590,9 +586,7 @@ module Mongo
|
|
|
590
586
|
yield
|
|
591
587
|
rescue Errno::ETIMEDOUT => e
|
|
592
588
|
raise Error::SocketTimeoutError, "#{e.class}: #{e} (for #{human_address})"
|
|
593
|
-
rescue IOError, SystemCallError, ::SocketError => e
|
|
594
|
-
raise Error::SocketError, "#{e.class}: #{e} (for #{human_address})"
|
|
595
|
-
rescue OpenSSL::SSL::SSLError => e
|
|
589
|
+
rescue IOError, SystemCallError, ::SocketError, OpenSSL::SSL::SSLError => e
|
|
596
590
|
raise Error::SocketError, "#{e.class}: #{e} (for #{human_address})"
|
|
597
591
|
end
|
|
598
592
|
|
data/lib/mongo/srv/monitor.rb
CHANGED
|
@@ -42,10 +42,13 @@ module Mongo
|
|
|
42
42
|
# Options to pass through to Resolv::DNS constructor for SRV lookups.
|
|
43
43
|
def initialize(cluster, **opts)
|
|
44
44
|
@cluster = cluster
|
|
45
|
-
raise ArgumentError, 'SRV URI is required' unless @srv_uri = opts.delete(:srv_uri)
|
|
45
|
+
raise ArgumentError, 'SRV URI is required' unless (@srv_uri = opts.delete(:srv_uri))
|
|
46
46
|
|
|
47
47
|
@options = opts.freeze
|
|
48
|
-
|
|
48
|
+
# Per the polling-srv-records spec, mismatched-domain records and empty
|
|
49
|
+
# results MUST be logged and ignored, not raised. Force the polling
|
|
50
|
+
# resolver into log-and-continue mode regardless of caller options.
|
|
51
|
+
@resolver = Srv::Resolver.new(**opts, raise_on_invalid: false)
|
|
49
52
|
@last_result = @srv_uri.srv_result
|
|
50
53
|
@stop_semaphore = Semaphore.new
|
|
51
54
|
end
|
|
@@ -82,6 +85,12 @@ module Mongo
|
|
|
82
85
|
rescue Resolv::ResolvError => e
|
|
83
86
|
log_warn("SRV monitor: unable to resolve hostname #{@srv_uri.query_hostname}: #{e.class}: #{e}")
|
|
84
87
|
return
|
|
88
|
+
rescue Mongo::Error => e
|
|
89
|
+
# Defense in depth: the polling resolver is configured to log-and-continue
|
|
90
|
+
# for mismatched-domain and empty-result cases, but if any Mongo::Error
|
|
91
|
+
# leaks out we MUST NOT let it terminate the SRV monitor thread.
|
|
92
|
+
log_warn("SRV monitor: error resolving hostname #{@srv_uri.query_hostname}: #{e.class}: #{e}")
|
|
93
|
+
return
|
|
85
94
|
end
|
|
86
95
|
|
|
87
96
|
if last_result.empty?
|
data/lib/mongo/srv/resolver.rb
CHANGED
data/lib/mongo/srv/result.rb
CHANGED
|
@@ -123,9 +123,11 @@ module Mongo
|
|
|
123
123
|
raise Error::MismatchedDomain.new(format(MISMATCHED_DOMAINNAME, record_host, srv_host_domain))
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
record_matches_domain = (record_host_parts.size > srv_host_domain.size) &&
|
|
127
|
+
(srv_host_domain == record_host_parts[-srv_host_domain.size..-1])
|
|
128
|
+
return if record_matches_domain
|
|
129
|
+
|
|
130
|
+
raise Error::MismatchedDomain.new(format(MISMATCHED_DOMAINNAME, record_host, srv_host_domain))
|
|
129
131
|
end
|
|
130
132
|
end
|
|
131
133
|
end
|
data/lib/mongo/timeout.rb
CHANGED
|
@@ -18,8 +18,7 @@ module Mongo
|
|
|
18
18
|
# @api private
|
|
19
19
|
module Timeout
|
|
20
20
|
# A wrapper around Ruby core's Timeout::timeout method that provides
|
|
21
|
-
# a standardized API for
|
|
22
|
-
# which is when the third argument was introduced.
|
|
21
|
+
# a standardized API for calling it.
|
|
23
22
|
#
|
|
24
23
|
# @param [ Numeric ] sec The number of seconds before timeout.
|
|
25
24
|
# @param [ Class ] klass The exception class to raise on timeout, optional.
|
|
@@ -28,19 +27,15 @@ module Mongo
|
|
|
28
27
|
# on timeout, optional. When no error message is provided, the default
|
|
29
28
|
# error message for the exception class is used.
|
|
30
29
|
def timeout(sec, klass = nil, message = nil, &block)
|
|
31
|
-
if message
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# Timeout::timeout method.
|
|
41
|
-
optional_args = [ klass, message ].compact
|
|
42
|
-
::Timeout.timeout(sec, *optional_args, &block)
|
|
43
|
-
end
|
|
30
|
+
# provide a default error class if the message is present; otherwise,
|
|
31
|
+
# the message will be interpreted as the error class, if klass is nil
|
|
32
|
+
klass ||= ::Timeout::Error if message
|
|
33
|
+
|
|
34
|
+
# Jruby Timeout::timeout method does not support passing nil arguments.
|
|
35
|
+
# Remove the nil arguments before passing them along to the core
|
|
36
|
+
# Timeout::timeout method.
|
|
37
|
+
optional_args = [ klass, message ].compact
|
|
38
|
+
::Timeout.timeout(sec, *optional_args, &block)
|
|
44
39
|
end
|
|
45
40
|
module_function :timeout
|
|
46
41
|
end
|
|
@@ -21,6 +21,15 @@ module Mongo
|
|
|
21
21
|
#
|
|
22
22
|
# @api private
|
|
23
23
|
class CommandTracer
|
|
24
|
+
include Mongo::Monitoring::Event::Secure
|
|
25
|
+
|
|
26
|
+
# Commands for which a span MUST NOT be created. The OpenTelemetry spec
|
|
27
|
+
# requires drivers to skip command spans for sensitive commands listed in
|
|
28
|
+
# the Command Logging and Monitoring spec. We additionally skip hello /
|
|
29
|
+
# legacy hello in all forms — these are handshake/heartbeat traffic and
|
|
30
|
+
# would only add noise to traces.
|
|
31
|
+
HELLO_COMMANDS = %w[hello ismaster isMaster].freeze
|
|
32
|
+
|
|
24
33
|
# Initializes a new CommandTracer.
|
|
25
34
|
#
|
|
26
35
|
# @param otel_tracer [ OpenTelemetry::Trace::Tracer ] the OpenTelemetry tracer.
|
|
@@ -57,6 +66,8 @@ module Mongo
|
|
|
57
66
|
# @return [ Object ] the result of the command.
|
|
58
67
|
# rubocop:disable Lint/RescueException
|
|
59
68
|
def trace_command(message, _operation_context, connection)
|
|
69
|
+
return yield if skip_tracing?(message)
|
|
70
|
+
|
|
60
71
|
# Commands should always be nested under their operation span, not directly under
|
|
61
72
|
# the transaction span. Don't pass with_parent to use automatic parent resolution
|
|
62
73
|
# from the currently active span (the operation span).
|
|
@@ -76,6 +87,22 @@ module Mongo
|
|
|
76
87
|
|
|
77
88
|
private
|
|
78
89
|
|
|
90
|
+
# Determines whether the command must not be traced. Sensitive auth
|
|
91
|
+
# commands carry credentials in their payloads (SCRAM proofs, cleartext
|
|
92
|
+
# passwords, etc.) and the OpenTelemetry spec requires drivers to skip
|
|
93
|
+
# command spans for them. Hello / legacy hello are also skipped to keep
|
|
94
|
+
# handshake traffic out of traces.
|
|
95
|
+
#
|
|
96
|
+
# @param message [ Mongo::Protocol::Message ] the command message.
|
|
97
|
+
#
|
|
98
|
+
# @return [ Boolean ] true when no command span should be created.
|
|
99
|
+
def skip_tracing?(message)
|
|
100
|
+
name = command_name(message)
|
|
101
|
+
return true if HELLO_COMMANDS.include?(name)
|
|
102
|
+
|
|
103
|
+
sensitive?(command_name: name, document: message.documents.first)
|
|
104
|
+
end
|
|
105
|
+
|
|
79
106
|
# Creates a span for a command.
|
|
80
107
|
#
|
|
81
108
|
# @param message [ Mongo::Protocol::Message ] the command message.
|
|
@@ -179,9 +206,23 @@ module Mongo
|
|
|
179
206
|
# @param _context [ OpenTelemetry::Context ] the context (unused).
|
|
180
207
|
# @param span [ OpenTelemetry::Trace::Span ] the current span.
|
|
181
208
|
def process_cursor_context(result, _cursor_id, _context, span)
|
|
182
|
-
|
|
209
|
+
cursor_id = normalize_cursor_id(result.cursor_id)
|
|
210
|
+
return unless cursor_id.positive?
|
|
211
|
+
|
|
212
|
+
span.set_attribute('db.mongodb.cursor_id', cursor_id)
|
|
213
|
+
end
|
|
183
214
|
|
|
184
|
-
|
|
215
|
+
# Normalizes a cursor id to a plain Integer.
|
|
216
|
+
#
|
|
217
|
+
# OP_MSG replies deserialized in :bson mode expose the cursor id as a
|
|
218
|
+
# BSON::Int64, which does not implement Numeric#positive? and is not a
|
|
219
|
+
# valid OpenTelemetry attribute type.
|
|
220
|
+
#
|
|
221
|
+
# @param cursor_id [ Integer | BSON::Int64 ] the raw cursor id.
|
|
222
|
+
#
|
|
223
|
+
# @return [ Integer ] the cursor id as an Integer.
|
|
224
|
+
def normalize_cursor_id(cursor_id)
|
|
225
|
+
cursor_id.is_a?(BSON::Int64) ? cursor_id.value : cursor_id
|
|
185
226
|
end
|
|
186
227
|
|
|
187
228
|
# Records error status code if the command failed.
|
|
@@ -87,7 +87,7 @@ module Mongo
|
|
|
87
87
|
strategy = URI_OPTION_MAP[key.downcase]
|
|
88
88
|
if strategy.nil?
|
|
89
89
|
log_warn("Unsupported URI option '#{key}' on URI '#{@string}'. It will be ignored.")
|
|
90
|
-
|
|
90
|
+
next
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
group = strategy[:group]
|
|
@@ -125,7 +125,7 @@ module Mongo
|
|
|
125
125
|
end
|
|
126
126
|
next if v.nil?
|
|
127
127
|
|
|
128
|
-
if type = spec[:type]
|
|
128
|
+
if (type = spec[:type])
|
|
129
129
|
v = send("revert_#{type}", v)
|
|
130
130
|
end
|
|
131
131
|
canonical_key = URI_OPTION_CANONICAL_NAMES[uri_key]
|
|
@@ -163,7 +163,7 @@ module Mongo
|
|
|
163
163
|
end
|
|
164
164
|
next if v.nil?
|
|
165
165
|
|
|
166
|
-
if type = spec[:type]
|
|
166
|
+
if (type = spec[:type])
|
|
167
167
|
v = send("stringify_#{type}", v)
|
|
168
168
|
end
|
|
169
169
|
canonical_key = URI_OPTION_CANONICAL_NAMES[uri_key]
|
|
@@ -354,13 +354,25 @@ module Mongo
|
|
|
354
354
|
|
|
355
355
|
# Converts the value into a boolean and returns it wrapped in an array.
|
|
356
356
|
#
|
|
357
|
-
#
|
|
357
|
+
# tls and ssl are the only repeated_bool options. An invalid value is
|
|
358
|
+
# preserved as a nil element rather than warned-and-dropped, so that
|
|
359
|
+
# URI#validate_uri_options! can detect it and raise instead of silently
|
|
360
|
+
# falling back to a plaintext connection (RUBY-3832).
|
|
361
|
+
#
|
|
362
|
+
# @param [ String ] _name Name of the URI option being processed.
|
|
358
363
|
# @param [ String ] value URI option value.
|
|
359
364
|
#
|
|
360
|
-
# @return [ Array<true | false
|
|
361
|
-
# in an array.
|
|
362
|
-
def convert_repeated_bool(
|
|
363
|
-
|
|
365
|
+
# @return [ Array<true | false | nil> ] The boolean value parsed and
|
|
366
|
+
# wrapped in an array.
|
|
367
|
+
def convert_repeated_bool(_name, value)
|
|
368
|
+
case value
|
|
369
|
+
when true, 'true', 'TRUE'
|
|
370
|
+
[ true ]
|
|
371
|
+
when false, 'false', 'FALSE'
|
|
372
|
+
[ false ]
|
|
373
|
+
else
|
|
374
|
+
[ nil ]
|
|
375
|
+
end
|
|
364
376
|
end
|
|
365
377
|
|
|
366
378
|
# Reverts a repeated boolean type.
|
|
@@ -379,7 +391,7 @@ module Mongo
|
|
|
379
391
|
# @return [ Array<true | false> | nil ] The string.
|
|
380
392
|
def stringify_repeated_bool(value)
|
|
381
393
|
rep = revert_repeated_bool(value)
|
|
382
|
-
if rep
|
|
394
|
+
if rep.is_a?(Array)
|
|
383
395
|
rep.join(',')
|
|
384
396
|
else
|
|
385
397
|
rep
|
|
@@ -117,14 +117,14 @@ module Mongo
|
|
|
117
117
|
raise Error::InvalidURI.new(@string, details, FORMAT)
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
# Gets the SRV resolver.
|
|
121
|
-
#
|
|
122
|
-
#
|
|
120
|
+
# Gets the SRV resolver used for initial URI parsing.
|
|
121
|
+
# Per the Initial DNS Seedlist Discovery spec, the driver MUST raise an
|
|
122
|
+
# error if domain verification fails or no SRV records are found, so
|
|
123
|
+
# raise_on_invalid is left at its default of true.
|
|
123
124
|
#
|
|
124
125
|
# @return [ Mongo::Srv::Resolver ]
|
|
125
126
|
def resolver
|
|
126
127
|
@resolver ||= Srv::Resolver.new(
|
|
127
|
-
raise_on_invalid: false,
|
|
128
128
|
resolv_options: options[:resolv_options],
|
|
129
129
|
timeout: options[:connect_timeout]
|
|
130
130
|
)
|