Class | Mongo::ReplSetConnection |
In: |
lib/mongo/repl_set_connection.rb
|
Parent: | Connection |
Instantiates and manages connections to a MongoDB replica set.
CLEANUP_INTERVAL | = | 300 |
refresh_interval | [R] | |
refresh_mode | [R] | |
refresh_version | [R] | |
replica_set_name | [R] | |
seeds | [R] |
Create a connection to a MongoDB replica set.
Once connected to a replica set, you can find out which nodes are primary, secondary, and arbiters with the corresponding accessors: Connection#primary, Connection#secondaries, and Connection#arbiters. This is useful if your application needs to connect manually to nodes other than the primary.
@param [Array] args A list of host-port pairs to be used as seed nodes followed by a
hash containing any options. See the examples below for exactly how to use the constructor.
@option options [String] :rs_name (nil) The name of the replica set to connect to. You
can use this option to verify that you're connecting to the right replica set.
@option options [Boolean, Hash] :safe (false) Set the default safe-mode options
propogated to DB objects instantiated off of this Connection. This default can be overridden upon instantiation of any DB by explicity setting a :safe value on initialization.
@option options [:primary, :secondary] :read (:primary) The default read preference for Mongo::DB
objects created from this connection object. If +:secondary+ is chosen, reads will be sent to one of the closest available secondary nodes. If a secondary node cannot be located, the read will be sent to the primary.
@option options [Logger] :logger (nil) Logger instance to receive driver operation log. @option options [Integer] :pool_size (1) The maximum number of socket connections allowed per
connection pool. Note: this setting is relevant only for multi-threaded applications.
@option options [Float] :pool_timeout (5.0) When all of the connections a pool are checked out,
this is the number of seconds to wait for a new connection to be released before throwing an exception. Note: this setting is relevant only for multi-threaded applications.
@option opts [Float] :op_timeout (30) The number of seconds to wait for a read operation to time out. @option opts [Float] :connect_timeout (30) The number of seconds to wait before timing out a
connection attempt.
@option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL. @option opts [Boolean] :refresh_mode (false) Set this to :sync to periodically update the
state of the connection every :refresh_interval seconds. Replica set connection failures will always trigger a complete refresh. This option is useful when you want to add new nodes or remove replica set nodes not currently in use by the driver.
@option opts [Integer] :refresh_interval (90) If :refresh_mode is enabled, this is the number of seconds
between calls to check the replica set's state.
@option opts [Boolean] :require_primary (true) If true, require a primary node for the connection
to succeed. Otherwise, connection will succeed as long as there's at least one secondary node.
@example Connect to a replica set and provide two seed nodes. Note that the number of seed nodes does
not have to be equal to the number of replica set members. The purpose of seed nodes is to permit the driver to find at least one replica set member even if a member is down. ReplSetConnection.new(['localhost', 30000], ['localhost', 30001])
@example Connect to a replica set providing two seed nodes and ensuring a connection to the replica set named ‘prod’:
ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :rs_name => 'prod')
@example Connect to a replica set providing two seed nodes and allowing reads from a secondary node:
ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :read_secondary => true)
@see api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
@raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
driver fails to connect to a replica set with that name.
# File lib/mongo/repl_set_connection.rb, line 82 def initialize(*args) if args.last.is_a?(Hash) opts = args.pop else opts = {} end unless args.length > 0 raise MongoArgumentError, "A ReplSetConnection requires at least one seed node." end # The original, immutable list of seed node. # TODO: add a method for replacing this list of node. @seeds = args @seeds.freeze # TODO: get rid of this @nodes = @seeds.dup # Refresh @refresh_mode = opts.fetch(:refresh_mode, false) @refresh_interval = opts[:refresh_interval] || 90 @last_refresh = Time.now # No connection manager by default. @manager = nil @pool_mutex = Mutex.new if @refresh_mode == :async warn ":async refresh mode has been deprecated. Refresh mode will be disabled." elsif ![:sync, false].include?(@refresh_mode) raise MongoArgumentError, "Refresh mode must be either :sync or false." end # Are we allowing reads from secondaries? if opts[:read_secondary] warn ":read_secondary options has now been deprecated and will " + "be removed in driver v2.0. Use the :read option instead." @read_secondary = opts.fetch(:read_secondary, false) @read = :secondary else @read = opts.fetch(:read, :primary) Mongo::Support.validate_read_preference(@read) end @connected = false @refresh_version = 0 # Replica set name if opts[:rs_name] warn ":rs_name option has been deprecated and will be removed in v2.0. " + "Please use :name instead." @replica_set_name = opts[:rs_name] else @replica_set_name = opts[:name] end # Require a primary node to connect? @require_primary = opts.fetch(:require_primary, true) setup(opts) end
# File lib/mongo/repl_set_connection.rb, line 398 def arbiters @manager.arbiters.nil? ? [] : @manager.arbiters end
# File lib/mongo/repl_set_connection.rb, line 292 def authenticate_pools self.primary_pool.authenticate_existing self.secondary_pools.each do |pool| pool.authenticate_existing end end
Checkin a socket used for reading.
# File lib/mongo/repl_set_connection.rb, line 362 def checkin_reader(socket) if !((self.read_pool && self.read_pool.checkin(socket)) || (self.primary_pool && self.primary_pool.checkin(socket))) close_socket(socket) end sync_refresh end
Checkin a socket used for writing.
# File lib/mongo/repl_set_connection.rb, line 371 def checkin_writer(socket) if !self.primary_pool || !self.primary_pool.checkin(socket) close_socket(socket) end sync_refresh end
Checkout a socket for reading (i.e., a secondary node). Note that @read_pool might point to the primary pool if no read pool has been defined.
# File lib/mongo/repl_set_connection.rb, line 309 def checkout_reader if connected? sync_refresh else connect end begin socket = get_socket_from_pool(self.read_pool) if !socket connect socket = get_socket_from_pool(self.primary_pool) end rescue => ex checkin(socket) if socket raise ex end if socket socket else raise ConnectionFailure.new("Could not connect to a node for reading.") end end
Checkout a socket for writing (i.e., a primary node).
# File lib/mongo/repl_set_connection.rb, line 336 def checkout_writer if connected? sync_refresh else connect end begin socket = get_socket_from_pool(self.primary_pool) if !socket connect socket = get_socket_from_pool(self.primary_pool) end rescue => ex checkin(socket) raise ex end if socket socket else raise ConnectionFailure.new("Could not connect to primary node.") end end
Close the connection to the database.
# File lib/mongo/repl_set_connection.rb, line 263 def close(opts={}) if opts[:soft] @manager.close(:soft => true) if @manager else @manager.close if @manager end @connected = false end
# File lib/mongo/repl_set_connection.rb, line 378 def close_socket(socket) begin socket.close if socket rescue IOError log(:info, "Tried to close socket #{socket} but already closed.") end end
Initiate a connection to the replica set.
# File lib/mongo/repl_set_connection.rb, line 153 def connect log(:info, "Connecting...") return if @connected discovered_seeds = @manager ? @manager.seeds : [] @manager = PoolManager.new(self, discovered_seeds) @manager.connect @refresh_version += 1 if @require_primary && self.primary.nil? #TODO: in v2.0, we'll let this be optional and do a lazy connect. close raise ConnectionFailure, "Failed to connect to primary node." elsif self.read_pool.nil? close raise ConnectionFailure, "Failed to connect to any node." else @connected = true end end
# File lib/mongo/repl_set_connection.rb, line 219 def connected? @connected && (self.primary_pool || self.read_pool) end
@deprecated
# File lib/mongo/repl_set_connection.rb, line 224 def connecting? warn "ReplSetConnection#connecting? is deprecated and will be removed in v2.0." false end
# File lib/mongo/repl_set_connection.rb, line 386 def get_socket_from_pool(pool) begin if pool socket = pool.checkout socket end rescue ConnectionFailure => ex log(:info, "Failed to checkout from #{pool} with #{ex.class}; #{ex.message}") return nil end end
Force a hard refresh of this connection‘s view of the replica set.
@return [Boolean] true if hard refresh
occurred. +false+ is returned when unable to get the refresh lock.
# File lib/mongo/repl_set_connection.rb, line 204 def hard_refresh! log(:info, "Initiating hard refresh...") discovered_seeds = @manager ? @manager.seeds : [] background_manager = PoolManager.new(self, discovered_seeds | @seeds) background_manager.connect # TODO: make sure that connect has succeeded old_manager = @manager @manager = background_manager old_manager.close(:soft => true) @refresh_version += 1 return true end
# File lib/mongo/repl_set_connection.rb, line 147 def inspect "<Mongo::ReplSetConnection:0x#{self.object_id.to_s(16)} @seeds=#{@seeds.inspect} " + "@connected=#{@connected}>" end
# File lib/mongo/repl_set_connection.rb, line 299 def logout_pools(db) self.primary_pool.logout_existing(db) self.secondary_pools.each do |pool| pool.logout_existing(db) end end
# File lib/mongo/repl_set_connection.rb, line 431 def max_bson_size if @manager && @manager.max_bson_size @manager.max_bson_size else Mongo::DEFAULT_MAX_BSON_SIZE end end
# File lib/mongo/repl_set_connection.rb, line 243 def nodes warn "ReplSetConnection#nodes is DEPRECATED and will be removed in v2.0. " + "Please use ReplSetConnection#seeds instead." @seeds end
# File lib/mongo/repl_set_connection.rb, line 415 def primary_pool @manager ? @manager.primary_pool : nil end
# File lib/mongo/repl_set_connection.rb, line 419 def read_pool @manager ? @manager.read_pool : nil end
Determine whether a replica set refresh is required. If so, run a hard refresh. You can force a hard refresh by running ReplSetConnection#hard_refresh!
@return [Boolean] true unless a hard refresh
is run and the refresh lock can't be acquired.
# File lib/mongo/repl_set_connection.rb, line 181 def refresh(opts={}) if !connected? log(:info, "Trying to check replica set health but not " + "connected...") return hard_refresh! end log(:debug, "Checking replica set connection health...") @manager.check_connection_health if @manager.refresh_required? return hard_refresh! end return true end
If a ConnectionFailure is raised, this method will be called to close the connection and reset connection values. @deprecated
# File lib/mongo/repl_set_connection.rb, line 275 def reset_connection close warn "ReplSetConnection#reset_connection is now deprecated and will be removed in v2.0. " + "Use ReplSetConnection#close instead." end
Note: might want to freeze these after connecting.
# File lib/mongo/repl_set_connection.rb, line 407 def secondaries @manager ? @manager.secondaries : [] end
# File lib/mongo/repl_set_connection.rb, line 423 def secondary_pools @manager ? @manager.secondary_pools : [] end
Returns true if it‘s okay to read from a secondary node. Since this is a replica set, this must always be true.
This method exist primarily so that Cursor objects will generate query messages with a slaveOkay value of true.
@return [Boolean] true
# File lib/mongo/repl_set_connection.rb, line 288 def slave_ok? true end