lib/mongo/server_selector/selectable.rb in mongo-2.6.4 vs lib/mongo/server_selector/selectable.rb in mongo-2.7.0.rc0
- old
+ new
@@ -1,6 +1,6 @@
-# Copyright (C) 2014-2018 MongoDB, Inc.
+# Copyright (C) 2014-2019 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
@@ -58,10 +58,14 @@
#
# @param [ Hash ] options The server preference options.
#
# @option options [ Integer ] :local_threshold The local threshold boundary for
# nearest selection in seconds.
+ # @option options [ Integer ] max_staleness The maximum replication lag,
+ # in seconds, that a secondary can suffer and still be eligible for a read.
+ # A value of -1 is treated identically to nil, which is to not
+ # have a maximum staleness.
#
# @raise [ Error::InvalidServerPreference ] If tag sets are specified
# but not allowed.
#
# @since 2.0.0
@@ -98,23 +102,41 @@
@local_threshold = cluster.options[:local_threshold] || LOCAL_THRESHOLD
@server_selection_timeout = cluster.options[:server_selection_timeout] || SERVER_SELECTION_TIMEOUT
deadline = Time.now + server_selection_timeout
while (deadline - Time.now) > 0
servers = candidates(cluster)
+ if Lint.enabled?
+ servers.each do |server|
+ if server.average_round_trip_time.nil?
+ raise Error::LintError, "Server #{server.address} has nil average rtt"
+ end
+ end
+ end
if servers && !servers.compact.empty?
+ unless cluster.topology.compatible?
+ raise Error::UnsupportedFeatures, cluster.topology.compatibility_error.to_s
+ end
+
+ # This list of servers may be ordered in a specific way
+ # by the selector (e.g. for secondary preferred, the first
+ # server may be a secondary and the second server may be primary)
+ # and we should take the first server here respecting the order
server = servers.first
- # HACK: all servers in a topology must satisfy wire protocol
- # constraints. There is probably a better implementation than
- # checking all servers here
- cluster.servers.each do |a_server|
- a_server.check_driver_support!
+
+ if cluster.topology.single? &&
+ cluster.topology.replica_set_name &&
+ cluster.topology.replica_set_name != server.description.replica_set_name
+ then
+ msg = "Cluster topology specifies replica set name #{cluster.topology.replica_set_name}, but the server has replica set name #{server.description.replica_set_name || '<nil>'}"
+ raise Error::NoServerAvailable.new(self, cluster, msg)
end
+
return server
end
- cluster.scan!
+ cluster.scan!(false)
end
- raise Error::NoServerAvailable.new(self)
+ raise Error::NoServerAvailable.new(self, cluster)
end
# Get the timeout for server selection.
#
# @example Get the server selection timeout, in seconds.
@@ -193,10 +215,14 @@
# @since 2.0.0
def secondaries(candidates)
matching_servers = candidates.select(&:secondary?)
matching_servers = filter_stale_servers(matching_servers, primary(candidates).first)
matching_servers = match_tag_sets(matching_servers) unless tag_sets.empty?
+ # Per server selection spec the server selected MUST be a random
+ # one matching staleness and latency requirements.
+ # Selectors always pass the output of #secondaries to #nearest
+ # which shuffles the server list, fulfilling this requirement.
matching_servers
end
# Select the near servers from a list of provided candidates, taking the
# local threshold into account.
@@ -231,25 +257,24 @@
matches || []
end
def filter_stale_servers(candidates, primary = nil)
return candidates unless @max_staleness
- max_staleness_ms = @max_staleness * 1000
if primary
candidates.select do |server|
validate_max_staleness_support!(server)
staleness = (server.last_scan - server.last_write_date) -
(primary.last_scan - primary.last_write_date) +
- (server.heartbeat_frequency_seconds * 1000)
- staleness <= max_staleness_ms
+ server.heartbeat_frequency_seconds
+ staleness <= @max_staleness
end
else
max_write_date = candidates.collect(&:last_write_date).max
candidates.select do |server|
validate_max_staleness_support!(server)
- staleness = max_write_date - server.last_write_date + (server.heartbeat_frequency_seconds * 1000)
- staleness <= max_staleness_ms
+ staleness = max_write_date - server.last_write_date + server.heartbeat_frequency_seconds
+ staleness <= @max_staleness
end
end
end
def validate!