Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b45049a
working toward removing 3.6 and 4.0 server support
jamis Feb 6, 2026
f77e133
another test updated
jamis Feb 6, 2026
32bf1d7
database_spec.rb
jamis Feb 6, 2026
ea5851a
more specs
jamis Feb 6, 2026
cd7ef1f
another test
jamis Feb 6, 2026
76b4dad
moar
jamis Feb 6, 2026
25fae16
map/reduce
jamis Feb 6, 2026
76aa2d7
and moar
jamis Feb 6, 2026
8760b62
more specs
jamis Feb 9, 2026
f1cd979
more specs
jamis Feb 9, 2026
99a6bb7
more specs
jamis Feb 9, 2026
1f64590
cleaning up references to old server versions
jamis Feb 9, 2026
478f8b4
more specs and stuff
jamis Feb 10, 2026
34a1c55
removing references to 4.0 and older
jamis Feb 10, 2026
3f3a3f6
removing 4.0/4.2 constraints
jamis Feb 10, 2026
c3a23f7
more shenanigans
jamis Feb 10, 2026
82a7830
mmapv1 references
jamis Feb 10, 2026
d6b28f4
Merge branch 'master' into 3381-3640-eol-3.6-4.0
jamis Feb 10, 2026
fa72920
module was removed
jamis Feb 10, 2026
c8d2200
copilot feedback
jamis Feb 10, 2026
7f2a3a1
fix typo
jamis Feb 10, 2026
7ff282f
avoid pulling the entire cursor into memory unnecessarily
jamis Feb 10, 2026
8e5e3a7
remove test for checking mmapv1 behavior
jamis Feb 10, 2026
a634548
correctly identify/mock connections without session support
jamis Feb 11, 2026
e3e47cc
fail commands are well-supported now; also sync sdam specs
jamis Feb 11, 2026
08b475d
fail commands are still required
jamis Feb 12, 2026
e26cef5
accidentally deleted something
jamis Feb 13, 2026
a873623
bump spec/shared
jamis Feb 13, 2026
55d8718
Remove unused FCV axis, and DB versions
jamis Feb 20, 2026
0f878c9
try and fix flaky test by bringing it in sync with specifications repo
jamis Feb 20, 2026
9ba7854
correctly interpret $$lte as "less than OR EQUAL TO"
jamis Feb 20, 2026
e357879
skip failing spec (caused by RUBY-3781)
jamis Feb 23, 2026
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
16 changes: 0 additions & 16 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -804,22 +804,6 @@ axes:
variables:
MONGODB_VERSION: "4.2"
CRYPT_SHARED_VERSION: "6.0.5"
- id: "4.0"
display_name: "4.0"
variables:
MONGODB_VERSION: "4.0"
- id: "3.6"
display_name: "3.6"
variables:
MONGODB_VERSION: "3.6"

- id: fcv
display_name: FCV
values:
- id: '3.4'
display_name: '3.4'
variables:
FCV: '3.4'

- id: "topology"
display_name: Topology
Expand Down
16 changes: 0 additions & 16 deletions .evergreen/config/axes.yml.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,6 @@ axes:
variables:
MONGODB_VERSION: "4.2"
CRYPT_SHARED_VERSION: "6.0.5"
- id: "4.0"
display_name: "4.0"
variables:
MONGODB_VERSION: "4.0"
- id: "3.6"
display_name: "3.6"
variables:
MONGODB_VERSION: "3.6"

- id: fcv
display_name: FCV
values:
- id: '3.4'
display_name: '3.4'
variables:
FCV: '3.4'

- id: "topology"
display_name: Topology
Expand Down
2 changes: 1 addition & 1 deletion lib/mongo/auth/conversation_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def speculative_auth_document

# @return [ Protocol::Message ] The message to send.
def build_message(connection, auth_source, selector)
if connection && connection.features.op_msg_enabled?
if connection
selector = selector.dup
selector[Protocol::Msg::DATABASE_IDENTIFIER] = auth_source
cluster_time = connection.mongos? && connection.cluster_time
Expand Down
3 changes: 1 addition & 2 deletions lib/mongo/auth/stringprep.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
module Mongo
module Auth
# This namespace contains all behavior related to string preparation
# (RFC 3454). It's used to implement SCRAM-SHA-256 authentication,
# which is available in MongoDB server versions 4.0 and later.
# (RFC 3454). It's used to implement SCRAM-SHA-256 authentication.
#
# @since 2.6.0
# @api private
Expand Down
29 changes: 4 additions & 25 deletions lib/mongo/bulk_write.rb
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,6 @@ def base_spec(operation_id, session)
end

def execute_operation(name, values, connection, context, operation_id, result_combiner, session, txn_num = nil)
validate_collation!(connection)
validate_array_filters!(connection)
validate_hint!(connection)

unpin_maybe(session, connection) do
Expand All @@ -234,13 +232,9 @@ def execute_operation(name, values, connection, context, operation_id, result_co
end
end
end
# With OP_MSG (3.6+ servers), the size of each section in the message
# The size of each section in the message
# is independently capped at 16m and each bulk operation becomes
# its own section. The size of the entire bulk write is limited to 48m.
# With OP_QUERY (pre-3.6 servers), the entire bulk write is sent as a
# single document and is thus subject to the 16m document size limit.
# This means the splits differ between pre-3.6 and 3.6+ servers, with
# 3.6+ servers being able to split less.
rescue Error::MaxBSONSize, Error::MaxMessageSize => e
raise e if values.size <= 1
unpin_maybe(session, connection) do
Expand Down Expand Up @@ -297,33 +291,19 @@ def update_many(documents, connection, context, operation_id, session, txn_num)

private

def validate_collation!(connection)
if op_combiner.has_collation? && !connection.features.collation_enabled?
raise Error::UnsupportedCollation.new
end
end

def validate_array_filters!(connection)
if op_combiner.has_array_filters? && !connection.features.array_filters_enabled?
raise Error::UnsupportedArrayFilters.new
end
end

def validate_hint!(connection)
if op_combiner.has_hint?
if !can_hint?(connection) && write_concern && !write_concern.acknowledged?
raise Error::UnsupportedOption.hint_error(unacknowledged_write: true)
elsif !connection.features.update_delete_option_validation_enabled?
raise Error::UnsupportedOption.hint_error
end
end
end

# Loop through the requests and check if each operation is allowed to send
# a hint for each operation on the given server version.
#
# For the following operations, the client can send a hint for servers >= 4.2
# and for the rest, the client can only send it for 4.4+:
# For the following operations, the client can send a hint for all supported
# server versions, and for the rest, the client can only send it for 4.4+:
# - updateOne
# - updateMany
# - replaceOne
Expand All @@ -333,13 +313,12 @@ def validate_hint!(connection)
# @return [ true | false ] Whether the request is able to send hints for
# the current server version.
def can_hint?(connection)
gte_4_2 = connection.server.description.server_version_gte?('4.2')
gte_4_4 = connection.server.description.server_version_gte?('4.4')
op_combiner.requests.all? do |req|
op = req.keys.first
if req[op].keys.include?(:hint)
if [:update_one, :update_many, :replace_one].include?(op)
gte_4_2
true
else
gte_4_4
end
Expand Down
2 changes: 1 addition & 1 deletion lib/mongo/bulk_write/unordered_combiner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class BulkWrite
#
# @since 2.1.0
class UnorderedCombiner
include Transformable
include Validatable
include Transformable
include Combineable

# Combine the requests in order.
Expand Down
12 changes: 4 additions & 8 deletions lib/mongo/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,7 @@ def hash
# analogous options present in the URI string.
#
# @option options [ String, Symbol ] :app_name Application name that is
# printed to the mongod logs upon establishing a connection in server
# versions >= 3.4.
# printed to the mongod logs upon establishing a connection
# @option options [ Symbol ] :auth_mech The authentication mechanism to
# use. One of :mongodb_cr, :mongodb_x509, :plain, :scram, :scram256
# @option options [ Hash ] :auth_mech_properties
Expand Down Expand Up @@ -308,7 +307,6 @@ def hash
# @option options [ String ] :password The user's password.
# @option options [ String ] :platform Platform information to include in
# the metadata printed to the mongod logs upon establishing a connection
# in server versions >= 3.4.
# @option options [ Hash ] :read The read preference options. The hash
# may have the following items:
# - *:mode* -- read preference specified as a symbol; valid values are
Expand All @@ -325,7 +323,7 @@ def hash
# reads are enabled (which is the default). If false, modern retryable
# reads are disabled and legacy retryable reads are enabled.
# @option options [ true | false ] :retry_writes Retry writes once when
# connected to a replica set or sharded cluster versions 3.6 and up.
# connected to a replica set or sharded cluster.
# (Default is true.)
# @option options [ true | false ] :scan Whether to scan all seeds
# in constructor. The default in driver version 2.x is to do so;
Expand Down Expand Up @@ -1045,9 +1043,8 @@ def start_session(options = {})
end
end

# As of version 3.6 of the MongoDB server, a ``$changeStream`` pipeline stage is supported
# in the aggregation framework. As of version 4.0, this stage allows users to request that
# notifications are sent for all changes that occur in the client's cluster.
# Allows users to request that notifications are sent for all changes that
# occur in the client's cluster.
#
# @example Get change notifications for the client's cluster.
# client.watch([{ '$match' => { operationType: { '$in' => ['insert', 'replace'] } } }])
Expand Down Expand Up @@ -1093,7 +1090,6 @@ def start_session(options = {})
# @option options [ BSON::Timestamp ] :start_at_operation_time Only return
# changes that occurred at or after the specified timestamp. Any command run
# against the server will return a cluster time that can be used here.
# Only recognized by server versions 4.0+.
# @option options [ Object ] :comment A user-provided
# comment to attach to this command.
# @option options [ Boolean ] :show_expanded_events Enables the server to
Expand Down
11 changes: 4 additions & 7 deletions lib/mongo/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,8 @@ def aggregate(pipeline, options = {})
View.new(self, {}, options).aggregate(pipeline, options)
end

# As of version 3.6 of the MongoDB server, a ``$changeStream`` pipeline
# stage is supported in the aggregation framework. This stage allows users
# to request that notifications are sent for all changes to a particular
# collection.
# Allows users to request that notifications are sent for all changes
# to a particular collection.
#
# @example Get change notifications for a given collection.
# collection.watch([{ '$match' => { operationType: { '$in' => ['insert', 'replace'] } } }])
Expand Down Expand Up @@ -627,7 +625,6 @@ def aggregate(pipeline, options = {})
# @option options [ BSON::Timestamp ] :start_at_operation_time Only return
# changes that occurred at or after the specified timestamp. Any command run
# against the server will return a cluster time that can be used here.
# Only recognized by server versions 4.0+.
# @option options [ Object ] :comment A user-provided
# comment to attach to this command.
# @option options [ Boolean ] :show_expanded_events Enables the server to
Expand Down Expand Up @@ -686,7 +683,7 @@ def watch(pipeline = [], options = {})
#
# @deprecated Use #count_documents or estimated_document_count instead. However, note that the
# following operators will need to be substituted when switching to #count_documents:
# * $where should be replaced with $expr (only works on 3.6+)
# * $where should be replaced with $expr
# * $near should be replaced with $geoWithin with $center
# * $nearSphere should be replaced with $geoWithin with $centerSphere
def count(filter = nil, options = {})
Expand All @@ -706,7 +703,7 @@ def count(filter = nil, options = {})
#
# @option options :skip [ Integer ] The number of documents to skip.
# @option options :hint [ Hash ] Override default index selection and force
# MongoDB to use a specific index for the query. Requires server version 3.6+.
# MongoDB to use a specific index for the query.
# @option options :limit [ Integer ] Max number of docs to count.
# @option options :max_time_ms [ Integer ] The maximum amount of time to allow the
# command to run.
Expand Down
23 changes: 2 additions & 21 deletions lib/mongo/collection/view/change_stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,6 @@ class View
# that notifications are sent for all changes to a particular collection
# or database.
#
# @note Only available in server versions 3.6 and higher.
# @note ChangeStreams do not work properly with JRuby because of the
# issue documented here: https://github.com/jruby/jruby/issues/4212.
# Namely, JRuby eagerly evaluates #next on an Enumerator in a background
# green thread, therefore calling #next on the change stream will cause
# getMores to be called in a loop in the background.
#
#
# @since 2.5.0
class ChangeStream
include Aggregation::Behavior
Expand Down Expand Up @@ -114,7 +106,7 @@ class ChangeStream
# @option options [ BSON::Timestamp ] :start_at_operation_time Only
# return changes that occurred at or after the specified timestamp. Any
# command run against the server will return a cluster time that can
# be used here. Only recognized by server versions 4.0+.
# be used here.
# @option options [ Bson::Document, Hash ] :start_after Similar to :resume_after, this
# option takes a resume token and starts a new change stream returning the first
# notification after the token. This will allow users to watch collections that have been
Expand Down Expand Up @@ -340,18 +332,13 @@ def for_collection?
def create_cursor!(timeout_ms = nil)
# clear the cache because we may get a newer or an older server
# (rolling upgrades)
@start_at_operation_time_supported = nil

session = client.get_session(@options)
context = Operation::Context.new(client: client, session: session, view: self, operation_timeouts: timeout_ms ? { operation_timeout_ms: timeout_ms } : operation_timeouts)

start_at_operation_time = nil
start_at_operation_time_supported = nil

@cursor = read_with_retry_cursor(session, server_selector, self, context: context) do |server|
server.with_connection do |connection|
start_at_operation_time_supported = connection.description.server_version_gte?('4.0')

result = send_initial_query(connection, context)

if doc = result.replies.first && result.replies.first.documents.first
Expand All @@ -369,7 +356,6 @@ def create_cursor!(timeout_ms = nil)
end

@start_at_operation_time = start_at_operation_time
@start_at_operation_time_supported = start_at_operation_time_supported
end

def pipeline
Expand Down Expand Up @@ -405,12 +391,7 @@ def change_doc
# Spec says we need to remove both startAtOperationTime and startAfter if
# either was passed in by user, thus we won't forward them
doc[:resumeAfter] = resume_token
elsif @start_at_operation_time_supported && @start_at_operation_time
# It is crucial to check @start_at_operation_time_supported
# here - we may have switched to an older server that
# does not support operation times and therefore shouldn't
# try to send one to it!
#
elsif @start_at_operation_time
# @start_at_operation_time is already a BSON::Timestamp
doc[:startAtOperationTime] = @start_at_operation_time
else
Expand Down
16 changes: 6 additions & 10 deletions lib/mongo/collection/view/explainable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@ module Explainable
# @example Get the query plan for the query with execution statistics.
# view.explain(verbosity: :execution_stats)
#
# @option opts [ true | false ] :verbose The level of detail
# to return for MongoDB 2.6 servers.
# @option opts [ String | Symbol ] :verbosity The type of information
# to return for MongoDB 3.0 and newer servers. If the value is a
# symbol, it will be stringified and converted from underscore
# style to camel case style (e.g. :query_planner => "queryPlanner").
# to return. If the value is a symbol, it will be stringified and
# converted from underscore style to camel case style
# (e.g. :query_planner => "queryPlanner").
#
# @return [ Hash ] A single document with the query plan.
#
Expand All @@ -66,12 +64,10 @@ def explained?
!!options[:explain]
end

# @option opts [ true | false ] :verbose The level of detail
# to return for MongoDB 2.6 servers.
# @option opts [ String | Symbol ] :verbosity The type of information
# to return for MongoDB 3.0 and newer servers. If the value is a
# symbol, it will be stringified and converted from underscore
# style to camel case style (e.g. :query_planner => "queryPlanner").
# to return. If the value is a symbol, it will be stringified and
# converted from underscore style to camel case style
# (e.g. :query_planner => "queryPlanner").
def explain_options(**opts)
explain_limit = limit || 0
# Note: opts will never be nil here.
Expand Down
13 changes: 7 additions & 6 deletions lib/mongo/collection/view/iterable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ def each

limit_for_cached_query = compute_limit_for_cached_query

# Ruby versions 2.5 and older do not support arr[0..nil] syntax, so
# this must be a separate conditional.
# TODO: rather than pulling the entire (limited) result set into
# memory, this should tell the cursor about the limit and then let
# the cursor limit the iteration as necessary.
cursor_to_iterate = if limit_for_cached_query
@cursor.to_a[0...limit_for_cached_query]
else
@cursor
end
@cursor.to_a[0...limit_for_cached_query]
else
@cursor
end

cursor_to_iterate.each do |doc|
yield doc
Expand Down
6 changes: 3 additions & 3 deletions lib/mongo/collection/view/map_reduce.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class MapReduce
#
# @since 2.1.0
# @deprecated
REROUTE = 'Rerouting the MapReduce operation to the primary server.'.freeze
REROUTE = 'Rerouting the MapReduce operation to the primary server'.freeze

# @return [ View ] view The collection view.
attr_reader :view
Expand Down Expand Up @@ -124,7 +124,7 @@ def initialize(view, map, reduce, options = {})
@reduce_function = reduce.dup.freeze
@options = BSON::Document.new(options).freeze

client.log_warn('The map_reduce operation is deprecated, please use the aggregation pipeline instead')
Deprecations.warn(:map_reduce, 'The map_reduce operation is deprecated, please use the aggregation pipeline instead.')
end

# Set or get the jsMode flag for the operation.
Expand Down Expand Up @@ -298,7 +298,7 @@ def send_initial_query_with_connection(connection, session, context:)
if valid_server?(connection.description)
op.execute_with_connection(connection, context: context)
else
msg = "Rerouting the MapReduce operation to the primary server - #{connection.address} is not suitable because it is not currently the primray"
msg = "#{REROUTE} - #{connection.address} is not suitable because it is not currently the primary"
log_warn(msg)
server = cluster.next_primary(nil, session)
op.execute(server, context: context)
Expand Down
Loading
Loading