Skip to content

Commit af7f0ae

Browse files
authored
RUBY-3552 Deprecate support for server version 3.6 (#2978)
* RUBY-3552 Deprecate support for server version 3.6 Adds a new Mongo::Deprecations module as well * feedback from copilot * extend, not include (for Ruby 2.7) * reverse the prefix-match logic so it actually works
1 parent 00d1b86 commit af7f0ae

File tree

4 files changed

+156
-8
lines changed

4 files changed

+156
-8
lines changed

lib/mongo.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
require 'mongo/csot_timeout_holder'
4343
require 'mongo/options'
4444
require 'mongo/loggable'
45+
require 'mongo/deprecations'
4546
require 'mongo/cluster_time'
4647
require 'mongo/topology_version'
4748
require 'mongo/monitoring'

lib/mongo/deprecations.rb

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

lib/mongo/server/description/features.rb

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,44 @@ class Features
7474
SERVER_TOO_OLD = "Server at (%s) reports wire version (%s), but this version of the Ruby driver " +
7575
"requires at least (%s)."
7676

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+
7782
# Error message if the driver is too old for the version of the server.
7883
#
7984
# @since 2.5.0
8085
DRIVER_TOO_OLD = "Server at (%s) requires wire version (%s), but this version of the Ruby driver " +
8186
"only supports up to (%s)."
8287

88+
# An empty range constant, for use in DEPRECATED_WIRE_VERSIONS.
89+
EMPTY_RANGE = (0...0).freeze
90+
8391
# The wire protocol versions that this version of the driver supports.
8492
#
8593
# @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..6
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
87115

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

133161
# 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.
138164
#
139165
# @raise [ Error::UnsupportedFeatures ] If the wire version range is
140166
# not covered by the driver.
141-
#
142-
# @since 2.5.1
143167
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
145173
raise Error::UnsupportedFeatures.new(SERVER_TOO_OLD % [@address,
146174
@server_wire_versions.max,
147175
DRIVER_WIRE_VERSIONS.min])
176+
148177
elsif DRIVER_WIRE_VERSIONS.max < @server_wire_versions.min
149178
raise Error::UnsupportedFeatures.new(DRIVER_TOO_OLD % [@address,
150179
@server_wire_versions.min,

spec/mongo/server/description/features_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,26 @@
3535
end
3636
end
3737

38+
if described_class::DEPRECATED_WIRE_VERSIONS.any?
39+
context 'when the max server wire version range is deprecated' do
40+
before do
41+
Mongo::Deprecations.clear!
42+
end
43+
44+
let(:wire_versions) do
45+
(described_class::DEPRECATED_WIRE_VERSIONS.min - 1)..described_class::DEPRECATED_WIRE_VERSIONS.max
46+
end
47+
48+
it 'issues a deprecation warning' do
49+
expect {
50+
features.check_driver_support!
51+
}.to change {
52+
Mongo::Deprecations.warned?("wire_version:#{default_address}")
53+
}.from(false).to(true)
54+
end
55+
end
56+
end
57+
3858
context 'when the server wire version range max is higher' do
3959

4060
let(:wire_versions) do

0 commit comments

Comments
 (0)