lib/mongo/server_selector/selectable.rb in mongo-2.7.0 vs lib/mongo/server_selector/selectable.rb in mongo-2.7.1
- old
+ new
@@ -18,10 +18,42 @@
# Provides common behavior for filtering a list of servers by server mode or tag set.
#
# @since 2.0.0
module Selectable
+ # Initialize the server selector.
+ #
+ # @example Initialize the selector.
+ # Mongo::ServerSelector::Secondary.new(:tag_sets => [{'dc' => 'nyc'}])
+ #
+ # @example Initialize the preference with no options.
+ # Mongo::ServerSelector::Secondary.new
+ #
+ # @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
+ def initialize(options = nil)
+ options = options ? options.dup : {}
+ if options[:max_staleness] == -1
+ options.delete(:max_staleness)
+ end
+ @options = options.freeze
+ @tag_sets = (options[:tag_sets] || []).freeze
+ @max_staleness = options[:max_staleness]
+ validate!
+ end
+
# @return [ Hash ] options The options.
attr_reader :options
# @return [ Array ] tag_sets The tag sets used to select servers.
attr_reader :tag_sets
@@ -46,38 +78,10 @@
name == other.name &&
tag_sets == other.tag_sets &&
max_staleness == other.max_staleness
end
- # Initialize the server selector.
- #
- # @example Initialize the selector.
- # Mongo::ServerSelector::Secondary.new(:tag_sets => [{'dc' => 'nyc'}])
- #
- # @example Initialize the preference with no options.
- # Mongo::ServerSelector::Secondary.new
- #
- # @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
- def initialize(options = {})
- @options = (options || {}).freeze
- @tag_sets = (options[:tag_sets] || []).freeze
- @max_staleness = options[:max_staleness] unless options[:max_staleness] == -1
- validate!
- end
-
# Inspect the server selector.
#
# @example Inspect the server selector.
# selector.inspect
#
@@ -97,10 +101,28 @@
#
# @return [ Mongo::Server ] A server matching the server preference.
#
# @since 2.0.0
def select_server(cluster, ping = nil)
+ if cluster.replica_set?
+ validate_max_staleness_value_early!
+ end
+ if cluster.addresses.empty?
+ if Lint.enabled?
+ unless cluster.servers.empty?
+ raise Error::LintError, "Cluster has no addresses but has servers: #{cluster.servers.map(&:inspect).join(', ')}"
+ end
+ end
+ msg = "Cluster has no addresses, and therefore will never have a server"
+ raise Error::NoServerAvailable.new(self, cluster, msg)
+ end
+=begin Add this check in version 3.0.0
+ unless cluster.connected?
+ msg = 'Cluster is disconnected'
+ raise Error::NoServerAvailable.new(self, cluster, msg)
+ end
+=end
@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)
@@ -132,11 +154,28 @@
return server
end
cluster.scan!(false)
end
- raise Error::NoServerAvailable.new(self, cluster)
+
+ msg = "No #{name} server is available in cluster: #{cluster.summary} " +
+ "with timeout=#{server_selection_timeout}, " +
+ "LT=#{local_threshold}"
+ dead_monitors = []
+ cluster.servers_list.each do |server|
+ thread = server.monitor.instance_variable_get('@thread')
+ if thread.nil? || !thread.alive?
+ dead_monitors << server
+ end
+ end
+ if dead_monitors.any?
+ msg += ". The following servers have dead monitor threads: #{dead_monitors.map(&:summary).join(', ')}"
+ end
+ unless cluster.connected?
+ msg += ". The cluster is disconnected (client may have been closed)"
+ end
+ raise Error::NoServerAvailable.new(self, cluster, msg)
end
# Get the timeout for server selection.
#
# @example Get the server selection timeout, in seconds.
@@ -290,15 +329,30 @@
if @max_staleness && !server.features.max_staleness_enabled?
raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::NO_MAX_STALENESS_WITH_LEGACY_SERVER)
end
end
+ def validate_max_staleness_value_early!
+ if @max_staleness
+ unless @max_staleness >= SMALLEST_MAX_STALENESS_SECONDS
+ msg = "`max_staleness` value (#{@max_staleness}) is too small - it must be at least " +
+ "`Mongo::ServerSelector::SMALLEST_MAX_STALENESS_SECONDS` (#{ServerSelector::SMALLEST_MAX_STALENESS_SECONDS})"
+ raise Error::InvalidServerPreference.new(msg)
+ end
+ end
+ end
+
def validate_max_staleness_value!(cluster)
if @max_staleness
heartbeat_frequency_seconds = cluster.options[:heartbeat_frequency] || Server::Monitor::HEARTBEAT_FREQUENCY
- unless @max_staleness >= [ SMALLEST_MAX_STALENESS_SECONDS,
- (heartbeat_frequency_seconds + Cluster::IDLE_WRITE_PERIOD_SECONDS) ].max
- raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::INVALID_MAX_STALENESS)
+ unless @max_staleness >= [
+ SMALLEST_MAX_STALENESS_SECONDS,
+ min_cluster_staleness = heartbeat_frequency_seconds + Cluster::IDLE_WRITE_PERIOD_SECONDS,
+ ].max
+ msg = "`max_staleness` value (#{@max_staleness}) is too small - it must be at least " +
+ "`Mongo::ServerSelector::SMALLEST_MAX_STALENESS_SECONDS` (#{ServerSelector::SMALLEST_MAX_STALENESS_SECONDS}) and (the cluster's heartbeat_frequency " +
+ "setting + `Mongo::Cluster::IDLE_WRITE_PERIOD_SECONDS`) (#{min_cluster_staleness})"
+ raise Error::InvalidServerPreference.new(msg)
end
end
end
end
end