Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/mongo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
require 'mongo/csot_timeout_holder'
require 'mongo/options'
require 'mongo/loggable'
require 'mongo/deprecations'
require 'mongo/cluster_time'
require 'mongo/topology_version'
require 'mongo/monitoring'
Expand Down
98 changes: 98 additions & 0 deletions lib/mongo/deprecations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# frozen_string_literal: true

require 'mongo/loggable'

module Mongo
# Used for reporting deprecated behavior in the driver. When it is possible
# to detect that a deprecated feature is being used, a warning should be issued
# through this module.
#
# The warning will be issued no more than once for that feature, regardless
# of how many times Mongo::Deprecations.warn is called.
#
# @example Issue a deprecation warning.
# Mongo::Deprecations.warn(:old_feature, "The old_feature is deprecated, use new_feature instead.")
#
# @api private
module Deprecations
extend self
extend Mongo::Loggable

# Mutex for synchronizing access to warned features.
# @api private
MUTEX = Thread::Mutex.new

# Issue a warning about a deprecated feature. The warning is written to the
# logger, and will not be written more than once per feature.
#
# @param [ String | Symbol ] feature The deprecated feature.
# @param [ String ] message The deprecation message.
def warn(feature, message)
MUTEX.synchronize do
return if _warned?(feature)

_warned!(feature)
log_warn("[DEPRECATION:#{feature}] #{message}")
end
end

# Check if a warning for a given deprecated feature has already been issued.
#
# @param [ String | Symbol ] feature The deprecated feature.
# @param [ true | false ] prefix Whether to check for prefix matches.
#
# @return [ true | false ] If a warning has already been issued.
def warned?(feature, prefix: false)
MUTEX.synchronize { _warned?(feature, prefix: prefix) }
end

# Mark that a warning for a given deprecated feature has been issued.
#
# @param [ String | Symbol ] feature The deprecated feature.
def warned!(feature)
MUTEX.synchronize { _warned!(feature) }
nil
end

# Clears all memory of previously warned features.
def clear!
MUTEX.synchronize { warned_features reset: true }
nil
end

private

# Set of features that have already been warned about.
#
# @param [ true | false ] reset Whether to reset the warned features.
#
# @return [ Set<String> ] The set of warned features.
def warned_features(reset: false)
@warned_features = nil if reset
@warned_features ||= Set.new
end

# Check if a warning for a given deprecated feature has already been issued.
# This version is not thread-safe.
#
# @param [ String | Symbol ] feature The deprecated feature.
# @param [ true | false ] prefix Whether to check for prefix matches.
#
# @return [ true | false ] If a warning has already been issued.
def _warned?(feature, prefix: false)
if prefix
warned_features.any? { |f| f.to_s.start_with?(feature) }
else
warned_features.include?(feature.to_s)
end
end

# Mark that a warning for a given deprecated feature has been issued.
# This version is not thread-safe.
#
# @param [ String | Symbol ] feature The deprecated feature.
def _warned!(feature)
warned_features.add(feature.to_s)
end
end
end
45 changes: 37 additions & 8 deletions lib/mongo/server/description/features.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,44 @@ class Features
SERVER_TOO_OLD = "Server at (%s) reports wire version (%s), but this version of the Ruby driver " +
"requires at least (%s)."

# Warning message if the server version is deprecated.
SERVER_DEPRECATED = 'Server at (%s) reports wire version (%s), but support for that wire version ' \
'is deprecated and will be removed in a future version of the Ruby driver. ' \
'Please upgrade your MongoDB server to a newer version soon.'

# Error message if the driver is too old for the version of the server.
#
# @since 2.5.0
DRIVER_TOO_OLD = "Server at (%s) requires wire version (%s), but this version of the Ruby driver " +
"only supports up to (%s)."

# An empty range constant, for use in DEPRECATED_WIRE_VERSIONS.
EMPTY_RANGE = (0...0).freeze

# The wire protocol versions that this version of the driver supports.
#
# @since 2.0.0
DRIVER_WIRE_VERSIONS = (6..25).freeze
DRIVER_WIRE_VERSIONS = 6..25

# The wire protocol versions that are deprecated in this version of the
# driver. Support for these versions will be removed in the future.
#
# If there are multiple currently-deprecated wire versions, this should
# be set to a range of those versions.
#
# If there is only a single currently-deprecated wire version, this should
# be set to a range where the min and max are the same value.
#
# If there are no currently-deprecated wire versions, this should be
# set to an empty range (e.g. the EMPTY_RANGE constant).
DEPRECATED_WIRE_VERSIONS = 6..6

# make sure the deprecated versions are valid
if DEPRECATED_WIRE_VERSIONS.min
if DRIVER_WIRE_VERSIONS.min > DEPRECATED_WIRE_VERSIONS.max
raise ArgumentError, 'DEPRECATED_WIRE_VERSIONS must be empty, or be within DRIVER_WIRE_VERSIONS'
end
end

# Create the methods for each mapping to tell if they are supported.
#
Expand Down Expand Up @@ -131,20 +159,21 @@ def initialize(server_wire_versions, address = nil)
end

# Check that there is an overlap between the driver supported wire
# version range and the server wire version range.
#
# @example Verify the wire version overlap.
# features.check_driver_support!
# version range and the server wire version range. Also checks to see
# if the server is using a deprecated wire version.
#
# @raise [ Error::UnsupportedFeatures ] If the wire version range is
# not covered by the driver.
#
# @since 2.5.1
def check_driver_support!
if DRIVER_WIRE_VERSIONS.min > @server_wire_versions.max
if DEPRECATED_WIRE_VERSIONS.include?(@server_wire_versions.max)
feature = "wire_version:#{@address}"
Mongo::Deprecations.warn(feature, SERVER_DEPRECATED % [@address, @server_wire_versions.max])

elsif DRIVER_WIRE_VERSIONS.min > @server_wire_versions.max
raise Error::UnsupportedFeatures.new(SERVER_TOO_OLD % [@address,
@server_wire_versions.max,
DRIVER_WIRE_VERSIONS.min])

elsif DRIVER_WIRE_VERSIONS.max < @server_wire_versions.min
raise Error::UnsupportedFeatures.new(DRIVER_TOO_OLD % [@address,
@server_wire_versions.min,
Expand Down
20 changes: 20 additions & 0 deletions spec/mongo/server/description/features_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@
end
end

if described_class::DEPRECATED_WIRE_VERSIONS.any?
context 'when the max server wire version range is deprecated' do
before do
Mongo::Deprecations.clear!
end

let(:wire_versions) do
(described_class::DEPRECATED_WIRE_VERSIONS.min - 1)..described_class::DEPRECATED_WIRE_VERSIONS.max
end

it 'issues a deprecation warning' do
expect {
features.check_driver_support!
}.to change {
Mongo::Deprecations.warned?("wire_version:#{default_address}")
}.from(false).to(true)
end
end
end

context 'when the server wire version range max is higher' do

let(:wire_versions) do
Expand Down
Loading