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.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/bin/mongo_console +2 -2
  3. data/lib/mongo/address/validator.rb +1 -1
  4. data/lib/mongo/address.rb +1 -3
  5. data/lib/mongo/auth/aws/conversation.rb +0 -4
  6. data/lib/mongo/auth/aws/credentials_retriever.rb +3 -8
  7. data/lib/mongo/auth/base.rb +1 -1
  8. data/lib/mongo/auth/sasl_conversation_base.rb +1 -1
  9. data/lib/mongo/auth/scram_conversation_base.rb +1 -8
  10. data/lib/mongo/auth/stringprep.rb +1 -6
  11. data/lib/mongo/auth/user/view.rb +1 -1
  12. data/lib/mongo/bulk_write/result.rb +10 -2
  13. data/lib/mongo/bulk_write/result_combiner.rb +11 -4
  14. data/lib/mongo/bulk_write.rb +1 -1
  15. data/lib/mongo/client.rb +82 -12
  16. data/lib/mongo/cluster/reapers/cursor_reaper.rb +12 -5
  17. data/lib/mongo/cluster/sdam_flow.rb +4 -4
  18. data/lib/mongo/cluster/topology/base.rb +1 -1
  19. data/lib/mongo/cluster.rb +12 -28
  20. data/lib/mongo/collection/view/aggregation/behavior.rb +1 -1
  21. data/lib/mongo/collection/view/aggregation.rb +2 -4
  22. data/lib/mongo/collection/view/builder/aggregation.rb +3 -5
  23. data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
  24. data/lib/mongo/collection/view/change_stream.rb +14 -9
  25. data/lib/mongo/collection/view/map_reduce.rb +2 -11
  26. data/lib/mongo/collection/view/readable.rb +11 -7
  27. data/lib/mongo/collection/view/writable.rb +4 -4
  28. data/lib/mongo/collection/view.rb +8 -4
  29. data/lib/mongo/collection.rb +1 -1
  30. data/lib/mongo/config.rb +5 -0
  31. data/lib/mongo/crypt/auto_encrypter.rb +1 -1
  32. data/lib/mongo/crypt/binary.rb +7 -4
  33. data/lib/mongo/crypt/binding.rb +88 -10
  34. data/lib/mongo/crypt/context.rb +50 -19
  35. data/lib/mongo/crypt/encryption_io.rb +11 -5
  36. data/lib/mongo/crypt/handle.rb +17 -5
  37. data/lib/mongo/crypt/kms/credentials.rb +70 -31
  38. data/lib/mongo/crypt/kms/kmip/master_document.rb +30 -1
  39. data/lib/mongo/crypt/kms/master_key_document.rb +11 -6
  40. data/lib/mongo/crypt/kms.rb +12 -1
  41. data/lib/mongo/cursor.rb +8 -2
  42. data/lib/mongo/database/cursor_command_view.rb +95 -0
  43. data/lib/mongo/database.rb +144 -18
  44. data/lib/mongo/error/bulk_write_error.rb +29 -1
  45. data/lib/mongo/error/invalid_server_preference.rb +3 -0
  46. data/lib/mongo/error/invalid_uri.rb +5 -1
  47. data/lib/mongo/error/operation_failure.rb +42 -3
  48. data/lib/mongo/error/parser.rb +3 -3
  49. data/lib/mongo/error/sdam_error_detection.rb +2 -3
  50. data/lib/mongo/grid/fs_bucket.rb +27 -21
  51. data/lib/mongo/grid/stream/write.rb +2 -2
  52. data/lib/mongo/index/view.rb +13 -7
  53. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -0
  54. data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +1 -0
  55. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +1 -0
  56. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +1 -0
  57. data/lib/mongo/monitoring/event/cmap/connection_closed.rb +1 -0
  58. data/lib/mongo/monitoring/event/cmap/connection_created.rb +1 -0
  59. data/lib/mongo/monitoring/event/cmap/connection_ready.rb +1 -0
  60. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +1 -0
  61. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +1 -0
  62. data/lib/mongo/monitoring/event/cmap/pool_created.rb +1 -0
  63. data/lib/mongo/monitoring/event/cmap/pool_ready.rb +1 -0
  64. data/lib/mongo/monitoring/event/command_failed.rb +1 -0
  65. data/lib/mongo/monitoring/event/command_started.rb +1 -0
  66. data/lib/mongo/monitoring/event/command_succeeded.rb +1 -0
  67. data/lib/mongo/monitoring/event/secure.rb +12 -17
  68. data/lib/mongo/monitoring/event/server_closed.rb +1 -0
  69. data/lib/mongo/monitoring/event/server_description_changed.rb +1 -0
  70. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +1 -0
  71. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +1 -0
  72. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +1 -0
  73. data/lib/mongo/monitoring/event/server_opening.rb +1 -0
  74. data/lib/mongo/monitoring/event/topology_changed.rb +1 -0
  75. data/lib/mongo/monitoring/event/topology_closed.rb +1 -0
  76. data/lib/mongo/monitoring/event/topology_opening.rb +1 -0
  77. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +2 -0
  78. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +3 -0
  79. data/lib/mongo/operation/create/op_msg.rb +1 -0
  80. data/lib/mongo/operation/create_index/op_msg.rb +2 -1
  81. data/lib/mongo/operation/cursor_command/op_msg.rb +37 -0
  82. data/lib/mongo/operation/cursor_command/result.rb +60 -0
  83. data/lib/mongo/operation/cursor_command.rb +33 -0
  84. data/lib/mongo/operation/delete/op_msg.rb +1 -0
  85. data/lib/mongo/operation/drop/op_msg.rb +1 -0
  86. data/lib/mongo/operation/drop_database/op_msg.rb +1 -0
  87. data/lib/mongo/operation/drop_index/op_msg.rb +1 -0
  88. data/lib/mongo/operation/find/builder/command.rb +1 -1
  89. data/lib/mongo/operation/insert/bulk_result.rb +2 -4
  90. data/lib/mongo/operation/insert/op_msg.rb +1 -0
  91. data/lib/mongo/operation/result.rb +14 -26
  92. data/lib/mongo/operation/shared/causal_consistency_supported.rb +4 -2
  93. data/lib/mongo/operation/shared/executable.rb +2 -10
  94. data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
  95. data/lib/mongo/operation/shared/sessions_supported.rb +3 -5
  96. data/lib/mongo/operation/update/bulk_result.rb +1 -1
  97. data/lib/mongo/operation/update/op_msg.rb +1 -0
  98. data/lib/mongo/operation/write_command/op_msg.rb +2 -0
  99. data/lib/mongo/operation.rb +1 -0
  100. data/lib/mongo/options/redacted.rb +2 -2
  101. data/lib/mongo/protocol/compressed.rb +15 -11
  102. data/lib/mongo/protocol/message.rb +16 -16
  103. data/lib/mongo/protocol/registry.rb +1 -1
  104. data/lib/mongo/protocol/serializers.rb +1 -3
  105. data/lib/mongo/query_cache.rb +3 -5
  106. data/lib/mongo/server/connection.rb +3 -1
  107. data/lib/mongo/server/connection_common.rb +9 -1
  108. data/lib/mongo/server/connection_pool/generation_manager.rb +1 -1
  109. data/lib/mongo/server/connection_pool.rb +79 -18
  110. data/lib/mongo/server/description/features.rb +2 -2
  111. data/lib/mongo/server/description.rb +24 -2
  112. data/lib/mongo/server/monitor/connection.rb +3 -2
  113. data/lib/mongo/server/monitor.rb +133 -30
  114. data/lib/mongo/server/pending_connection.rb +1 -0
  115. data/lib/mongo/server/push_monitor.rb +16 -2
  116. data/lib/mongo/server.rb +27 -7
  117. data/lib/mongo/server_selector/base.rb +16 -6
  118. data/lib/mongo/server_selector/nearest.rb +3 -0
  119. data/lib/mongo/server_selector/primary.rb +3 -0
  120. data/lib/mongo/server_selector/primary_preferred.rb +3 -0
  121. data/lib/mongo/server_selector/secondary.rb +3 -0
  122. data/lib/mongo/server_selector/secondary_preferred.rb +7 -1
  123. data/lib/mongo/session.rb +56 -24
  124. data/lib/mongo/socket/ssl.rb +3 -3
  125. data/lib/mongo/socket.rb +1 -7
  126. data/lib/mongo/srv/monitor.rb +11 -2
  127. data/lib/mongo/srv/resolver.rb +1 -1
  128. data/lib/mongo/srv/result.rb +5 -3
  129. data/lib/mongo/timeout.rb +10 -15
  130. data/lib/mongo/tracing/open_telemetry/command_tracer.rb +43 -2
  131. data/lib/mongo/uri/options_mapper.rb +21 -9
  132. data/lib/mongo/uri/srv_protocol.rb +4 -4
  133. data/lib/mongo/uri.rb +56 -8
  134. data/lib/mongo/utils.rb +1 -1
  135. data/lib/mongo/version.rb +1 -1
  136. data/lib/mongo.rb +1 -0
  137. metadata +6 -4
  138. data/lib/mongo/auth/stringprep/unicode_normalize/normalize.rb +0 -173
  139. data/lib/mongo/auth/stringprep/unicode_normalize/tables.rb +0 -1164
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 MongoDB Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'mongo/operation/cursor_command/op_msg'
18
+ require 'mongo/operation/cursor_command/result'
19
+
20
+ module Mongo
21
+ module Operation
22
+ # A command operation whose response is parsed as a cursor.
23
+ #
24
+ # Unlike Command, the result exposes the firstBatch, namespace, and cursor
25
+ # id from the command response so that a Cursor can be built from it.
26
+ #
27
+ # @api private
28
+ class CursorCommand
29
+ include Specifiable
30
+ include OpMsgExecutable
31
+ end
32
+ end
33
+ end
@@ -27,6 +27,7 @@ module Mongo
27
27
  include ExecutableNoValidate
28
28
  include ExecutableTransactionLabel
29
29
  include PolymorphicResult
30
+ include CausalConsistencySupported
30
31
 
31
32
  private
32
33
 
@@ -24,6 +24,7 @@ module Mongo
24
24
  # @since 2.5.2
25
25
  class OpMsg < OpMsgBase
26
26
  include ExecutableTransactionLabel
27
+ include CausalConsistencySupported
27
28
  end
28
29
  end
29
30
  end
@@ -24,6 +24,7 @@ module Mongo
24
24
  # @since 2.5.2
25
25
  class OpMsg < OpMsgBase
26
26
  include ExecutableTransactionLabel
27
+ include CausalConsistencySupported
27
28
  end
28
29
  end
29
30
  end
@@ -24,6 +24,7 @@ module Mongo
24
24
  # @since 2.5.2
25
25
  class OpMsg < OpMsgBase
26
26
  include ExecutableTransactionLabel
27
+ include CausalConsistencySupported
27
28
 
28
29
  private
29
30
 
@@ -60,7 +60,7 @@ module Mongo
60
60
  end
61
61
  end
62
62
 
63
- if rc = selector[:readConcern]
63
+ if (rc = selector[:readConcern])
64
64
  selector[:readConcern] = Options::Mapper.transform_values_to_strings(rc)
65
65
  end
66
66
 
@@ -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
- @replies = [ *replies ] if replies
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|
@@ -28,6 +28,7 @@ module Mongo
28
28
  include ExecutableNoValidate
29
29
  include ExecutableTransactionLabel
30
30
  include PolymorphicResult
31
+ include CausalConsistencySupported
31
32
 
32
33
  private
33
34
 
@@ -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
- acknowledged? ? replies.last.cursor_id : 0
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
@@ -355,7 +356,8 @@ module Mongo
355
356
  wtimeout: parser.wtimeout,
356
357
  connection_description: connection_description,
357
358
  document: parser.document,
358
- server_message: parser.server_message
359
+ server_message: parser.server_message,
360
+ server_address: connection_description
359
361
  )
360
362
  end
361
363
 
@@ -449,7 +451,7 @@ module Mongo
449
451
  end
450
452
 
451
453
  def snapshot_timestamp
452
- return unless doc = reply.documents.first
454
+ return unless (doc = reply.documents.first)
453
455
 
454
456
  doc['cursor']&.[]('atClusterTime') || doc['atClusterTime']
455
457
  end
@@ -464,20 +466,6 @@ module Mongo
464
466
  end
465
467
  end
466
468
 
467
- def aggregate_returned_count
468
- replies.reduce(0) do |n, reply|
469
- n += reply.number_returned
470
- n
471
- end
472
- end
473
-
474
- def aggregate_written_count
475
- documents.reduce(0) do |n, document|
476
- n += document[N] || 0
477
- n
478
- end
479
- end
480
-
481
469
  def parser
482
470
  @parser ||= Error::Parser.new(first_document, replies)
483
471
  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 defined
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
@@ -59,19 +59,11 @@ module Mongo
59
59
  end
60
60
  end
61
61
 
62
- if session.snapshot? && !session.snapshot_timestamp
62
+ if session.snapshot?
63
63
  session.snapshot_timestamp = result.snapshot_timestamp
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
@@ -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.send(:causal_consistency_doc)
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
@@ -107,7 +107,7 @@ module Mongo
107
107
  return [] unless acknowledged?
108
108
 
109
109
  @replies.reduce([]) do |ids, reply|
110
- if upserted_ids = reply.documents.first[UPSERTED]
110
+ if (upserted_ids = reply.documents.first[UPSERTED])
111
111
  ids += upserted_ids
112
112
  end
113
113
  ids
@@ -27,6 +27,7 @@ module Mongo
27
27
  include ExecutableNoValidate
28
28
  include ExecutableTransactionLabel
29
29
  include PolymorphicResult
30
+ include CausalConsistencySupported
30
31
 
31
32
  private
32
33
 
@@ -21,6 +21,8 @@ module Mongo
21
21
  #
22
22
  # @api private
23
23
  class OpMsg < OpMsgBase
24
+ include CausalConsistencySupported
25
+
24
26
  private
25
27
 
26
28
  def selector(connection)
@@ -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.send(method)}=>#{redact(k, v, method)}"
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.send(method)
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.send(:fields).each do |field|
99
+ message.fields.each do |field|
97
100
  if field[:multi]
98
- Message.deserialize_array(message, buf, field)
101
+ message.deserialize_array(buf, field)
99
102
  else
100
- Message.deserialize_field(message, buf, field)
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)
@@ -268,11 +268,11 @@ module Mongo
268
268
  buf = BSON::ByteBuffer.new(chunk)
269
269
 
270
270
  message = Registry.get(_op_code).allocate
271
- message.send(:fields).each do |field|
271
+ message.fields.each do |field|
272
272
  if field[:multi]
273
- deserialize_array(message, buf, field, options)
273
+ message.deserialize_array(buf, field, options)
274
274
  else
275
- deserialize_field(message, buf, field, options)
275
+ message.deserialize_field(buf, field, options)
276
276
  end
277
277
  end
278
278
  message.fix_after_deserialization if message.is_a?(Msg)
@@ -369,7 +369,6 @@ module Mongo
369
369
  # deserialized field specified in the class by the field dsl under
370
370
  # the key +:multi+
371
371
  #
372
- # @param message [Message] Message to contain the deserialized array.
373
372
  # @param io [IO] Stream containing the array to deserialize.
374
373
  # @param field [Hash] Hash representing a field.
375
374
  # @param options [ Hash ]
@@ -377,18 +376,17 @@ module Mongo
377
376
  # @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
378
377
  # each of the elements in this array using BSON types wherever possible.
379
378
  #
380
- # @return [Message] Message with deserialized array.
379
+ # @return [Array] The deserialized array.
381
380
  # @api private
382
- def self.deserialize_array(message, io, field, options = {})
381
+ def deserialize_array(io, field, options = {})
383
382
  elements = []
384
- count = message.instance_variable_get(field[:multi])
383
+ count = instance_variable_get(field[:multi])
385
384
  count.times { elements << field[:type].deserialize(io, options) }
386
- message.instance_variable_set(field[:name], elements)
385
+ instance_variable_set(field[:name], elements)
387
386
  end
388
387
 
389
- # Deserializes a single field in a message
388
+ # Deserializes a single field into this message.
390
389
  #
391
- # @param message [Message] Message to contain the deserialized field.
392
390
  # @param io [IO] Stream containing the field to deserialize.
393
391
  # @param field [Hash] Hash representing a field.
394
392
  # @param options [ Hash ]
@@ -396,20 +394,19 @@ module Mongo
396
394
  # @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
397
395
  # this field using BSON types wherever possible.
398
396
  #
399
- # @return [Message] Message with deserialized field.
397
+ # @return [Object] The deserialized field value.
400
398
  # @api private
401
- def self.deserialize_field(message, io, field, options = {})
402
- message.instance_variable_set(
399
+ def deserialize_field(io, field, options = {})
400
+ instance_variable_set(
403
401
  field[:name],
404
402
  field[:type].deserialize(io, options)
405
403
  )
406
404
  end
407
405
 
408
- private
409
-
410
406
  # A method for getting the fields for a message class
411
407
  #
412
- # @return [Integer] the fields for the message class
408
+ # @return [Array<Hash>] The fields for the message class
409
+ # @api private
413
410
  def fields
414
411
  self.class.fields
415
412
  end
@@ -418,6 +415,7 @@ module Mongo
418
415
  #
419
416
  # @param buffer [String] buffer to receive the field
420
417
  # @return [String] buffer with serialized field
418
+ # @api private
421
419
  def serialize_fields(buffer, max_bson_size = nil)
422
420
  fields.each do |field|
423
421
  value = instance_variable_get(field[:name])
@@ -437,6 +435,8 @@ module Mongo
437
435
  end
438
436
  end
439
437
 
438
+ private
439
+
440
440
  # Serializes the header of the message consisting of 4 32bit integers
441
441
  #
442
442
  # The integers represent a message length placeholder (calculation of
@@ -36,7 +36,7 @@ module Mongo
36
36
  #
37
37
  # @since 2.5.0
38
38
  def get(op_code, _message = nil)
39
- if type = MAPPINGS[op_code]
39
+ if (type = MAPPINGS[op_code])
40
40
  type
41
41
  else
42
42
  handle_unsupported_op_code!(op_code)
@@ -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)
@@ -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
- if limit && (caching_cursor_limit.nil? || caching_cursor_limit >= limit)
203
- caching_cursor
204
- elsif limit.nil? && caching_cursor_limit.nil?
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)
@@ -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
@@ -125,7 +125,7 @@ module Mongo
125
125
 
126
126
  # Close all fds scheduled for closing.
127
127
  def close_all_scheduled
128
- while pipe = @scheduled_for_close.pop
128
+ while (pipe = @scheduled_for_close.pop)
129
129
  pipe.close
130
130
  end
131
131
  end