mongo 2.22.0 → 2.23.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mongo/client.rb +40 -4
  3. data/lib/mongo/cluster.rb +4 -1
  4. data/lib/mongo/collection/view/aggregation/behavior.rb +1 -1
  5. data/lib/mongo/collection/view/aggregation.rb +5 -2
  6. data/lib/mongo/collection/view/iterable.rb +16 -14
  7. data/lib/mongo/collection/view/readable.rb +64 -55
  8. data/lib/mongo/collection/view/writable.rb +52 -46
  9. data/lib/mongo/collection/view.rb +2 -0
  10. data/lib/mongo/collection.rb +56 -46
  11. data/lib/mongo/config.rb +4 -0
  12. data/lib/mongo/crypt/auto_decryption_context.rb +9 -0
  13. data/lib/mongo/crypt/binding.rb +1 -1
  14. data/lib/mongo/crypt/context.rb +10 -0
  15. data/lib/mongo/crypt/explicit_decryption_context.rb +9 -0
  16. data/lib/mongo/database/view.rb +25 -20
  17. data/lib/mongo/database.rb +17 -10
  18. data/lib/mongo/deprecations.rb +98 -0
  19. data/lib/mongo/index/view.rb +28 -19
  20. data/lib/mongo/operation/create.rb +4 -0
  21. data/lib/mongo/operation/insert/op_msg.rb +5 -2
  22. data/lib/mongo/operation/shared/executable.rb +11 -4
  23. data/lib/mongo/operation/shared/specifiable.rb +5 -1
  24. data/lib/mongo/search_index/view.rb +29 -9
  25. data/lib/mongo/server/app_metadata/platform.rb +17 -4
  26. data/lib/mongo/server/connection.rb +18 -0
  27. data/lib/mongo/server/description/features.rb +37 -8
  28. data/lib/mongo/server.rb +2 -1
  29. data/lib/mongo/session.rb +55 -19
  30. data/lib/mongo/srv/monitor.rb +5 -1
  31. data/lib/mongo/srv/result.rb +14 -4
  32. data/lib/mongo/tracing/open_telemetry/command_tracer.rb +320 -0
  33. data/lib/mongo/tracing/open_telemetry/operation_tracer.rb +227 -0
  34. data/lib/mongo/tracing/open_telemetry/tracer.rb +236 -0
  35. data/lib/mongo/tracing/open_telemetry.rb +27 -0
  36. data/lib/mongo/tracing.rb +42 -0
  37. data/lib/mongo/uri/srv_protocol.rb +11 -6
  38. data/lib/mongo/version.rb +1 -1
  39. data/lib/mongo.rb +3 -0
  40. metadata +8 -2
@@ -1216,7 +1216,7 @@ module Mongo
1216
1216
  # TODO since the binary references a C pointer, and ByteBuffer is
1217
1217
  # written in C in MRI, we could omit a copy of the data by making
1218
1218
  # ByteBuffer reference the string that is owned by libmongocrypt.
1219
- BSON::Document.from_bson(BSON::ByteBuffer.new(binary.to_s), mode: :bson)
1219
+ BSON::Document.from_bson(BSON::ByteBuffer.new(binary.to_s), mode: context.bson_mode)
1220
1220
  end
1221
1221
 
1222
1222
  # @!method self.mongocrypt_ctx_destroy(ctx)
@@ -109,6 +109,16 @@ module Mongo
109
109
  end
110
110
  end
111
111
 
112
+ # Which BSON mode to use when creating documents from the outcome of
113
+ # the state machine. The default is :bson, which creates BSON::Document
114
+ # with BSON types. Subclasses may override this method to
115
+ # change this behavior.
116
+ #
117
+ # @return [ Symbol, nil ] The BSON mode.
118
+ def bson_mode
119
+ :bson
120
+ end
121
+
112
122
  private
113
123
 
114
124
  def provide_markings(timeout_ms)
@@ -38,6 +38,15 @@ module Mongo
38
38
  # explicit decryption
39
39
  Binding.ctx_explicit_decrypt_init(self, doc)
40
40
  end
41
+
42
+ # Which BSON mode to use when creating documents from the outcome of
43
+ # the state machine. The returned value is based on the
44
+ # +Mongo::Config.csfle_convert_to_ruby_types+ option.
45
+ #
46
+ # @return [ Symbol, nil ] The BSON mode.
47
+ def bson_mode
48
+ Mongo::Config.csfle_convert_to_ruby_types ? nil : :bson
49
+ end
41
50
  end
42
51
  end
43
52
  end
@@ -45,6 +45,8 @@ module Mongo
45
45
  # @return [ Collection ] collection The command collection.
46
46
  attr_reader :collection
47
47
 
48
+ def_delegators :@database, :tracer
49
+
48
50
  # Get all the names of the non-system collections in the database.
49
51
  #
50
52
  # @note The set of returned collection names depends on the version of
@@ -214,27 +216,30 @@ module Mongo
214
216
  session: session,
215
217
  operation_timeouts: operation_timeouts(options)
216
218
  )
217
- cursor = read_with_retry_cursor(session, server_selector, self, context: context) do |server|
218
- # TODO take description from the connection used to send the query
219
- # once https://jira.mongodb.org/browse/RUBY-1601 is fixed.
220
- description = server.description
221
- send_initial_query(server, session, context, options)
222
- end
223
- # On 3.0+ servers, we get just the collection names.
224
- # On 2.6 server, we get collection names prefixed with the database
225
- # name. We need to filter system collections out here because
226
- # in the caller we don't know which server version executed the
227
- # command and thus what the proper filtering logic should be
228
- # (it is valid for collection names to have dots, thus filtering out
229
- # collections named system.* here for 2.6 servers would actually
230
- # filter out collections in the system database).
231
- if description.server_version_gte?('3.0')
232
- cursor.reject do |doc|
233
- doc['name'].start_with?('system.') || doc['name'].include?('$')
219
+ op = initial_query_op(session, options)
220
+ tracer.trace_operation(op, context, op_name: 'listCollections') do
221
+ cursor = read_with_retry_cursor(session, server_selector, self, context: context) do |server|
222
+ # TODO take description from the connection used to send the query
223
+ # once https://jira.mongodb.org/browse/RUBY-1601 is fixed.
224
+ description = server.description
225
+ send_initial_query(server, session, context, options)
234
226
  end
235
- else
236
- cursor.reject do |doc|
237
- doc['name'].start_with?("#{database.name}.system") || doc['name'].include?('$')
227
+ # On 3.0+ servers, we get just the collection names.
228
+ # On 2.6 server, we get collection names prefixed with the database
229
+ # name. We need to filter system collections out here because
230
+ # in the caller we don't know which server version executed the
231
+ # command and thus what the proper filtering logic should be
232
+ # (it is valid for collection names to have dots, thus filtering out
233
+ # collections named system.* here for 2.6 servers would actually
234
+ # filter out collections in the system database).
235
+ if description.server_version_gte?('3.0')
236
+ cursor.reject do |doc|
237
+ doc['name'].start_with?('system.') || doc['name'].include?('$')
238
+ end
239
+ else
240
+ cursor.reject do |doc|
241
+ doc['name'].start_with?("#{database.name}.system") || doc['name'].include?('$')
242
+ end
238
243
  end
239
244
  end
240
245
  end
@@ -74,7 +74,8 @@ module Mongo
74
74
  :server_selector,
75
75
  :read_concern,
76
76
  :write_concern,
77
- :encrypted_fields_map
77
+ :encrypted_fields_map,
78
+ :tracer
78
79
 
79
80
  # @return [ Mongo::Server ] Get the primary server from the cluster.
80
81
  def_delegators :cluster,
@@ -267,10 +268,12 @@ module Mongo
267
268
  # @option opts :session [ Session ] The session to use for this command.
268
269
  # @option opts [ Object ] :comment A user-provided
269
270
  # comment to attach to this command.
270
- # @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
271
+ # @option opts [ Integer ] :timeout_ms The operation timeout in milliseconds.
271
272
  # Must be a non-negative integer. An explicit value of 0 means infinite.
272
273
  # The default value is unset which means the value is inherited from
273
274
  # the database or the client.
275
+ # @option opts :op_name [ String | nil ] The name of the operation for
276
+ # tracing purposes.
274
277
  #
275
278
  # @return [ Hash ] The result of the command execution.
276
279
  # @api private
@@ -290,14 +293,18 @@ module Mongo
290
293
  session: session,
291
294
  operation_timeouts: operation_timeouts(opts)
292
295
  )
293
- read_with_retry(session, preference, context) do |server|
294
- Operation::Command.new(
295
- selector: operation.dup,
296
- db_name: name,
297
- read: preference,
298
- session: session,
299
- comment: opts[:comment],
300
- ).execute(server, context: context)
296
+ operation = Operation::Command.new(
297
+ selector: operation.dup,
298
+ db_name: name,
299
+ read: preference,
300
+ session: session,
301
+ comment: opts[:comment],
302
+ )
303
+ op_name = opts[:op_name] || 'command'
304
+ tracer.trace_operation(operation, context, op_name: op_name) do
305
+ read_with_retry(session, preference, context) do |server|
306
+ operation.execute(server, context: context)
307
+ end
301
308
  end
302
309
  end
303
310
  end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mongo/loggable'
4
+
5
+ module Mongo
6
+ # Used for reporting deprecated behavior in the driver. When it is possible
7
+ # to detect that a deprecated feature is being used, a warning should be issued
8
+ # through this module.
9
+ #
10
+ # The warning will be issued no more than once for that feature, regardless
11
+ # of how many times Mongo::Deprecations.warn is called.
12
+ #
13
+ # @example Issue a deprecation warning.
14
+ # Mongo::Deprecations.warn(:old_feature, "The old_feature is deprecated, use new_feature instead.")
15
+ #
16
+ # @api private
17
+ module Deprecations
18
+ extend self
19
+ extend Mongo::Loggable
20
+
21
+ # Mutex for synchronizing access to warned features.
22
+ # @api private
23
+ MUTEX = Thread::Mutex.new
24
+
25
+ # Issue a warning about a deprecated feature. The warning is written to the
26
+ # logger, and will not be written more than once per feature.
27
+ #
28
+ # @param [ String | Symbol ] feature The deprecated feature.
29
+ # @param [ String ] message The deprecation message.
30
+ def warn(feature, message)
31
+ MUTEX.synchronize do
32
+ return if _warned?(feature)
33
+
34
+ _warned!(feature)
35
+ log_warn("[DEPRECATION:#{feature}] #{message}")
36
+ end
37
+ end
38
+
39
+ # Check if a warning for a given deprecated feature has already been issued.
40
+ #
41
+ # @param [ String | Symbol ] feature The deprecated feature.
42
+ # @param [ true | false ] prefix Whether to check for prefix matches.
43
+ #
44
+ # @return [ true | false ] If a warning has already been issued.
45
+ def warned?(feature, prefix: false)
46
+ MUTEX.synchronize { _warned?(feature, prefix: prefix) }
47
+ end
48
+
49
+ # Mark that a warning for a given deprecated feature has been issued.
50
+ #
51
+ # @param [ String | Symbol ] feature The deprecated feature.
52
+ def warned!(feature)
53
+ MUTEX.synchronize { _warned!(feature) }
54
+ nil
55
+ end
56
+
57
+ # Clears all memory of previously warned features.
58
+ def clear!
59
+ MUTEX.synchronize { warned_features reset: true }
60
+ nil
61
+ end
62
+
63
+ private
64
+
65
+ # Set of features that have already been warned about.
66
+ #
67
+ # @param [ true | false ] reset Whether to reset the warned features.
68
+ #
69
+ # @return [ Set<String> ] The set of warned features.
70
+ def warned_features(reset: false)
71
+ @warned_features = nil if reset
72
+ @warned_features ||= Set.new
73
+ end
74
+
75
+ # Check if a warning for a given deprecated feature has already been issued.
76
+ # This version is not thread-safe.
77
+ #
78
+ # @param [ String | Symbol ] feature The deprecated feature.
79
+ # @param [ true | false ] prefix Whether to check for prefix matches.
80
+ #
81
+ # @return [ true | false ] If a warning has already been issued.
82
+ def _warned?(feature, prefix: false)
83
+ if prefix
84
+ warned_features.any? { |f| f.to_s.start_with?(feature) }
85
+ else
86
+ warned_features.include?(feature.to_s)
87
+ end
88
+ end
89
+
90
+ # Mark that a warning for a given deprecated feature has been issued.
91
+ # This version is not thread-safe.
92
+ #
93
+ # @param [ String | Symbol ] feature The deprecated feature.
94
+ def _warned!(feature)
95
+ warned_features.add(feature.to_s)
96
+ end
97
+ end
98
+ end
@@ -45,6 +45,7 @@ module Mongo
45
45
 
46
46
  def_delegators :@collection, :cluster, :database, :read_preference, :write_concern, :client
47
47
  def_delegators :cluster, :next_primary
48
+ def_delegators :client, :tracer
48
49
 
49
50
  # The index key field.
50
51
  #
@@ -221,9 +222,7 @@ module Mongo
221
222
  end
222
223
 
223
224
  client.with_session(@options.merge(options)) do |session|
224
- server = next_primary(nil, session)
225
-
226
- indexes = normalize_models(models, server)
225
+ indexes = normalize_models(models)
227
226
  indexes.each do |index|
228
227
  if index[:bucketSize] || index['bucketSize']
229
228
  client.log_warn("Haystack indexes (bucketSize index option) are deprecated as of MongoDB 4.4")
@@ -244,7 +243,11 @@ module Mongo
244
243
  session: session,
245
244
  operation_timeouts: operation_timeouts(options)
246
245
  )
247
- Operation::CreateIndex.new(spec).execute(server, context: context)
246
+ operation = Operation::CreateIndex.new(spec)
247
+ tracer.trace_operation(operation, context, op_name: 'createIndexes') do
248
+ server = next_primary(nil, session)
249
+ operation.execute(server, context: context)
250
+ end
248
251
  end
249
252
  end
250
253
 
@@ -283,16 +286,18 @@ module Mongo
283
286
  session: session,
284
287
  operation_timeouts: operation_timeouts(@options)
285
288
  )
286
-
287
- cursor = read_with_retry_cursor(session, ServerSelector.primary, self, context: context) do |server|
288
- send_initial_query(server, session, context)
289
- end
290
- if block_given?
291
- cursor.each do |doc|
292
- yield doc
289
+ op = initial_query_op(session)
290
+ tracer.trace_operation(op, context, op_name: 'listIndexes') do
291
+ cursor = read_with_retry_cursor(session, ServerSelector.primary, self, context: context) do |server|
292
+ send_initial_query(op, server, session, context)
293
+ end
294
+ if block_given?
295
+ cursor.each do |doc|
296
+ yield doc
297
+ end
298
+ else
299
+ cursor.to_enum
293
300
  end
294
- else
295
- cursor.to_enum
296
301
  end
297
302
  end
298
303
 
@@ -359,13 +364,17 @@ module Mongo
359
364
  write_concern: write_concern,
360
365
  }
361
366
  spec[:comment] = opts[:comment] unless opts[:comment].nil?
362
- server = next_primary(nil, session)
363
367
  context = Operation::Context.new(
364
368
  client: client,
365
369
  session: session,
366
370
  operation_timeouts: operation_timeouts(opts)
367
371
  )
368
- Operation::DropIndex.new(spec).execute(server, context: context)
372
+ op = Operation::DropIndex.new(spec)
373
+ op_name = name == Index::ALL ? 'dropIndexes' : 'dropIndex'
374
+ tracer.trace_operation(op, context, op_name: op_name) do
375
+ server = next_primary(nil, session)
376
+ op.execute(server, context: context)
377
+ end
369
378
  end
370
379
  end
371
380
 
@@ -394,7 +403,7 @@ module Mongo
394
403
  Options::Mapper.transform_keys_to_strings(spec)
395
404
  end
396
405
 
397
- def normalize_models(models, server)
406
+ def normalize_models(models)
398
407
  models.map do |model|
399
408
  # Transform options first which gives us a mutable hash
400
409
  Options::Mapper.transform(model, OPTIONS).tap do |model|
@@ -403,12 +412,12 @@ module Mongo
403
412
  end
404
413
  end
405
414
 
406
- def send_initial_query(server, session, context)
415
+ def send_initial_query(op, server, session, context)
407
416
  if server.load_balancer?
408
417
  connection = server.pool.check_out(context: context)
409
- initial_query_op(session).execute_with_connection(connection, context: context)
418
+ op.execute_with_connection(connection, context: context)
410
419
  else
411
- initial_query_op(session).execute(server, context: context)
420
+ op.execute(server, context: context)
412
421
  end
413
422
  end
414
423
  end
@@ -28,6 +28,10 @@ module Mongo
28
28
  class Create
29
29
  include Specifiable
30
30
  include OpMsgExecutable
31
+
32
+ def encrypted_fields=(value)
33
+ @spec[:encrypted_fields] = value
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -34,8 +34,11 @@ module Mongo
34
34
  private
35
35
 
36
36
  def get_result(connection, context, options = {})
37
- # This is a Mongo::Operation::Insert::Result
38
- Result.new(*dispatch_message(connection, context), @ids, context: context)
37
+ message = build_message(connection, context)
38
+ connection.tracer.trace_command(message, context, connection) do
39
+ result = Result.new(*dispatch_message(message, connection, context), @ids, context: context)
40
+ yield result
41
+ end
39
42
  end
40
43
 
41
44
  def selector(connection)
@@ -45,7 +45,7 @@ module Mongo
45
45
  add_error_labels(connection, context) do
46
46
  check_for_network_error do
47
47
  add_server_diagnostics(connection) do
48
- get_result(connection, context, options).tap do |result|
48
+ get_result(connection, context, options) do |result|
49
49
  if session
50
50
  if session.in_transaction? &&
51
51
  connection.description.load_balancer?
@@ -104,12 +104,19 @@ module Mongo
104
104
  end
105
105
 
106
106
  def get_result(connection, context, options = {})
107
- result_class.new(*dispatch_message(connection, context, options), context: context, connection: connection)
107
+ message = build_message(connection, context)
108
+ connection.tracer.trace_command(message, context, connection) do
109
+ result = result_class.new(*dispatch_message(message, connection, context, options), context: context, connection: connection)
110
+ if block_given?
111
+ yield result
112
+ else
113
+ result
114
+ end
115
+ end
108
116
  end
109
117
 
110
118
  # Returns a Protocol::Message or nil as reply.
111
- def dispatch_message(connection, context, options = {})
112
- message = build_message(connection, context)
119
+ def dispatch_message(message, connection, context, options = {})
113
120
  message = message.maybe_encrypt(connection, context)
114
121
  reply = connection.dispatch([ message ], context, options)
115
122
  [reply, connection.description, connection.global_id]
@@ -233,7 +233,7 @@ module Mongo
233
233
  #
234
234
  # @since 2.0.0
235
235
  def coll_name
236
- spec.fetch(COLL_NAME)
236
+ spec[COLL_NAME]
237
237
  end
238
238
 
239
239
  # The id of the cursor created on the server.
@@ -526,6 +526,10 @@ module Mongo
526
526
  @spec[:txn_num]
527
527
  end
528
528
 
529
+ def txn_num=(num)
530
+ @spec[:txn_num] = num
531
+ end
532
+
529
533
  # The command.
530
534
  #
531
535
  # @return [ Hash ] The command.
@@ -4,6 +4,7 @@ module Mongo
4
4
  module SearchIndex
5
5
  # A class representing a view of search indexes.
6
6
  class View
7
+ extend Forwardable
7
8
  include Enumerable
8
9
  include Retryable
9
10
  include Collection::Helpers
@@ -21,6 +22,8 @@ module Mongo
21
22
  # when querying the available indexes.
22
23
  attr_reader :aggregate_options
23
24
 
25
+ def_delegators :@collection, :tracer
26
+
24
27
  # Create the new search index view.
25
28
  #
26
29
  # @param [ Collection ] collection The collection.
@@ -46,23 +49,33 @@ module Mongo
46
49
  #
47
50
  # @param [ Hash ] definition The definition of the search index.
48
51
  # @param [ nil | String ] name The name to give the new search index.
52
+ # @param [ String ] type The type of the search index. Possible values
53
+ # are 'search' and 'vectorSearch'. The default is 'search'.
49
54
  #
50
55
  # @return [ String ] the name of the new search index.
51
56
  def create_one(definition, name: nil, type: 'search')
52
- create_many([ { name: name, definition: definition, type: type } ]).first
57
+ spec = { definition: definition, type: type }.tap do |sp|
58
+ sp[:name] = name unless name.nil?
59
+ end
60
+ create_many([ spec ]).first
53
61
  end
54
62
 
55
63
  # Create multiple search indexes with a single command.
56
64
  #
57
65
  # @param [ Array<Hash> ] indexes The description of the indexes to
58
66
  # create. Each element of the list must be a hash with a definition
59
- # key, and an optional name key.
67
+ # key, an optional name key, and an optional type key. The type key
68
+ # must be one of 'search' or 'vectorSearch'. The default is 'search'.
60
69
  #
61
70
  # @return [ Array<String> ] the names of the new search indexes.
62
71
  def create_many(indexes)
63
72
  spec = spec_with(indexes: indexes.map { |v| validate_search_index!(v) })
64
- result = Operation::CreateSearchIndexes.new(spec).execute(next_primary, context: execution_context)
65
- result.first['indexesCreated'].map { |idx| idx['name'] }
73
+ operation = Operation::CreateSearchIndexes.new(spec)
74
+ context = execution_context
75
+ tracer.trace_operation(operation, context, op_name: 'createSearchIndexes') do
76
+ result = operation.execute(next_primary, context: context)
77
+ result.first['indexesCreated'].map { |idx| idx['name'] }
78
+ end
66
79
  end
67
80
 
68
81
  # Drop the search index with the given id, or name. One or the other must
@@ -78,11 +91,14 @@ module Mongo
78
91
 
79
92
  spec = spec_with(index_id: id, index_name: name)
80
93
  op = Operation::DropSearchIndex.new(spec)
94
+ context = execution_context
81
95
 
82
- # per the spec:
83
- # Drivers MUST suppress NamespaceNotFound errors for the
84
- # ``dropSearchIndex`` helper. Drop operations should be idempotent.
85
- do_drop(op, nil, execution_context)
96
+ tracer.trace_operation(op, context, op_name: 'dropSearchIndex') do
97
+ # per the spec:
98
+ # Drivers MUST suppress NamespaceNotFound errors for the
99
+ # ``dropSearchIndex`` helper. Drop operations should be idempotent.
100
+ do_drop(op, nil, context)
101
+ end
86
102
  end
87
103
 
88
104
  # Iterate over the search indexes.
@@ -124,7 +140,11 @@ module Mongo
124
140
  validate_id_or_name!(id, name)
125
141
 
126
142
  spec = spec_with(index_id: id, index_name: name, index: definition)
127
- Operation::UpdateSearchIndex.new(spec).execute(next_primary, context: execution_context)
143
+ op = Operation::UpdateSearchIndex.new(spec)
144
+ context = execution_context
145
+ tracer.trace_operation(op, context, op_name: 'updateSearchIndex') do
146
+ op.execute(next_primary, context: context)
147
+ end
128
148
  end
129
149
 
130
150
  # The following methods are to make the view act more like an array,
@@ -34,21 +34,34 @@ module Mongo
34
34
  @metadata = metadata
35
35
  end
36
36
 
37
+ # Queries whether the current runtime is Ruby MRI or not.
38
+ #
39
+ # @return [ true | false ] whether the runtime is Ruby MRI or not.
40
+ def mri?
41
+ RUBY_ENGINE == 'ruby'
42
+ end
43
+
37
44
  # Queries whether the current runtime is JRuby or not.
38
45
  #
39
46
  # @return [ true | false ] whether the runtime is JRuby or not.
40
47
  def jruby?
41
- BSON::Environment.jruby?
48
+ RUBY_ENGINE == 'jruby'
49
+ end
50
+
51
+ ENGINE_NAMES = { 'jruby' => 'JRuby', 'truffleruby' => 'TruffleRuby' }.freeze
52
+
53
+ def engine_name
54
+ ENGINE_NAMES[RUBY_ENGINE] || RUBY_ENGINE
42
55
  end
43
56
 
44
57
  # Returns the list of Ruby versions that identify this runtime.
45
58
  #
46
59
  # @return [ Array<String> ] the list of ruby versions
47
60
  def ruby_versions
48
- if jruby?
49
- [ "JRuby #{JRUBY_VERSION}", "like Ruby #{RUBY_VERSION}" ]
50
- else
61
+ if mri?
51
62
  [ "Ruby #{RUBY_VERSION}" ]
63
+ else
64
+ [ "#{engine_name} #{RUBY_ENGINE_VERSION}", "like Ruby #{RUBY_VERSION}" ]
52
65
  end
53
66
  end
54
67
 
@@ -139,6 +139,8 @@ module Mongo
139
139
  # across all connections.
140
140
  attr_reader :global_id
141
141
 
142
+ def_delegators :server, :tracer
143
+
142
144
  # The connection pool from which this connection was created.
143
145
  # May be nil.
144
146
  #
@@ -388,6 +390,22 @@ module Mongo
388
390
  self
389
391
  end
390
392
 
393
+ # Get the transport type for this connection.
394
+ #
395
+ # @return [ Symbol | nil ] The transport type, :tcp or :unix, or nil
396
+ # if no socket.
397
+ # @api private
398
+ def transport
399
+ return nil if @socket.nil?
400
+
401
+ case @socket
402
+ when Mongo::Socket::Unix
403
+ :unix
404
+ else
405
+ :tcp
406
+ end
407
+ end
408
+
391
409
  private
392
410
 
393
411
  def deliver(message, client, options = {})
@@ -74,16 +74,44 @@ module Mongo
74
74
  SERVER_TOO_OLD = "Server at (%s) reports wire version (%s), but this version of the Ruby driver " +
75
75
  "requires at least (%s)."
76
76
 
77
+ # Warning message if the server version is deprecated.
78
+ SERVER_DEPRECATED = 'Server at (%s) reports wire version (%s), but support for that wire version ' \
79
+ 'is deprecated and will be removed in a future version of the Ruby driver. ' \
80
+ 'Please upgrade your MongoDB server to a newer version soon.'
81
+
77
82
  # Error message if the driver is too old for the version of the server.
78
83
  #
79
84
  # @since 2.5.0
80
85
  DRIVER_TOO_OLD = "Server at (%s) requires wire version (%s), but this version of the Ruby driver " +
81
86
  "only supports up to (%s)."
82
87
 
88
+ # An empty range constant, for use in DEPRECATED_WIRE_VERSIONS.
89
+ EMPTY_RANGE = (0...0).freeze
90
+
83
91
  # The wire protocol versions that this version of the driver supports.
84
92
  #
85
93
  # @since 2.0.0
86
- DRIVER_WIRE_VERSIONS = (6..25).freeze
94
+ DRIVER_WIRE_VERSIONS = 6..25
95
+
96
+ # The wire protocol versions that are deprecated in this version of the
97
+ # driver. Support for these versions will be removed in the future.
98
+ #
99
+ # If there are multiple currently-deprecated wire versions, this should
100
+ # be set to a range of those versions.
101
+ #
102
+ # If there is only a single currently-deprecated wire version, this should
103
+ # be set to a range where the min and max are the same value.
104
+ #
105
+ # If there are no currently-deprecated wire versions, this should be
106
+ # set to an empty range (e.g. the EMPTY_RANGE constant).
107
+ DEPRECATED_WIRE_VERSIONS = 6..7
108
+
109
+ # make sure the deprecated versions are valid
110
+ if DEPRECATED_WIRE_VERSIONS.min
111
+ if DRIVER_WIRE_VERSIONS.min > DEPRECATED_WIRE_VERSIONS.max
112
+ raise ArgumentError, 'DEPRECATED_WIRE_VERSIONS must be empty, or be within DRIVER_WIRE_VERSIONS'
113
+ end
114
+ end
87
115
 
88
116
  # Create the methods for each mapping to tell if they are supported.
89
117
  #
@@ -131,20 +159,21 @@ module Mongo
131
159
  end
132
160
 
133
161
  # Check that there is an overlap between the driver supported wire
134
- # version range and the server wire version range.
135
- #
136
- # @example Verify the wire version overlap.
137
- # features.check_driver_support!
162
+ # version range and the server wire version range. Also checks to see
163
+ # if the server is using a deprecated wire version.
138
164
  #
139
165
  # @raise [ Error::UnsupportedFeatures ] If the wire version range is
140
166
  # not covered by the driver.
141
- #
142
- # @since 2.5.1
143
167
  def check_driver_support!
144
- if DRIVER_WIRE_VERSIONS.min > @server_wire_versions.max
168
+ if DEPRECATED_WIRE_VERSIONS.include?(@server_wire_versions.max)
169
+ feature = "wire_version:#{@address}"
170
+ Mongo::Deprecations.warn(feature, SERVER_DEPRECATED % [@address, @server_wire_versions.max])
171
+
172
+ elsif DRIVER_WIRE_VERSIONS.min > @server_wire_versions.max
145
173
  raise Error::UnsupportedFeatures.new(SERVER_TOO_OLD % [@address,
146
174
  @server_wire_versions.max,
147
175
  DRIVER_WIRE_VERSIONS.min])
176
+
148
177
  elsif DRIVER_WIRE_VERSIONS.max < @server_wire_versions.min
149
178
  raise Error::UnsupportedFeatures.new(DRIVER_TOO_OLD % [@address,
150
179
  @server_wire_versions.min,