mongo 2.24.1 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/mongo_console +2 -2
- data/lib/mongo/address/validator.rb +1 -1
- data/lib/mongo/address.rb +1 -3
- data/lib/mongo/auth/aws/conversation.rb +0 -4
- data/lib/mongo/auth/aws/credentials_retriever.rb +3 -8
- data/lib/mongo/auth/base.rb +1 -1
- data/lib/mongo/auth/sasl_conversation_base.rb +1 -1
- data/lib/mongo/auth/scram_conversation_base.rb +1 -8
- data/lib/mongo/auth/stringprep.rb +1 -6
- data/lib/mongo/auth/user/view.rb +1 -1
- data/lib/mongo/bulk_write/combineable.rb +0 -7
- data/lib/mongo/bulk_write/result_combiner.rb +3 -3
- data/lib/mongo/bulk_write/validatable.rb +0 -4
- data/lib/mongo/bulk_write.rb +1 -35
- data/lib/mongo/client.rb +117 -17
- data/lib/mongo/client_encryption.rb +36 -11
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +12 -5
- data/lib/mongo/cluster/sdam_flow.rb +4 -4
- data/lib/mongo/cluster/topology/base.rb +1 -1
- data/lib/mongo/cluster.rb +13 -30
- data/lib/mongo/collection/queryable_encryption.rb +7 -6
- data/lib/mongo/collection/view/aggregation/behavior.rb +1 -1
- data/lib/mongo/collection/view/aggregation.rb +2 -4
- data/lib/mongo/collection/view/builder/aggregation.rb +3 -5
- data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +14 -9
- data/lib/mongo/collection/view/map_reduce.rb +2 -11
- data/lib/mongo/collection/view/readable.rb +11 -7
- data/lib/mongo/collection/view/writable.rb +4 -39
- data/lib/mongo/collection/view.rb +8 -4
- data/lib/mongo/collection.rb +1 -1
- data/lib/mongo/crypt/auto_encrypter.rb +6 -2
- data/lib/mongo/crypt/binary.rb +7 -4
- data/lib/mongo/crypt/binding.rb +154 -11
- data/lib/mongo/crypt/context.rb +50 -19
- data/lib/mongo/crypt/encryption_io.rb +11 -5
- data/lib/mongo/crypt/explicit_encrypter.rb +27 -12
- data/lib/mongo/crypt/explicit_encryption_context.rb +51 -12
- data/lib/mongo/crypt/handle.rb +35 -5
- data/lib/mongo/crypt/kms/credentials.rb +70 -31
- data/lib/mongo/crypt/kms/kmip/master_document.rb +30 -1
- data/lib/mongo/crypt/kms/master_key_document.rb +11 -6
- data/lib/mongo/crypt/kms.rb +12 -1
- data/lib/mongo/cursor.rb +8 -2
- data/lib/mongo/database/cursor_command_view.rb +95 -0
- data/lib/mongo/database.rb +144 -18
- data/lib/mongo/error/invalid_uri.rb +5 -1
- data/lib/mongo/error/operation_failure.rb +2 -2
- data/lib/mongo/error/parser.rb +3 -3
- data/lib/mongo/error/sdam_error_detection.rb +2 -3
- data/lib/mongo/error/unsupported_option.rb +0 -40
- data/lib/mongo/grid/fs_bucket.rb +29 -23
- data/lib/mongo/grid/stream/read.rb +2 -2
- data/lib/mongo/grid/stream/write.rb +3 -3
- data/lib/mongo/index/view.rb +13 -7
- data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_closed.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_created.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_ready.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/pool_closed.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/pool_created.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/pool_ready.rb +1 -0
- data/lib/mongo/monitoring/event/command_failed.rb +1 -0
- data/lib/mongo/monitoring/event/command_started.rb +1 -0
- data/lib/mongo/monitoring/event/command_succeeded.rb +1 -0
- data/lib/mongo/monitoring/event/secure.rb +12 -17
- data/lib/mongo/monitoring/event/server_closed.rb +1 -0
- data/lib/mongo/monitoring/event/server_description_changed.rb +1 -0
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +1 -0
- data/lib/mongo/monitoring/event/server_heartbeat_started.rb +1 -0
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +1 -0
- data/lib/mongo/monitoring/event/server_opening.rb +1 -0
- data/lib/mongo/monitoring/event/topology_changed.rb +1 -0
- data/lib/mongo/monitoring/event/topology_closed.rb +1 -0
- data/lib/mongo/monitoring/event/topology_opening.rb +1 -0
- data/lib/mongo/operation/create/op_msg.rb +1 -0
- data/lib/mongo/operation/create_index/op_msg.rb +2 -1
- data/lib/mongo/operation/cursor_command/op_msg.rb +37 -0
- data/lib/mongo/operation/cursor_command/result.rb +60 -0
- data/lib/mongo/operation/cursor_command.rb +33 -0
- data/lib/mongo/operation/delete/op_msg.rb +1 -0
- data/lib/mongo/operation/drop/op_msg.rb +1 -0
- data/lib/mongo/operation/drop_database/op_msg.rb +1 -0
- data/lib/mongo/operation/drop_index/op_msg.rb +1 -0
- data/lib/mongo/operation/find/builder/command.rb +1 -1
- data/lib/mongo/operation/insert/bulk_result.rb +2 -4
- data/lib/mongo/operation/insert/op_msg.rb +1 -0
- data/lib/mongo/operation/result.rb +21 -25
- data/lib/mongo/operation/shared/causal_consistency_supported.rb +4 -2
- data/lib/mongo/operation/shared/executable.rb +2 -15
- data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
- data/lib/mongo/operation/shared/sessions_supported.rb +3 -5
- data/lib/mongo/operation/update/bulk_result.rb +1 -1
- data/lib/mongo/operation/update/op_msg.rb +1 -0
- data/lib/mongo/operation/write_command/op_msg.rb +2 -0
- data/lib/mongo/operation.rb +1 -0
- data/lib/mongo/options/redacted.rb +2 -2
- data/lib/mongo/protocol/compressed.rb +15 -11
- data/lib/mongo/protocol/message.rb +16 -20
- data/lib/mongo/protocol/msg.rb +1 -12
- data/lib/mongo/protocol/registry.rb +1 -1
- data/lib/mongo/protocol/serializers.rb +1 -3
- data/lib/mongo/query_cache.rb +3 -5
- data/lib/mongo/retryable/backpressure.rb +17 -2
- data/lib/mongo/retryable/read_worker.rb +1 -1
- data/lib/mongo/retryable/retry_policy.rb +2 -2
- data/lib/mongo/retryable/write_worker.rb +2 -2
- data/lib/mongo/retryable.rb +1 -1
- data/lib/mongo/server/app_metadata.rb +1 -1
- data/lib/mongo/server/connection.rb +3 -1
- data/lib/mongo/server/connection_common.rb +9 -1
- data/lib/mongo/server/connection_pool/generation_manager.rb +1 -1
- data/lib/mongo/server/connection_pool.rb +24 -10
- data/lib/mongo/server/description/features.rb +1 -2
- data/lib/mongo/server/description.rb +1 -2
- data/lib/mongo/server/monitor/connection.rb +3 -2
- data/lib/mongo/server/monitor.rb +133 -30
- data/lib/mongo/server/pending_connection.rb +1 -5
- data/lib/mongo/server/push_monitor.rb +16 -2
- data/lib/mongo/server.rb +28 -9
- data/lib/mongo/server_selector/base.rb +3 -6
- data/lib/mongo/server_selector/secondary_preferred.rb +4 -1
- data/lib/mongo/session.rb +25 -26
- data/lib/mongo/socket/ssl.rb +3 -3
- data/lib/mongo/socket.rb +1 -7
- data/lib/mongo/srv/monitor.rb +11 -2
- data/lib/mongo/srv/resolver.rb +1 -1
- data/lib/mongo/srv/result.rb +5 -3
- data/lib/mongo/timeout.rb +10 -15
- data/lib/mongo/tracing/open_telemetry/command_tracer.rb +16 -2
- data/lib/mongo/uri/options_mapper.rb +36 -13
- data/lib/mongo/uri/srv_protocol.rb +4 -4
- data/lib/mongo/uri.rb +56 -8
- data/lib/mongo/utils.rb +1 -1
- data/lib/mongo/version.rb +1 -1
- metadata +6 -4
- data/lib/mongo/auth/stringprep/unicode_normalize/normalize.rb +0 -173
- data/lib/mongo/auth/stringprep/unicode_normalize/tables.rb +0 -1164
|
@@ -47,11 +47,9 @@ module Mongo
|
|
|
47
47
|
# @since 2.0.0
|
|
48
48
|
# @api private
|
|
49
49
|
def initialize(replies, connection_description, connection_global_id, ids)
|
|
50
|
-
|
|
51
|
-
@connection_description = connection_description
|
|
52
|
-
@connection_global_id = connection_global_id
|
|
50
|
+
super(replies, connection_description, connection_global_id)
|
|
53
51
|
if replies && replies.first && (doc = replies.first.documents.first)
|
|
54
|
-
if errors = doc['writeErrors']
|
|
52
|
+
if (errors = doc['writeErrors'])
|
|
55
53
|
# some documents were potentially inserted
|
|
56
54
|
bad_indices = {}
|
|
57
55
|
errors.map do |error|
|
|
@@ -162,15 +162,6 @@ module Mongo
|
|
|
162
162
|
!!@replies
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
-
# Whether the result contains cursor_id
|
|
166
|
-
#
|
|
167
|
-
# @return [ true, false ] If the result contains cursor_id.
|
|
168
|
-
#
|
|
169
|
-
# @api private
|
|
170
|
-
def has_cursor_id?
|
|
171
|
-
acknowledged? && replies.last.respond_to?(:cursor_id)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
165
|
# Get the cursor id if the response is acknowledged.
|
|
175
166
|
#
|
|
176
167
|
# @note Cursor ids of 0 indicate there is no cursor on the server.
|
|
@@ -183,7 +174,17 @@ module Mongo
|
|
|
183
174
|
# @since 2.0.0
|
|
184
175
|
# @api private
|
|
185
176
|
def cursor_id
|
|
186
|
-
|
|
177
|
+
return 0 unless acknowledged?
|
|
178
|
+
|
|
179
|
+
if replies.last.respond_to?(:cursor_id)
|
|
180
|
+
# Legacy OP_REPLY replies expose the cursor id directly.
|
|
181
|
+
replies.last.cursor_id
|
|
182
|
+
elsif first_document.key?(CURSOR)
|
|
183
|
+
# OP_MSG command replies carry the cursor id in the `cursor` subdocument.
|
|
184
|
+
first_document[CURSOR][CURSOR_ID] || 0
|
|
185
|
+
else
|
|
186
|
+
0
|
|
187
|
+
end
|
|
187
188
|
end
|
|
188
189
|
|
|
189
190
|
# Get the namespace of the cursor. The method should be defined in
|
|
@@ -450,11 +451,20 @@ module Mongo
|
|
|
450
451
|
end
|
|
451
452
|
|
|
452
453
|
def snapshot_timestamp
|
|
453
|
-
return unless doc = reply.documents.first
|
|
454
|
+
return unless (doc = reply.documents.first)
|
|
454
455
|
|
|
455
456
|
doc['cursor']&.[]('atClusterTime') || doc['atClusterTime']
|
|
456
457
|
end
|
|
457
458
|
|
|
459
|
+
# Returns the base backoff in milliseconds for a server overload error, if present.
|
|
460
|
+
#
|
|
461
|
+
# @return [ Integer | nil ] The base backoff in milliseconds.
|
|
462
|
+
#
|
|
463
|
+
# @api private
|
|
464
|
+
def base_backoff_ms
|
|
465
|
+
first_document && first_document['baseBackoffMS']
|
|
466
|
+
end
|
|
467
|
+
|
|
458
468
|
private
|
|
459
469
|
|
|
460
470
|
def operation_failure_class
|
|
@@ -465,20 +475,6 @@ module Mongo
|
|
|
465
475
|
end
|
|
466
476
|
end
|
|
467
477
|
|
|
468
|
-
def aggregate_returned_count
|
|
469
|
-
replies.reduce(0) do |n, reply|
|
|
470
|
-
n += reply.number_returned
|
|
471
|
-
n
|
|
472
|
-
end
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
def aggregate_written_count
|
|
476
|
-
documents.reduce(0) do |n, document|
|
|
477
|
-
n += document[N] || 0
|
|
478
|
-
n
|
|
479
|
-
end
|
|
480
|
-
end
|
|
481
|
-
|
|
482
478
|
def parser
|
|
483
479
|
@parser ||= Error::Parser.new(first_document, replies)
|
|
484
480
|
end
|
|
@@ -28,8 +28,10 @@ module Mongo
|
|
|
28
28
|
#
|
|
29
29
|
# This method overrides the causal consistency addition logic of
|
|
30
30
|
# SessionsSupported and is meant to be used with operations classified
|
|
31
|
-
# as "read operations accepting a read concern", as these are
|
|
32
|
-
# in the causal consistency spec.
|
|
31
|
+
# as "read and write operations accepting a read concern", as these are
|
|
32
|
+
# defined in the causal consistency spec. For write operations this
|
|
33
|
+
# attaches only afterClusterTime (no read concern level) so that causal
|
|
34
|
+
# ordering is preserved across writes in a causally consistent session.
|
|
33
35
|
#
|
|
34
36
|
# In order for the override to work correctly the
|
|
35
37
|
# CausalConsistencySupported module must be included after
|
|
@@ -64,14 +64,6 @@ module Mongo
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
if result.has_cursor_id? &&
|
|
68
|
-
connection.description.load_balancer?
|
|
69
|
-
if result.cursor_id == 0
|
|
70
|
-
connection.unpin
|
|
71
|
-
else
|
|
72
|
-
connection.pin
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
67
|
process_result(result, connection)
|
|
76
68
|
end
|
|
77
69
|
end
|
|
@@ -121,7 +113,7 @@ module Mongo
|
|
|
121
113
|
# @param [ Mongo::Operation::Context ] context The operation context.
|
|
122
114
|
def build_message(connection, context)
|
|
123
115
|
msg = message(connection)
|
|
124
|
-
if server_api = context.server_api
|
|
116
|
+
if (server_api = context.server_api)
|
|
125
117
|
msg = msg.maybe_add_server_api(server_api)
|
|
126
118
|
end
|
|
127
119
|
msg
|
|
@@ -140,12 +132,7 @@ module Mongo
|
|
|
140
132
|
def process_result_for_sdam(result, connection)
|
|
141
133
|
if (result.not_master? || result.node_recovering?) &&
|
|
142
134
|
connection.generation >= connection.server.pool.generation(service_id: connection.service_id)
|
|
143
|
-
keep_pool =
|
|
144
|
-
false
|
|
145
|
-
else
|
|
146
|
-
# Max wire version needs to be examined while the server is known
|
|
147
|
-
connection.description.server_version_gte?('4.2')
|
|
148
|
-
end
|
|
135
|
+
keep_pool = !result.node_shutting_down?
|
|
149
136
|
|
|
150
137
|
connection.server.unknown!(
|
|
151
138
|
keep_connection_pool: keep_pool,
|
|
@@ -36,7 +36,7 @@ module Mongo
|
|
|
36
36
|
return unless @replies
|
|
37
37
|
|
|
38
38
|
@replies.reduce(nil) do |errors, reply|
|
|
39
|
-
next unless write_errors = reply.documents.first['writeErrors']
|
|
39
|
+
next unless (write_errors = reply.documents.first['writeErrors'])
|
|
40
40
|
|
|
41
41
|
wes = write_errors.collect do |we|
|
|
42
42
|
we.merge!('index' => count + we['index'])
|
|
@@ -59,7 +59,7 @@ module Mongo
|
|
|
59
59
|
return unless @replies
|
|
60
60
|
|
|
61
61
|
@replies.each_with_index.reduce(nil) do |errors, (reply, _)|
|
|
62
|
-
next unless write_concern_errors = reply.documents.first['writeConcernErrors']
|
|
62
|
+
next unless (write_concern_errors = reply.documents.first['writeConcernErrors'])
|
|
63
63
|
|
|
64
64
|
(errors || []) << write_concern_errors.reduce(nil) do |errs, wce|
|
|
65
65
|
wce.merge!('index' => count + wce['index'])
|
|
@@ -61,7 +61,7 @@ module Mongo
|
|
|
61
61
|
def apply_causal_consistency_if_possible(selector, connection)
|
|
62
62
|
return if connection.description.standalone?
|
|
63
63
|
|
|
64
|
-
cc_doc = session.
|
|
64
|
+
cc_doc = session.causal_consistency_doc
|
|
65
65
|
return unless cc_doc
|
|
66
66
|
|
|
67
67
|
rc_doc = (selector[:readConcern] || read_concern || {}).merge(cc_doc)
|
|
@@ -165,9 +165,7 @@ module Mongo
|
|
|
165
165
|
read_doc = if connection.description.standalone?
|
|
166
166
|
# Read preference is never sent to standalones.
|
|
167
167
|
nil
|
|
168
|
-
elsif connection.server.load_balancer?
|
|
169
|
-
read&.to_mongos
|
|
170
|
-
elsif connection.description.mongos?
|
|
168
|
+
elsif connection.server.load_balancer? || connection.description.mongos?
|
|
171
169
|
# When server is a mongos:
|
|
172
170
|
# - $readPreference is never sent when mode is 'primary'
|
|
173
171
|
# - Otherwise $readPreference is sent
|
|
@@ -243,7 +241,7 @@ module Mongo
|
|
|
243
241
|
end
|
|
244
242
|
|
|
245
243
|
super.tap do |message|
|
|
246
|
-
if session = context.session
|
|
244
|
+
if (session = context.session)
|
|
247
245
|
# Serialize the message to detect client-side problems,
|
|
248
246
|
# such as invalid BSON keys or too large messages.
|
|
249
247
|
# The message will be serialized again
|
data/lib/mongo/operation.rb
CHANGED
|
@@ -38,6 +38,7 @@ require 'mongo/operation/drop'
|
|
|
38
38
|
require 'mongo/operation/drop_database'
|
|
39
39
|
require 'mongo/operation/get_more'
|
|
40
40
|
require 'mongo/operation/find'
|
|
41
|
+
require 'mongo/operation/cursor_command'
|
|
41
42
|
require 'mongo/operation/explain'
|
|
42
43
|
require 'mongo/operation/kill_cursors'
|
|
43
44
|
require 'mongo/operation/indexes'
|
|
@@ -143,14 +143,14 @@ module Mongo
|
|
|
143
143
|
|
|
144
144
|
def redacted_string(method)
|
|
145
145
|
'{' + reduce([]) do |list, (k, v)|
|
|
146
|
-
list << "#{k.
|
|
146
|
+
list << "#{k.public_send(method)}=>#{redact(k, v, method)}"
|
|
147
147
|
end.join(', ') + '}'
|
|
148
148
|
end
|
|
149
149
|
|
|
150
150
|
def redact(k, v, method)
|
|
151
151
|
return STRING_REPLACEMENT if SENSITIVE_OPTIONS.include?(k.to_sym)
|
|
152
152
|
|
|
153
|
-
v.
|
|
153
|
+
v.public_send(method)
|
|
154
154
|
end
|
|
155
155
|
end
|
|
156
156
|
end
|
|
@@ -74,12 +74,15 @@ module Mongo
|
|
|
74
74
|
#
|
|
75
75
|
# @since 2.5.0
|
|
76
76
|
def initialize(message, compressor, zlib_compression_level = nil)
|
|
77
|
+
super()
|
|
77
78
|
@original_message = message
|
|
78
79
|
@original_op_code = message.op_code
|
|
79
80
|
@uncompressed_size = 0
|
|
80
81
|
@compressor_id = COMPRESSOR_ID_MAP[compressor]
|
|
81
82
|
@compressed_message = ''
|
|
82
83
|
@zlib_compression_level = zlib_compression_level if zlib_compression_level && zlib_compression_level != -1
|
|
84
|
+
# A compressed message must reuse the wrapped message's request id,
|
|
85
|
+
# overriding the fresh id assigned by the superclass initializer.
|
|
83
86
|
@request_id = message.request_id
|
|
84
87
|
end
|
|
85
88
|
|
|
@@ -93,11 +96,11 @@ module Mongo
|
|
|
93
96
|
message = Registry.get(@original_op_code).allocate
|
|
94
97
|
buf = decompress(@compressed_message)
|
|
95
98
|
|
|
96
|
-
message.
|
|
99
|
+
message.fields.each do |field|
|
|
97
100
|
if field[:multi]
|
|
98
|
-
|
|
101
|
+
message.deserialize_array(buf, field)
|
|
99
102
|
else
|
|
100
|
-
|
|
103
|
+
message.deserialize_field(buf, field)
|
|
101
104
|
end
|
|
102
105
|
end
|
|
103
106
|
message.fix_after_deserialization if message.is_a?(Msg)
|
|
@@ -116,6 +119,15 @@ module Mongo
|
|
|
116
119
|
@original_message.replyable?
|
|
117
120
|
end
|
|
118
121
|
|
|
122
|
+
# @api private
|
|
123
|
+
def serialize_fields(buffer, max_bson_size)
|
|
124
|
+
buf = BSON::ByteBuffer.new
|
|
125
|
+
@original_message.serialize_fields(buf, max_bson_size)
|
|
126
|
+
@uncompressed_size = buf.length
|
|
127
|
+
@compressed_message = compress(buf)
|
|
128
|
+
super
|
|
129
|
+
end
|
|
130
|
+
|
|
119
131
|
private
|
|
120
132
|
|
|
121
133
|
# The operation code for a +Compressed+ message.
|
|
@@ -140,14 +152,6 @@ module Mongo
|
|
|
140
152
|
# @return [ String ] The actual compressed message bytes.
|
|
141
153
|
field :compressed_message, Bytes
|
|
142
154
|
|
|
143
|
-
def serialize_fields(buffer, max_bson_size)
|
|
144
|
-
buf = BSON::ByteBuffer.new
|
|
145
|
-
@original_message.send(:serialize_fields, buf, max_bson_size)
|
|
146
|
-
@uncompressed_size = buf.length
|
|
147
|
-
@compressed_message = compress(buf)
|
|
148
|
-
super
|
|
149
|
-
end
|
|
150
|
-
|
|
151
155
|
def compress(buffer)
|
|
152
156
|
if @compressor_id == NOOP_BYTE
|
|
153
157
|
buffer.to_s.force_encoding(BSON::BINARY)
|
|
@@ -148,10 +148,6 @@ module Mongo
|
|
|
148
148
|
# @return [ Mongo::Protocol::Msg ] The decrypted message, or the original
|
|
149
149
|
# message if decryption was not possible or necessary.
|
|
150
150
|
def maybe_decrypt(_context)
|
|
151
|
-
# TODO: determine if we should be decrypting data coming from pre-4.2
|
|
152
|
-
# servers, potentially using legacy wire protocols. If so we need
|
|
153
|
-
# to implement decryption for those wire protocols as our current
|
|
154
|
-
# encryption/decryption code is OP_MSG-specific.
|
|
155
151
|
self
|
|
156
152
|
end
|
|
157
153
|
|
|
@@ -268,11 +264,11 @@ module Mongo
|
|
|
268
264
|
buf = BSON::ByteBuffer.new(chunk)
|
|
269
265
|
|
|
270
266
|
message = Registry.get(_op_code).allocate
|
|
271
|
-
message.
|
|
267
|
+
message.fields.each do |field|
|
|
272
268
|
if field[:multi]
|
|
273
|
-
deserialize_array(
|
|
269
|
+
message.deserialize_array(buf, field, options)
|
|
274
270
|
else
|
|
275
|
-
deserialize_field(
|
|
271
|
+
message.deserialize_field(buf, field, options)
|
|
276
272
|
end
|
|
277
273
|
end
|
|
278
274
|
message.fix_after_deserialization if message.is_a?(Msg)
|
|
@@ -369,7 +365,6 @@ module Mongo
|
|
|
369
365
|
# deserialized field specified in the class by the field dsl under
|
|
370
366
|
# the key +:multi+
|
|
371
367
|
#
|
|
372
|
-
# @param message [Message] Message to contain the deserialized array.
|
|
373
368
|
# @param io [IO] Stream containing the array to deserialize.
|
|
374
369
|
# @param field [Hash] Hash representing a field.
|
|
375
370
|
# @param options [ Hash ]
|
|
@@ -377,18 +372,17 @@ module Mongo
|
|
|
377
372
|
# @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
|
|
378
373
|
# each of the elements in this array using BSON types wherever possible.
|
|
379
374
|
#
|
|
380
|
-
# @return [
|
|
375
|
+
# @return [Array] The deserialized array.
|
|
381
376
|
# @api private
|
|
382
|
-
def
|
|
377
|
+
def deserialize_array(io, field, options = {})
|
|
383
378
|
elements = []
|
|
384
|
-
count =
|
|
379
|
+
count = instance_variable_get(field[:multi])
|
|
385
380
|
count.times { elements << field[:type].deserialize(io, options) }
|
|
386
|
-
|
|
381
|
+
instance_variable_set(field[:name], elements)
|
|
387
382
|
end
|
|
388
383
|
|
|
389
|
-
# Deserializes a single field
|
|
384
|
+
# Deserializes a single field into this message.
|
|
390
385
|
#
|
|
391
|
-
# @param message [Message] Message to contain the deserialized field.
|
|
392
386
|
# @param io [IO] Stream containing the field to deserialize.
|
|
393
387
|
# @param field [Hash] Hash representing a field.
|
|
394
388
|
# @param options [ Hash ]
|
|
@@ -396,20 +390,19 @@ module Mongo
|
|
|
396
390
|
# @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
|
|
397
391
|
# this field using BSON types wherever possible.
|
|
398
392
|
#
|
|
399
|
-
# @return [
|
|
393
|
+
# @return [Object] The deserialized field value.
|
|
400
394
|
# @api private
|
|
401
|
-
def
|
|
402
|
-
|
|
395
|
+
def deserialize_field(io, field, options = {})
|
|
396
|
+
instance_variable_set(
|
|
403
397
|
field[:name],
|
|
404
398
|
field[:type].deserialize(io, options)
|
|
405
399
|
)
|
|
406
400
|
end
|
|
407
401
|
|
|
408
|
-
private
|
|
409
|
-
|
|
410
402
|
# A method for getting the fields for a message class
|
|
411
403
|
#
|
|
412
|
-
# @return [
|
|
404
|
+
# @return [Array<Hash>] The fields for the message class
|
|
405
|
+
# @api private
|
|
413
406
|
def fields
|
|
414
407
|
self.class.fields
|
|
415
408
|
end
|
|
@@ -418,6 +411,7 @@ module Mongo
|
|
|
418
411
|
#
|
|
419
412
|
# @param buffer [String] buffer to receive the field
|
|
420
413
|
# @return [String] buffer with serialized field
|
|
414
|
+
# @api private
|
|
421
415
|
def serialize_fields(buffer, max_bson_size = nil)
|
|
422
416
|
fields.each do |field|
|
|
423
417
|
value = instance_variable_get(field[:name])
|
|
@@ -437,6 +431,8 @@ module Mongo
|
|
|
437
431
|
end
|
|
438
432
|
end
|
|
439
433
|
|
|
434
|
+
private
|
|
435
|
+
|
|
440
436
|
# Serializes the header of the message consisting of 4 32bit integers
|
|
441
437
|
#
|
|
442
438
|
# The integers represent a message length placeholder (calculation of
|
data/lib/mongo/protocol/msg.rb
CHANGED
|
@@ -201,23 +201,12 @@ module Mongo
|
|
|
201
201
|
# represents one of the command types allow-listed by libmongocrypt and it
|
|
202
202
|
# contains data that is required to be encrypted by a local or remote json schema.
|
|
203
203
|
#
|
|
204
|
-
# @param [ Mongo::Server::Connection ] connection The connection on which
|
|
205
|
-
# the operation is performed.
|
|
206
204
|
# @param [ Mongo::Operation::Context ] context The operation context.
|
|
207
205
|
#
|
|
208
206
|
# @return [ Mongo::Protocol::Msg ] The encrypted message, or the original
|
|
209
207
|
# message if encryption was not possible or necessary.
|
|
210
|
-
def maybe_encrypt(
|
|
208
|
+
def maybe_encrypt(_connection, context)
|
|
211
209
|
if context.encrypt?
|
|
212
|
-
if connection.description.max_wire_version < 8
|
|
213
|
-
raise Error::CryptError.new(
|
|
214
|
-
'Cannot perform encryption against a MongoDB server older than ' +
|
|
215
|
-
'4.2 (wire version less than 8). Currently connected to server ' +
|
|
216
|
-
"with max wire version #{connection.description.max_wire_version}} " +
|
|
217
|
-
'(Auto-encryption requires a minimum MongoDB version of 4.2)'
|
|
218
|
-
)
|
|
219
|
-
end
|
|
220
|
-
|
|
221
210
|
db_name = @main_document[DATABASE_IDENTIFIER]
|
|
222
211
|
cmd = merge_sections
|
|
223
212
|
enc_cmd = context.encrypt(db_name, cmd)
|
|
@@ -181,9 +181,7 @@ module Mongo
|
|
|
181
181
|
def self.serialize(buffer, value, max_bson_size = nil, _validating_keys = nil)
|
|
182
182
|
value.each do |section|
|
|
183
183
|
case section[:type]
|
|
184
|
-
when PayloadZero::TYPE
|
|
185
|
-
PayloadZero.serialize(buffer, section[:payload], max_bson_size)
|
|
186
|
-
when nil
|
|
184
|
+
when PayloadZero::TYPE, nil
|
|
187
185
|
PayloadZero.serialize(buffer, section[:payload], max_bson_size)
|
|
188
186
|
when PayloadOne::TYPE
|
|
189
187
|
PayloadOne.serialize(buffer, section[:payload], max_bson_size)
|
data/lib/mongo/query_cache.rb
CHANGED
|
@@ -199,11 +199,9 @@ module Mongo
|
|
|
199
199
|
# Otherwise, return nil because the stored cursor will not satisfy
|
|
200
200
|
# the query.
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
caching_cursor
|
|
206
|
-
end
|
|
202
|
+
return unless caching_cursor_limit.nil? || (limit && caching_cursor_limit >= limit)
|
|
203
|
+
|
|
204
|
+
caching_cursor
|
|
207
205
|
end
|
|
208
206
|
|
|
209
207
|
def normalized_limit(limit)
|
|
@@ -23,9 +23,24 @@ module Mongo
|
|
|
23
23
|
# a random value. Can be injected for deterministic testing.
|
|
24
24
|
#
|
|
25
25
|
# @return [ Float ] The backoff delay in seconds.
|
|
26
|
-
def self.backoff_delay(attempt, jitter: rand)
|
|
27
|
-
jitter * [ MAX_BACKOFF,
|
|
26
|
+
def self.backoff_delay(attempt, jitter: rand, err: nil)
|
|
27
|
+
jitter * [ MAX_BACKOFF, base_backoff(err) * (2**attempt) ].min
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
def self.base_backoff(err)
|
|
31
|
+
return BASE_BACKOFF if err.nil?
|
|
32
|
+
return BASE_BACKOFF unless err.respond_to?(:result) && err.result.respond_to?(:base_backoff_ms)
|
|
33
|
+
|
|
34
|
+
base_backoff_ms = err.result.base_backoff_ms
|
|
35
|
+
|
|
36
|
+
if base_backoff_ms && base_backoff_ms > 0
|
|
37
|
+
err.result.base_backoff_ms / 1000.0
|
|
38
|
+
else
|
|
39
|
+
BASE_BACKOFF
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private_class_method :base_backoff
|
|
29
44
|
end
|
|
30
45
|
end
|
|
31
46
|
end
|
|
@@ -340,7 +340,7 @@ module Mongo
|
|
|
340
340
|
def overload_read_retry(last_error, session, server_selector, context, failed_server, error_count:)
|
|
341
341
|
last_was_overload = true
|
|
342
342
|
loop do
|
|
343
|
-
delay = last_was_overload ? retry_policy.backoff_delay(error_count) : 0
|
|
343
|
+
delay = last_was_overload ? retry_policy.backoff_delay(error_count, err: last_error) : 0
|
|
344
344
|
raise last_error unless retry_policy.should_retry_overload?(error_count, delay, context: context)
|
|
345
345
|
|
|
346
346
|
log_retry(last_error, message: 'Read retry (overload backoff)')
|
|
@@ -27,8 +27,8 @@ module Mongo
|
|
|
27
27
|
# @param [ Float ] jitter A random float in [0.0, 1.0).
|
|
28
28
|
#
|
|
29
29
|
# @return [ Float ] The backoff delay in seconds.
|
|
30
|
-
def backoff_delay(attempt, jitter: rand)
|
|
31
|
-
Backpressure.backoff_delay(attempt, jitter: jitter)
|
|
30
|
+
def backoff_delay(attempt, jitter: rand, err: nil)
|
|
31
|
+
Backpressure.backoff_delay(attempt, jitter: jitter, err: err)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Determine whether an overload retry should be attempted.
|
|
@@ -123,7 +123,7 @@ module Mongo
|
|
|
123
123
|
unless e.respond_to?(:label?) && e.label?('NoWritesPerformed')
|
|
124
124
|
error_to_raise = e
|
|
125
125
|
end
|
|
126
|
-
delay = retry_policy.backoff_delay(error_count)
|
|
126
|
+
delay = retry_policy.backoff_delay(error_count, err: e)
|
|
127
127
|
raise error_to_raise unless retry_policy.should_retry_overload?(error_count, delay, context: context)
|
|
128
128
|
|
|
129
129
|
log_retry(e, message: 'Write retry (overload backoff)')
|
|
@@ -386,7 +386,7 @@ module Mongo
|
|
|
386
386
|
last_was_overload = true
|
|
387
387
|
|
|
388
388
|
loop do
|
|
389
|
-
delay = last_was_overload ? retry_policy.backoff_delay(error_count) : 0
|
|
389
|
+
delay = last_was_overload ? retry_policy.backoff_delay(error_count, err: last_error) : 0
|
|
390
390
|
raise error_to_raise unless retry_policy.should_retry_overload?(error_count, delay, context: context)
|
|
391
391
|
|
|
392
392
|
log_retry(last_error, message: 'Write retry (overload backoff)')
|
data/lib/mongo/retryable.rb
CHANGED
|
@@ -129,7 +129,7 @@ module Mongo
|
|
|
129
129
|
|
|
130
130
|
error_count += 1
|
|
131
131
|
policy = client.retry_policy
|
|
132
|
-
delay = policy.backoff_delay(error_count)
|
|
132
|
+
delay = policy.backoff_delay(error_count, err: e)
|
|
133
133
|
raise e unless policy.should_retry_overload?(error_count, delay, context: context)
|
|
134
134
|
|
|
135
135
|
Logger.logger.warn("Overload retry due to: #{e.class.name}: #{e.message}")
|
|
@@ -88,6 +88,7 @@ module Mongo
|
|
|
88
88
|
#
|
|
89
89
|
# @since 2.0.0
|
|
90
90
|
def initialize(server, options = {})
|
|
91
|
+
super()
|
|
91
92
|
if server.load_balancer? && options[:generation]
|
|
92
93
|
raise ArgumentError, 'Generation cannot be set when server is a load balancer'
|
|
93
94
|
end
|
|
@@ -422,7 +423,8 @@ module Mongo
|
|
|
422
423
|
generation: e.generation,
|
|
423
424
|
# or description.service_id?
|
|
424
425
|
service_id: e.service_id,
|
|
425
|
-
stop_push_monitor: true
|
|
426
|
+
stop_push_monitor: true,
|
|
427
|
+
network_error: true
|
|
426
428
|
)
|
|
427
429
|
raise
|
|
428
430
|
rescue Error::SocketTimeoutError => e
|
|
@@ -99,6 +99,14 @@ module Mongo
|
|
|
99
99
|
end
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
+
# Closes the underlying socket, if one is open, to interrupt an
|
|
103
|
+
# in-progress blocking read on the connection.
|
|
104
|
+
#
|
|
105
|
+
# @api private
|
|
106
|
+
def interrupt_socket
|
|
107
|
+
socket&.close
|
|
108
|
+
end
|
|
109
|
+
|
|
102
110
|
private
|
|
103
111
|
|
|
104
112
|
HELLO_DOC = BSON::Document.new({ hello: 1 }).freeze
|
|
@@ -112,7 +120,7 @@ module Mongo
|
|
|
112
120
|
|
|
113
121
|
return unless options[:compressors]
|
|
114
122
|
|
|
115
|
-
if intersection = (server_compressors & options[:compressors])
|
|
123
|
+
if (intersection = (server_compressors & options[:compressors]))
|
|
116
124
|
@compressor = intersection.first
|
|
117
125
|
else
|
|
118
126
|
msg = if server_compressors
|