mongo 2.24.1 → 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 (128) 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_combiner.rb +3 -3
  13. data/lib/mongo/bulk_write.rb +1 -1
  14. data/lib/mongo/client.rb +82 -12
  15. data/lib/mongo/cluster/reapers/cursor_reaper.rb +12 -5
  16. data/lib/mongo/cluster/sdam_flow.rb +4 -4
  17. data/lib/mongo/cluster/topology/base.rb +1 -1
  18. data/lib/mongo/cluster.rb +12 -28
  19. data/lib/mongo/collection/view/aggregation/behavior.rb +1 -1
  20. data/lib/mongo/collection/view/aggregation.rb +2 -4
  21. data/lib/mongo/collection/view/builder/aggregation.rb +3 -5
  22. data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
  23. data/lib/mongo/collection/view/change_stream.rb +14 -9
  24. data/lib/mongo/collection/view/map_reduce.rb +2 -11
  25. data/lib/mongo/collection/view/readable.rb +11 -7
  26. data/lib/mongo/collection/view/writable.rb +4 -4
  27. data/lib/mongo/collection/view.rb +8 -4
  28. data/lib/mongo/collection.rb +1 -1
  29. data/lib/mongo/crypt/auto_encrypter.rb +1 -1
  30. data/lib/mongo/crypt/binary.rb +7 -4
  31. data/lib/mongo/crypt/binding.rb +88 -10
  32. data/lib/mongo/crypt/context.rb +50 -19
  33. data/lib/mongo/crypt/encryption_io.rb +11 -5
  34. data/lib/mongo/crypt/handle.rb +17 -5
  35. data/lib/mongo/crypt/kms/credentials.rb +70 -31
  36. data/lib/mongo/crypt/kms/kmip/master_document.rb +30 -1
  37. data/lib/mongo/crypt/kms/master_key_document.rb +11 -6
  38. data/lib/mongo/crypt/kms.rb +12 -1
  39. data/lib/mongo/cursor.rb +8 -2
  40. data/lib/mongo/database/cursor_command_view.rb +95 -0
  41. data/lib/mongo/database.rb +144 -18
  42. data/lib/mongo/error/invalid_uri.rb +5 -1
  43. data/lib/mongo/error/operation_failure.rb +2 -2
  44. data/lib/mongo/error/parser.rb +3 -3
  45. data/lib/mongo/error/sdam_error_detection.rb +2 -3
  46. data/lib/mongo/grid/fs_bucket.rb +27 -21
  47. data/lib/mongo/grid/stream/write.rb +2 -2
  48. data/lib/mongo/index/view.rb +13 -7
  49. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -0
  50. data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +1 -0
  51. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +1 -0
  52. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +1 -0
  53. data/lib/mongo/monitoring/event/cmap/connection_closed.rb +1 -0
  54. data/lib/mongo/monitoring/event/cmap/connection_created.rb +1 -0
  55. data/lib/mongo/monitoring/event/cmap/connection_ready.rb +1 -0
  56. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +1 -0
  57. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +1 -0
  58. data/lib/mongo/monitoring/event/cmap/pool_created.rb +1 -0
  59. data/lib/mongo/monitoring/event/cmap/pool_ready.rb +1 -0
  60. data/lib/mongo/monitoring/event/command_failed.rb +1 -0
  61. data/lib/mongo/monitoring/event/command_started.rb +1 -0
  62. data/lib/mongo/monitoring/event/command_succeeded.rb +1 -0
  63. data/lib/mongo/monitoring/event/secure.rb +12 -17
  64. data/lib/mongo/monitoring/event/server_closed.rb +1 -0
  65. data/lib/mongo/monitoring/event/server_description_changed.rb +1 -0
  66. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +1 -0
  67. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +1 -0
  68. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +1 -0
  69. data/lib/mongo/monitoring/event/server_opening.rb +1 -0
  70. data/lib/mongo/monitoring/event/topology_changed.rb +1 -0
  71. data/lib/mongo/monitoring/event/topology_closed.rb +1 -0
  72. data/lib/mongo/monitoring/event/topology_opening.rb +1 -0
  73. data/lib/mongo/operation/create/op_msg.rb +1 -0
  74. data/lib/mongo/operation/create_index/op_msg.rb +2 -1
  75. data/lib/mongo/operation/cursor_command/op_msg.rb +37 -0
  76. data/lib/mongo/operation/cursor_command/result.rb +60 -0
  77. data/lib/mongo/operation/cursor_command.rb +33 -0
  78. data/lib/mongo/operation/delete/op_msg.rb +1 -0
  79. data/lib/mongo/operation/drop/op_msg.rb +1 -0
  80. data/lib/mongo/operation/drop_database/op_msg.rb +1 -0
  81. data/lib/mongo/operation/drop_index/op_msg.rb +1 -0
  82. data/lib/mongo/operation/find/builder/command.rb +1 -1
  83. data/lib/mongo/operation/insert/bulk_result.rb +2 -4
  84. data/lib/mongo/operation/insert/op_msg.rb +1 -0
  85. data/lib/mongo/operation/result.rb +12 -25
  86. data/lib/mongo/operation/shared/causal_consistency_supported.rb +4 -2
  87. data/lib/mongo/operation/shared/executable.rb +1 -9
  88. data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
  89. data/lib/mongo/operation/shared/sessions_supported.rb +3 -5
  90. data/lib/mongo/operation/update/bulk_result.rb +1 -1
  91. data/lib/mongo/operation/update/op_msg.rb +1 -0
  92. data/lib/mongo/operation/write_command/op_msg.rb +2 -0
  93. data/lib/mongo/operation.rb +1 -0
  94. data/lib/mongo/options/redacted.rb +2 -2
  95. data/lib/mongo/protocol/compressed.rb +15 -11
  96. data/lib/mongo/protocol/message.rb +16 -16
  97. data/lib/mongo/protocol/registry.rb +1 -1
  98. data/lib/mongo/protocol/serializers.rb +1 -3
  99. data/lib/mongo/query_cache.rb +3 -5
  100. data/lib/mongo/server/connection.rb +3 -1
  101. data/lib/mongo/server/connection_common.rb +9 -1
  102. data/lib/mongo/server/connection_pool/generation_manager.rb +1 -1
  103. data/lib/mongo/server/connection_pool.rb +24 -10
  104. data/lib/mongo/server/description/features.rb +1 -1
  105. data/lib/mongo/server/description.rb +1 -1
  106. data/lib/mongo/server/monitor/connection.rb +3 -2
  107. data/lib/mongo/server/monitor.rb +133 -30
  108. data/lib/mongo/server/pending_connection.rb +1 -0
  109. data/lib/mongo/server/push_monitor.rb +16 -2
  110. data/lib/mongo/server.rb +27 -7
  111. data/lib/mongo/server_selector/base.rb +3 -6
  112. data/lib/mongo/server_selector/secondary_preferred.rb +4 -1
  113. data/lib/mongo/session.rb +22 -23
  114. data/lib/mongo/socket/ssl.rb +3 -3
  115. data/lib/mongo/socket.rb +1 -7
  116. data/lib/mongo/srv/monitor.rb +11 -2
  117. data/lib/mongo/srv/resolver.rb +1 -1
  118. data/lib/mongo/srv/result.rb +5 -3
  119. data/lib/mongo/timeout.rb +10 -15
  120. data/lib/mongo/tracing/open_telemetry/command_tracer.rb +16 -2
  121. data/lib/mongo/uri/options_mapper.rb +21 -9
  122. data/lib/mongo/uri/srv_protocol.rb +4 -4
  123. data/lib/mongo/uri.rb +56 -8
  124. data/lib/mongo/utils.rb +1 -1
  125. data/lib/mongo/version.rb +1 -1
  126. metadata +6 -4
  127. data/lib/mongo/auth/stringprep/unicode_normalize/normalize.rb +0 -173
  128. data/lib/mongo/auth/stringprep/unicode_normalize/tables.rb +0 -1164
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9359ddba0c1cd025a706f5970893bbdce249c2ab5fbe9d4ce3293a308bb11ade
4
- data.tar.gz: f88046bc63c0a6b2d23017a3df2ba2cfe72bf6cd7d9565c985e64084bc41147d
3
+ metadata.gz: 846c673e8e85d3e7007bec794833276ed4da9591347e361465b190c10829c504
4
+ data.tar.gz: ad93e6b640fbdb3c6f757df0c0ae433f4c79d50c209fb0bd3c0b8c84402148a9
5
5
  SHA512:
6
- metadata.gz: 1ea813993a5e069434299e68eacfb1c79bcbb0161728d703dd20e3047f2699a11640c94067e22c1089e34b56398afb959843eb3d914f110878056c646402c7e8
7
- data.tar.gz: 837e4866998fc01f8523768fbee6f062a3d0564932f318c27d701e826ed123a4c329df0d74449455afa1146e2de42d7fe54941aaf25e9e9061fc83dd82d87d06
6
+ metadata.gz: 29750ebefccf852b621847e68bffd039f3e28c63829334880416d7e8348fbd8cc5769d7f5b1cf872030d874610739ef4df90f493d9b325d8bebcfe2dd7d7b638
7
+ data.tar.gz: fbb6248041e00a490ccf23e62c364ce3c8ea8214f3fd4c6f07ff8df18e090702c53039e30a1b2b66f8a5e464ebf4e9162d993a0c67cd0818911449a91d168b3f
data/bin/mongo_console CHANGED
@@ -4,8 +4,8 @@
4
4
  $LOAD_PATH[0, 0] = File.join(File.dirname(__FILE__), '..', 'lib')
5
5
 
6
6
  require 'mongo'
7
- # include the mongo namespace
8
- include Mongo
7
+ # include the mongo namespace so its constants are available unqualified
8
+ Object.include(Mongo)
9
9
 
10
10
  begin
11
11
  require 'pry'
@@ -24,7 +24,7 @@ module Mongo
24
24
  case address_str
25
25
  when /\A\[[\d:]+\](?::(\d+))?\z/
26
26
  # ipv6 with optional port
27
- if port_str = ::Regexp.last_match(1)
27
+ if (port_str = ::Regexp.last_match(1))
28
28
  validate_port_str!(port_str)
29
29
  end
30
30
  when %r{\A/}, /\.sock\z/
data/lib/mongo/address.rb CHANGED
@@ -302,9 +302,7 @@ module Mongo
302
302
  raise Error::TimeoutError, "#{e.class}: #{e} (for #{self})" if csot
303
303
 
304
304
  raise e
305
- rescue IOError, SystemCallError, ::SocketError => e
306
- raise Error::SocketError, "#{e.class}: #{e} (for #{self})"
307
- rescue OpenSSL::SSL::SSLError => e
305
+ rescue IOError, SystemCallError, ::SocketError, OpenSSL::SSL::SSLError => e
308
306
  raise Error::SocketError, "#{e.class}: #{e} (for #{self})"
309
307
  end
310
308
  end
@@ -74,10 +74,6 @@ module Mongo
74
74
  client_first_data.to_bson.to_s
75
75
  end
76
76
 
77
- def wrap_data(data)
78
- BSON::Binary.new(data.to_bson.to_s)
79
- end
80
-
81
77
  def client_nonce
82
78
  @client_nonce ||= SecureRandom.random_bytes(32)
83
79
  end
@@ -140,14 +140,9 @@ module Mongo
140
140
  # @raise Error::TimeoutError if credentials cannot be retrieved within
141
141
  # the timeout defined on the operation context.
142
142
  def obtain_credentials_from_endpoints(timeout_holder = nil)
143
- if (credentials = web_identity_credentials(timeout_holder)) && credentials_valid?(credentials,
144
- 'Web identity token')
145
- credentials
146
- elsif (credentials = ecs_metadata_credentials(timeout_holder)) && credentials_valid?(credentials,
147
- 'ECS task metadata')
148
- credentials
149
- elsif (credentials = ec2_metadata_credentials(timeout_holder)) && credentials_valid?(credentials,
150
- 'EC2 instance metadata')
143
+ if ((credentials = web_identity_credentials(timeout_holder)) && credentials_valid?(credentials, 'Web identity token')) ||
144
+ ((credentials = ecs_metadata_credentials(timeout_holder)) && credentials_valid?(credentials, 'ECS task metadata')) ||
145
+ ((credentials = ec2_metadata_credentials(timeout_holder)) && credentials_valid?(credentials, 'EC2 instance metadata'))
151
146
  credentials
152
147
  end
153
148
  end
@@ -102,7 +102,7 @@ module Mongo
102
102
  context = Operation::Context.new(options: {
103
103
  server_api: connection.options[:server_api],
104
104
  })
105
- if server_api = context.server_api
105
+ if (server_api = context.server_api)
106
106
  msg = msg.maybe_add_server_api(server_api)
107
107
  end
108
108
  reply = connection.dispatch([ msg ], context)
@@ -71,7 +71,7 @@ module Mongo
71
71
  mechanism: auth_mechanism_name,
72
72
  payload: BSON::Binary.new(payload)
73
73
  )
74
- if options = client_first_message_options
74
+ if (options = client_first_message_options)
75
75
  # Short SCRAM conversation,
76
76
  # https://jira.mongodb.org/browse/DRIVERS-707
77
77
  doc[:options] = options
@@ -200,7 +200,7 @@ module Mongo
200
200
  # This method can be called from different conversation steps
201
201
  # depending on whether the short SCRAM conversation is used.
202
202
  def check_server_signature(payload_data)
203
- return unless verifier = payload_data['v']
203
+ return unless (verifier = payload_data['v'])
204
204
  raise Error::InvalidSignature.new(verifier, server_signature) unless compare_digest(verifier, server_signature)
205
205
 
206
206
  @server_verified = true
@@ -281,13 +281,6 @@ module Mongo
281
281
  # @since 2.0.0
282
282
  attr_reader :iterations
283
283
 
284
- # Get the data from the returned payload.
285
- #
286
- # @api private
287
- #
288
- # @since 2.0.0
289
- attr_reader :payload_data
290
-
291
284
  # Get the server nonce from the payload.
292
285
  #
293
286
  # @api private
@@ -97,12 +97,7 @@ module Mongo
97
97
  end
98
98
 
99
99
  def normalize!(out)
100
- if String.method_defined?(:unicode_normalize!)
101
- out.unicode_normalize!(:nfkc)
102
- else
103
- require 'mongo/auth/stringprep/unicode_normalize/normalize'
104
- out.replace(UnicodeNormalize.normalize(out, :nfkc))
105
- end
100
+ out.unicode_normalize!(:nfkc)
106
101
  end
107
102
 
108
103
  def table_contains?(table, c)
@@ -152,7 +152,7 @@ module Mongo
152
152
  end
153
153
 
154
154
  def execute_operation(options)
155
- client.send(:with_session, options) do |session|
155
+ client.with_session(options) do |session|
156
156
  op = yield session
157
157
  op.execute(next_primary(nil, session), context: Operation::Context.new(client: client, session: session))
158
158
  end
@@ -92,7 +92,7 @@ module Mongo
92
92
 
93
93
  def combine_counts!(result)
94
94
  Result::FIELDS.each do |field|
95
- if result.respond_to?(field) && value = result.send(field)
95
+ if result.respond_to?(field) && (value = result.public_send(field))
96
96
  results.merge!(field => (results[field] || 0) + value)
97
97
  end
98
98
  end
@@ -115,7 +115,7 @@ module Mongo
115
115
  end
116
116
 
117
117
  def combine_write_errors!(result)
118
- if write_errors = result.aggregate_write_errors(count)
118
+ if (write_errors = result.aggregate_write_errors(count))
119
119
  results.merge!(
120
120
  'writeErrors' => ((results['writeErrors'] || []) << write_errors).flatten
121
121
  )
@@ -125,7 +125,7 @@ module Mongo
125
125
  end
126
126
 
127
127
  def combine_write_concern_errors!(result)
128
- return unless write_concern_errors = result.aggregate_write_concern_errors(count)
128
+ return unless (write_concern_errors = result.aggregate_write_concern_errors(count))
129
129
 
130
130
  results['writeConcernErrors'] = (results['writeConcernErrors'] || []) +
131
131
  write_concern_errors
@@ -360,7 +360,7 @@ module Mongo
360
360
  requests_empty = true
361
361
  @requests.each do |req|
362
362
  requests_empty = false
363
- if op = req.keys.first
363
+ if (op = req.keys.first)
364
364
  if %i[update_one update_many].include?(op)
365
365
  if (doc = maybe_first(req.dig(op, :update))) && (key = doc.keys&.first) && !key.to_s.start_with?('$')
366
366
  raise Error::InvalidUpdateDocument.new(key: key) if Mongo.validate_update_replace
data/lib/mongo/client.rb CHANGED
@@ -172,7 +172,6 @@ module Mongo
172
172
  @monitoring
173
173
  end
174
174
  end
175
- private :monitoring
176
175
 
177
176
  # Determine if this client is equivalent to another object.
178
177
  #
@@ -265,6 +264,11 @@ module Mongo
265
264
  # @option options [ Float ] :connect_timeout The timeout, in seconds, to
266
265
  # attempt a connection.
267
266
  # @option options [ String ] :database The database to connect to.
267
+ # @option options [ true | false ] :enable_overload_retargeting Whether
268
+ # the driver deprioritizes a server that returns an overload error,
269
+ # reducing the likelihood of retrying on the same overloaded server.
270
+ # This option works with MongoDB Atlas Server Version 9.0 and above.
271
+ # Default: false.
268
272
  # @option options [ Float ] :heartbeat_frequency The interval, in seconds,
269
273
  # for the server monitor to refresh its description via hello.
270
274
  # @option options [ Object ] :id_generator A custom object to generate ids
@@ -277,6 +281,9 @@ module Mongo
277
281
  # @option options [ String ] :log_prefix A custom log prefix to use when
278
282
  # logging. This option is experimental and subject to change in a future
279
283
  # version of the driver.
284
+ # @option options [ Integer ] :max_adaptive_retries The maximum number of
285
+ # retries to attempt when the driver encounters overload errors. This
286
+ # option works with MongoDB Atlas Server Version 9.0 and above. Default: 2.
280
287
  # @option options [ Integer ] :max_connecting The maximum number of
281
288
  # connections that can be connecting simultaneously. The default is 2.
282
289
  # This option should be increased if there are many threads that share
@@ -288,9 +295,13 @@ module Mongo
288
295
  # @option options [ Integer ] :max_pool_size The maximum size of the
289
296
  # connection pool. Setting this option to zero creates an unlimited connection pool.
290
297
  # @option options [ Integer ] :max_read_retries The maximum number of read
291
- # retries when legacy read retries are in use.
298
+ # retries when legacy read retries are in use. Deprecated: this option
299
+ # only affects the legacy retry implementation, which is deprecated and
300
+ # will be removed in a future version.
292
301
  # @option options [ Integer ] :max_write_retries The maximum number of write
293
- # retries when legacy write retries are in use.
302
+ # retries when legacy write retries are in use. Deprecated: this option
303
+ # only affects the legacy retry implementation, which is deprecated and
304
+ # will be removed in a future version.
294
305
  # @option options [ Integer ] :min_pool_size The minimum size of the
295
306
  # connection pool.
296
307
  # @option options [ true, false ] :monitoring If false is given, the
@@ -325,7 +336,9 @@ module Mongo
325
336
  # - *:local_threshold*.
326
337
  # @option options [ Hash ] :read_concern The read concern option.
327
338
  # @option options [ Float ] :read_retry_interval The interval, in seconds,
328
- # in which reads on a mongos are retried.
339
+ # in which reads on a mongos are retried. Deprecated: this option only
340
+ # affects the legacy retry implementation, which is deprecated and will
341
+ # be removed in a future version.
329
342
  # @option options [ Symbol ] :replica_set The name of the replica set to
330
343
  # connect to. Servers not in this replica set will be ignored.
331
344
  # @option options [ true | false ] :retry_reads If true, modern retryable
@@ -782,10 +795,10 @@ module Mongo
782
795
  def with(new_options = nil)
783
796
  clone.tap do |client|
784
797
  opts = client.update_options(new_options || Options::Redacted.new)
785
- Database.create(client)
798
+ client.reset_database!
786
799
  # We can't use the same cluster if some options that would affect it
787
800
  # have changed.
788
- Cluster.create(client, monitoring: opts[:monitoring]) if cluster_modifying?(opts)
801
+ client.reset_cluster!(monitoring: opts[:monitoring]) if cluster_modifying?(opts)
789
802
  end
790
803
  end
791
804
 
@@ -841,6 +854,31 @@ module Mongo
841
854
  end
842
855
  end
843
856
 
857
+ # Replaces this client's database with a fresh instance built from the
858
+ # client's current options. Used by #with so a reconfigured client does
859
+ # not share its database with the client it was cloned from.
860
+ #
861
+ # @api private
862
+ def reset_database!
863
+ @database = Database.new(self, options[:database], options)
864
+ end
865
+
866
+ # Replaces this client's cluster with a fresh instance built from the
867
+ # client's current options. Used by #with so a reconfigured client does
868
+ # not share its cluster with the client it was cloned from.
869
+ #
870
+ # @param [ Monitoring | nil ] monitoring The monitoring instance to use
871
+ # with the new cluster. If nil, a new instance of Monitoring is created.
872
+ #
873
+ # @api private
874
+ def reset_cluster!(monitoring: nil)
875
+ @cluster = Cluster.new(
876
+ cluster.addresses.map(&:to_s),
877
+ monitoring || Monitoring.new,
878
+ cluster_options
879
+ )
880
+ end
881
+
844
882
  # Get the read concern for this client.
845
883
  #
846
884
  # @example Get the client read concern.
@@ -1159,7 +1197,7 @@ module Mongo
1159
1197
  #
1160
1198
  # @api private
1161
1199
  def with_session(options = {})
1162
- # TODO: Add this back in RUBY-3174.
1200
+ # RUBY-3174 will re-enable this guard; see #assert_not_closed.
1163
1201
  # assert_not_closed
1164
1202
 
1165
1203
  session = get_session(options)
@@ -1397,7 +1435,7 @@ module Mongo
1397
1435
  log_warn("Read concern has invalid keys: #{invalid_keys.join(',')}.") unless invalid_keys.empty?
1398
1436
  end
1399
1437
 
1400
- if server_api = opts[:server_api]
1438
+ if (server_api = opts[:server_api])
1401
1439
  raise ArgumentError, ":server_api value must be a hash: #{server_api}" unless server_api.is_a?(Hash)
1402
1440
 
1403
1441
  extra_keys = server_api.keys - %w[version strict deprecation_errors]
@@ -1444,7 +1482,28 @@ module Mongo
1444
1482
  # Validates all options after they are set on the client.
1445
1483
  # This method is intended to catch combinations of options which are
1446
1484
  # not allowed.
1485
+ # Issues a deprecation warning for each legacy retry tuning option that is
1486
+ # explicitly set. These options only affect the legacy retry
1487
+ # implementation, which is deprecated and will be removed in a future
1488
+ # version. Modern retryable reads and writes (enabled by default) ignore
1489
+ # them.
1490
+ def deprecate_legacy_retry_options!
1491
+ %i[max_read_retries read_retry_interval max_write_retries].each do |key|
1492
+ next unless options.key?(key)
1493
+
1494
+ Mongo::Deprecations.warn(
1495
+ "legacy_retry_option_#{key}",
1496
+ "The :#{key} option is deprecated. It only affects the legacy retry " \
1497
+ 'implementation, which is deprecated and will be removed in a future ' \
1498
+ 'version. Modern retryable reads and writes are enabled by default ' \
1499
+ 'and do not use this option.'
1500
+ )
1501
+ end
1502
+ end
1503
+
1447
1504
  def validate_options!(addresses = nil, is_srv: nil)
1505
+ deprecate_legacy_retry_options!
1506
+
1448
1507
  if options[:write] && options[:write_concern] && options[:write] != options[:write_concern]
1449
1508
  raise ArgumentError, "If :write and :write_concern are both given, they must be identical: #{options.inspect}"
1450
1509
  end
@@ -1502,12 +1561,12 @@ module Mongo
1502
1561
  end
1503
1562
 
1504
1563
  %i[connect_timeout socket_timeout].each do |key|
1505
- next unless value = options[key]
1564
+ next unless (value = options[key])
1506
1565
  raise ArgumentError, "#{key} must be a non-negative number: #{value}" unless value.is_a?(Numeric)
1507
1566
  raise ArgumentError, "#{key} must be a non-negative number: #{value}" if value < 0
1508
1567
  end
1509
1568
 
1510
- if value = options[:bg_error_backtrace]
1569
+ if (value = options[:bg_error_backtrace])
1511
1570
  case value
1512
1571
  when Integer
1513
1572
  if value <= 0
@@ -1522,7 +1581,7 @@ module Mongo
1522
1581
  end
1523
1582
  end
1524
1583
 
1525
- if libraries = options[:wrapping_libraries]
1584
+ if (libraries = options[:wrapping_libraries])
1526
1585
  unless libraries.is_a?(Array)
1527
1586
  raise ArgumentError, ":wrapping_libraries must be an array of hashes: #{libraries}"
1528
1587
  end
@@ -1684,7 +1743,7 @@ module Mongo
1684
1743
  "the read preference must be specified as a hash: { mode: #{read.inspect} }")
1685
1744
  end
1686
1745
 
1687
- if mode = read[:mode]
1746
+ if (mode = read[:mode])
1688
1747
  mode = mode.to_sym
1689
1748
  unless Mongo::ServerSelector::PREFERENCES.include?(mode)
1690
1749
  raise Error::InvalidReadOption.new(read, "mode #{mode} is not one of recognized modes")
@@ -1694,6 +1753,17 @@ module Mongo
1694
1753
  true
1695
1754
  end
1696
1755
 
1756
+ # Raises Error::ClientClosed if this client has been closed.
1757
+ #
1758
+ # This is the guard for RUBY-3174 (disallow closed clients from
1759
+ # performing operations). The implementation is complete but not yet
1760
+ # wired in: the intended call site in #with_session is currently
1761
+ # commented out, pending that ticket. Do not delete this method or
1762
+ # Error::ClientClosed as "unused" -- both are here deliberately.
1763
+ #
1764
+ # @raise [ Error::ClientClosed ] if the client has been closed.
1765
+ #
1766
+ # @api private
1697
1767
  def assert_not_closed
1698
1768
  return unless closed?
1699
1769
 
@@ -101,7 +101,7 @@ module Mongo
101
101
  #
102
102
  # @api private
103
103
  def read_scheduled_kill_specs
104
- while kill_spec = @kill_spec_queue.pop(true)
104
+ while (kill_spec = @kill_spec_queue.pop(true))
105
105
  if @active_cursor_ids.include?(kill_spec.cursor_id)
106
106
  @to_kill[kill_spec.server_address] ||= Set.new
107
107
  @to_kill[kill_spec.server_address] << kill_spec
@@ -188,14 +188,21 @@ module Mongo
188
188
  server_api: server.options[:server_api],
189
189
  connection_global_id: kill_spec.connection_global_id,
190
190
  }
191
- if connection = kill_spec.connection
192
- op.execute_with_connection(connection, context: Operation::Context.new(options: options))
193
- connection.connection_pool.check_in(connection)
191
+ if (connection = kill_spec.connection)
192
+ begin
193
+ op.execute_with_connection(connection, context: Operation::Context.new(options: options))
194
+ rescue Error::SocketError, Error::SocketTimeoutError, Error::ConnectionPerished
195
+ # Connection is dead. do_check_in will detect connection.error?
196
+ # and disconnect it; the pool slot becomes free for a new connection.
197
+ ensure
198
+ connection.unpin(:cursor)
199
+ connection.connection_pool.check_in(connection) unless connection.pinned?
200
+ end
194
201
  else
195
202
  op.execute(server, context: Operation::Context.new(options: options))
196
203
  end
197
204
 
198
- next unless session = kill_spec.session
205
+ next unless (session = kill_spec.session)
199
206
 
200
207
  session.end_session if session.implicit?
201
208
  end
@@ -385,8 +385,8 @@ class Mongo::Cluster
385
385
  def add_servers_from_desc(updated_desc)
386
386
  added_servers = []
387
387
  %w[hosts passives arbiters].each do |m|
388
- updated_desc.send(m).each do |address_str|
389
- if server = cluster.add(address_str, monitor: false)
388
+ updated_desc.public_send(m).each do |address_str|
389
+ if (server = cluster.add(address_str, monitor: false))
390
390
  added_servers << server
391
391
  end
392
392
  end
@@ -402,7 +402,7 @@ class Mongo::Cluster
402
402
  # good primary).
403
403
  def remove_servers_not_in_desc(updated_desc)
404
404
  updated_desc_address_strs = %w[hosts passives arbiters].map do |m|
405
- updated_desc.send(m)
405
+ updated_desc.public_send(m)
406
406
  end.flatten
407
407
  servers_list.each do |server|
408
408
  next if updated_desc_address_strs.include?(address_str = server.address.to_s)
@@ -541,7 +541,7 @@ class Mongo::Cluster
541
541
  end
542
542
 
543
543
  def disconnect_servers
544
- while server = @servers_to_disconnect.shift
544
+ while (server = @servers_to_disconnect.shift)
545
545
  if server.connected?
546
546
  # Do not publish server closed event, as this was already done
547
547
  server.disconnect!
@@ -85,7 +85,7 @@ module Mongo
85
85
  # LST is only read from data-bearing servers
86
86
  if desc.data_bearing?
87
87
  @have_data_bearing_servers = true
88
- break unless timeout = desc.logical_session_timeout
88
+ break unless (timeout = desc.logical_session_timeout)
89
89
 
90
90
  [ timeout, min || timeout ].min
91
91
  else
data/lib/mongo/cluster.rb CHANGED
@@ -269,30 +269,6 @@ module Mongo
269
269
  start_stop_srv_monitor
270
270
  end
271
271
 
272
- # Create a cluster for the provided client, for use when we don't want the
273
- # client's original cluster instance to be the same.
274
- #
275
- # @example Create a cluster for the client.
276
- # Cluster.create(client)
277
- #
278
- # @param [ Client ] client The client to create on.
279
- # @param [ Monitoring | nil ] monitoring. The monitoring instance to use
280
- # with the new cluster. If nil, a new instance of Monitoring will be
281
- # created.
282
- #
283
- # @return [ Cluster ] The cluster.
284
- #
285
- # @since 2.0.0
286
- # @api private
287
- def self.create(client, monitoring: nil)
288
- cluster = Cluster.new(
289
- client.cluster.addresses.map(&:to_s),
290
- monitoring || Monitoring.new,
291
- client.cluster_options
292
- )
293
- client.instance_variable_set(:@cluster, cluster)
294
- end
295
-
296
272
  # @return [ Hash ] The options hash.
297
273
  attr_reader :options
298
274
 
@@ -324,9 +300,7 @@ module Mongo
324
300
  # @api private
325
301
  attr_reader :seeds
326
302
 
327
- # @private
328
- #
329
- # @since 2.5.1
303
+ # @api private
330
304
  attr_reader :session_pool
331
305
 
332
306
  def_delegators :topology, :replica_set?, :replica_set_name, :sharded?,
@@ -802,7 +776,7 @@ module Mongo
802
776
  #
803
777
  # @since 2.5.0
804
778
  def update_cluster_time(result)
805
- return unless cluster_time_doc = result.cluster_time
779
+ return unless (cluster_time_doc = result.cluster_time)
806
780
 
807
781
  @cluster_time_lock.synchronize do
808
782
  advance_cluster_time(cluster_time_doc)
@@ -983,6 +957,16 @@ module Mongo
983
957
  end
984
958
  end
985
959
 
960
+ # Forces the cluster's periodic executor to run immediately. If the cluster
961
+ # has no periodic executor, this method does nothing.
962
+ #
963
+ # @api private
964
+ def trigger_periodic_executor!
965
+ return unless @periodic_executor
966
+
967
+ @periodic_executor.execute
968
+ end
969
+
986
970
  private
987
971
 
988
972
  # @api private
@@ -85,7 +85,7 @@ module Mongo
85
85
  end
86
86
 
87
87
  def server_selector
88
- @view.send(:server_selector)
88
+ @view.server_selector
89
89
  end
90
90
 
91
91
  def aggregate_spec(session, read_preference = nil)
@@ -104,10 +104,8 @@ module Mongo
104
104
 
105
105
  primary_read_preference = { mode: :primary }
106
106
  description = connection.description
107
- if description.primary?
108
- log_warn('Routing the Aggregation operation to the primary server')
109
- primary_read_preference
110
- elsif description.mongos? && !description.features.merge_out_on_secondary_enabled?
107
+ if description.primary? ||
108
+ (description.mongos? && !description.features.merge_out_on_secondary_enabled?)
111
109
  log_warn('Routing the Aggregation operation to the primary server')
112
110
  primary_read_preference
113
111
  else
@@ -105,7 +105,7 @@ module Mongo
105
105
  raise ArgumentError, "Unknown view class: #{view}"
106
106
  end
107
107
  command[:pipeline] = pipeline
108
- if read_concern = view.read_concern
108
+ if (read_concern = view.read_concern) && !read_concern.empty?
109
109
  command[:readConcern] = Options::Mapper.transform_values_to_strings(
110
110
  read_concern
111
111
  )
@@ -117,12 +117,10 @@ module Mongo
117
117
 
118
118
  def batch_size_doc
119
119
  value = options[:batch_size] || view.batch_size
120
- if value == 0 && write?
120
+ if value.nil? || (value == 0 && write?)
121
121
  {}
122
- elsif value
123
- { batchSize: value }
124
122
  else
125
- {}
123
+ { batchSize: value }
126
124
  end
127
125
  end
128
126
  end
@@ -92,7 +92,7 @@ module Mongo
92
92
  private
93
93
 
94
94
  def write?(spec)
95
- return unless out = spec[:selector][:out]
95
+ return unless (out = spec[:selector][:out])
96
96
 
97
97
  out.is_a?(String) ||
98
98
  (out.respond_to?(:keys) && out.keys.first.to_s.downcase != View::MapReduce::INLINE)
@@ -351,19 +351,24 @@ module Mongo
351
351
  # In load balanced topology, manually check out a connection
352
352
  # so it remains checked out and pinned to the cursor.
353
353
  connection = server.pool.check_out(context: context)
354
- result = send_initial_query(connection, context)
355
-
356
- start_at_operation_time = if doc = result.replies.first && result.replies.first.documents.first
357
- doc['operationTime']
358
- else
359
- nil
360
- end
361
- result
354
+ begin
355
+ result = send_initial_query(connection, context)
356
+
357
+ start_at_operation_time = if (doc = result.replies.first && result.replies.first.documents.first)
358
+ doc['operationTime']
359
+ else
360
+ nil
361
+ end
362
+ result
363
+ rescue StandardError
364
+ server.pool.check_in(connection)
365
+ raise
366
+ end
362
367
  else
363
368
  server.with_connection do |connection|
364
369
  result = send_initial_query(connection, context)
365
370
 
366
- start_at_operation_time = if doc = result.replies.first && result.replies.first.documents.first
371
+ start_at_operation_time = if (doc = result.replies.first && result.replies.first.documents.first)
367
372
  doc['operationTime']
368
373
  else
369
374
  # The above may set @start_at_operation_time to nil
@@ -227,7 +227,7 @@ module Mongo
227
227
  #
228
228
  # @since 2.5.0
229
229
  def execute
230
- view.send(:with_session, @options) do |session|
230
+ view.with_session(@options) do |session|
231
231
  write_concern = view.write_concern_with_session(session)
232
232
  context = Operation::Context.new(client: client, session: session)
233
233
  nro_write_with_retry(write_concern, context: context) do |connection, _txn_num, context|
@@ -241,7 +241,7 @@ module Mongo
241
241
  OUT_ACTIONS = %i[replace merge reduce].freeze
242
242
 
243
243
  def server_selector
244
- @view.send(:server_selector)
244
+ @view.server_selector
245
245
  end
246
246
 
247
247
  def inline?
@@ -299,15 +299,6 @@ module Mongo
299
299
  end
300
300
  end
301
301
 
302
- def fetch_query_spec
303
- Builder::MapReduce.new(map_function, reduce_function, view, options).query_specification
304
- end
305
-
306
- def find_command_spec(session)
307
- Builder::MapReduce.new(map_function, reduce_function, view,
308
- options.merge(session: session)).command_specification
309
- end
310
-
311
302
  def fetch_query_op(session)
312
303
  spec = {
313
304
  coll_name: out_collection_name,