# File 'lib/mongo/server_selector/base.rb', line 193
private def select_server_impl(cluster, _ping, session, write_aggregation, deprioritized, csot_timeout)
return cluster.servers.first if cluster.topology.is_a?(Cluster::Topology::LoadBalanced)
timeout = cluster.options[:server_selection_timeout] || SERVER_SELECTION_TIMEOUT
server_selection_timeout = if csot_timeout && csot_timeout > 0
[ timeout, csot_timeout ].min
else
timeout
end
if server_selection_timeout == 0
msg = 'Failing server selection due to zero timeout. ' +
" Requested #{name} in cluster: #{cluster.summary}"
raise Error::NoServerAvailable.new(self, cluster, msg)
end
deadline = Utils.monotonic_time + server_selection_timeout
if session && session.pinned_server
if Mongo::Lint.enabled? && !cluster.sharded?
raise Error::LintError, "Session has a pinned server in a non-sharded topology: #{topology}"
end
session.unpin unless session.in_transaction?
if server = session.pinned_server
unless server.mongos?
while (time_remaining = deadline - Utils.monotonic_time) > 0
wait_for_server_selection(cluster, time_remaining)
end
unless server.mongos?
msg = "The session being used is pinned to the server which is not a mongos: #{server.summary} " +
"(after #{server_selection_timeout} seconds)"
raise Error::NoServerAvailable.new(self, cluster, msg)
end
end
return server
end
end
validate_max_staleness_value_early! if cluster.replica_set?
if cluster.addresses.empty?
if Lint.enabled? && !cluster.servers.empty?
raise Error::LintError,
"Cluster has no addresses but has servers: #{cluster.servers.map(&:inspect).join(', ')}"
end
msg = 'Cluster has no addresses, and therefore will never have a server'
raise Error::NoServerAvailable.new(self, cluster, msg)
end
loop do
if Lint.enabled?
cluster.servers.each do |server|
if !server.unknown? && !server.pool.ready?
raise Error::LintError, "Server #{server.summary} is known but has non-ready pool"
end
end
end
server = try_select_server(cluster, write_aggregation: write_aggregation, deprioritized: deprioritized)
if server.nil? && deprioritized.any?
server = try_select_server(cluster, write_aggregation: write_aggregation, deprioritized: [])
end
if server
unless cluster.topology.compatible?
raise Error::UnsupportedFeatures, cluster.topology.compatibility_error.to_s
end
session.pin_to_server(server) if session && session.starting_transaction? && cluster.sharded?
return server
end
cluster.scan!(false)
time_remaining = deadline - Utils.monotonic_time
break unless time_remaining > 0
wait_for_server_selection(cluster, time_remaining)
end
msg = "No #{name} server"
msg += " with tag sets: #{tag_sets}" if is_a?(ServerSelector::Secondary) && !tag_sets.empty?
msg += " is available in cluster: #{cluster.summary} " +
"with timeout=#{server_selection_timeout}, " +
"LT=#{local_threshold_with_cluster(cluster)}"
msg += server_selection_diagnostic_message(cluster)
raise Error::NoServerAvailable.new(self, cluster, msg)
rescue Error::NoServerAvailable => e
if session && session.in_transaction? && !session.committing_transaction?
e.add_label('TransientTransactionError')
end
e.add_label('UnknownTransactionCommitResult') if session && session.committing_transaction?
raise e
end