module Mongo::ReadPreference
Constants
- MONGOS_MODES
- READ_PREFERENCES
- SECONDARY_OK_COMMANDS
Commands that may be sent to replica-set secondaries, depending on read preference and tags. All other commands are always run on the primary.
Public Class Methods
cmd_read_pref(read_pref, selector)
click to toggle source
Given a command and read preference, possibly reroute to primary.
# File lib/mongo/functional/read_preference.rb, line 89 def self.cmd_read_pref(read_pref, selector) ReadPreference::validate(read_pref) if reroute_cmd_primary?(read_pref, selector) warn "Database command '#{selector.keys.first}' rerouted to primary node" read_pref = :primary end read_pref end
mongos(mode, tag_sets)
click to toggle source
# File lib/mongo/functional/read_preference.rb, line 51 def self.mongos(mode, tag_sets) if mode != :secondary_preferred || !tag_sets.empty? mongos_read_preference = BSON::OrderedHash[:mode => MONGOS_MODES[mode]] mongos_read_preference[:tags] = tag_sets if !tag_sets.empty? end mongos_read_preference end
reroute_cmd_primary?(read_pref, selector)
click to toggle source
Returns true if the command should be rerouted to the primary.
# File lib/mongo/functional/read_preference.rb, line 83 def self.reroute_cmd_primary?(read_pref, selector) return false if read_pref == :primary !secondary_ok?(selector) end
secondary_ok?(selector)
click to toggle source
Returns true if it's ok to run the command on a secondary
# File lib/mongo/functional/read_preference.rb, line 69 def self.secondary_ok?(selector) command = selector.keys.first.to_s.downcase if command == 'mapreduce' out = selector.select { |k, v| k.to_s.downcase == 'out' }.first.last # the server only looks at the first key in the out object return out.respond_to?(:keys) && out.keys.first.to_s.downcase == 'inline' elsif command == 'aggregate' return selector['pipeline'].none? { |op| op.key?('$out') || op.key?(:$out) } end SECONDARY_OK_COMMANDS.member?(command) end
validate(value)
click to toggle source
# File lib/mongo/functional/read_preference.rb, line 59 def self.validate(value) if READ_PREFERENCES.include?(value) return true else raise MongoArgumentError, "#{value} is not a valid read preference. " + "Please specify one of the following read preferences as a symbol: #{READ_PREFERENCES}" end end
Public Instance Methods
read_pool(read_preference_override={})
click to toggle source
# File lib/mongo/functional/read_preference.rb, line 106 def read_pool(read_preference_override={}) return primary_pool if mongos? read_pref = read_preference.merge(read_preference_override) if pinned_pool && pinned_pool[:read_preference] == read_pref pool = pinned_pool[:pool] else unpin_pool pool = select_pool(read_pref) end unless pool raise ConnectionFailure, "No replica set member available for query " + "with read preference matching mode #{read_pref[:mode]} and tags " + "matching #{read_pref[:tags]}." end pool end
read_preference()
click to toggle source
# File lib/mongo/functional/read_preference.rb, line 98 def read_preference { :mode => @read, :tags => @tag_sets, :latency => @acceptable_latency } end
select_near_pool(candidates, read_pref)
click to toggle source
# File lib/mongo/functional/read_preference.rb, line 165 def select_near_pool(candidates, read_pref) latency = read_pref[:latency] nearest_pool = candidates.min_by { |candidate| candidate.ping_time } near_pools = candidates.select do |candidate| (candidate.ping_time - nearest_pool.ping_time) <= latency end near_pools[ rand(near_pools.length) ] end
select_pool(read_pref)
click to toggle source
# File lib/mongo/functional/read_preference.rb, line 127 def select_pool(read_pref) if read_pref[:mode] == :primary && !read_pref[:tags].empty? raise MongoArgumentError, "Read preference :primary cannot be combined with tags" end case read_pref[:mode] when :primary primary_pool when :primary_preferred primary_pool || select_secondary_pool(secondary_pools, read_pref) when :secondary select_secondary_pool(secondary_pools, read_pref) when :secondary_preferred select_secondary_pool(secondary_pools, read_pref) || primary_pool when :nearest select_near_pool(pools, read_pref) end end
select_secondary_pool(candidates, read_pref)
click to toggle source
# File lib/mongo/functional/read_preference.rb, line 146 def select_secondary_pool(candidates, read_pref) tag_sets = read_pref[:tags] if !tag_sets.empty? matches = [] tag_sets.detect do |tag_set| matches = candidates.select do |candidate| tag_set.none? { |k,v| candidate.tags[k.to_s] != v } && candidate.ping_time end !matches.empty? end else matches = candidates end matches.empty? ? nil : select_near_pool(matches, read_pref) end