Class Mongo::ReplSetConnection
In: lib/mongo/repl_set_connection.rb
Parent: Connection

Instantiates and manages connections to a MongoDB replica set.

Methods

Constants

CLEANUP_INTERVAL = 300

Attributes

refresh_interval  [R] 
refresh_mode  [R] 
refresh_version  [R] 
replica_set_name  [R] 
seeds  [R] 

Public Class methods

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.

[Source]

# 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

Public Instance methods

[Source]

# File lib/mongo/repl_set_connection.rb, line 398
    def arbiters
      @manager.arbiters.nil? ? [] : @manager.arbiters
    end

[Source]

# 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.

[Source]

# 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.

[Source]

# 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.

[Source]

# 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).

[Source]

# 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.

[Source]

# 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

[Source]

# 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.

[Source]

# 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

[Source]

# File lib/mongo/repl_set_connection.rb, line 219
    def connected?
      @connected && (self.primary_pool || self.read_pool)
    end

@deprecated

[Source]

# 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

[Source]

# 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.

[Source]

# 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

The replica set primary‘s host name.

@return [String]

[Source]

# File lib/mongo/repl_set_connection.rb, line 232
    def host
      self.primary_pool.host
    end

[Source]

# File lib/mongo/repl_set_connection.rb, line 411
    def hosts
      @manager ? @manager.hosts : []
    end

[Source]

# 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

[Source]

# 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

[Source]

# 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

[Source]

# 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

The replica set primary‘s port.

@return [Integer]

[Source]

# File lib/mongo/repl_set_connection.rb, line 239
    def port
      self.primary_pool.port
    end

[Source]

# File lib/mongo/repl_set_connection.rb, line 402
    def primary
      @manager ? @manager.primary : nil
    end
primary?()

Alias for read_primary?

[Source]

# File lib/mongo/repl_set_connection.rb, line 415
    def primary_pool
      @manager ? @manager.primary_pool : nil
    end

[Source]

# File lib/mongo/repl_set_connection.rb, line 419
    def read_pool
      @manager ? @manager.read_pool : nil
    end

[Source]

# File lib/mongo/repl_set_connection.rb, line 258
    def read_preference
      @read
    end

Determine whether we‘re reading from a primary node. If false, this connection connects to a secondary node and @read_secondaries is true.

@return [Boolean]

[Source]

# File lib/mongo/repl_set_connection.rb, line 253
    def read_primary?
      self.read_pool == self.primary_pool
    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.

[Source]

# 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

[Source]

# 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.

[Source]

# File lib/mongo/repl_set_connection.rb, line 407
    def secondaries
      @manager ? @manager.secondaries : []
    end

[Source]

# 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

[Source]

# File lib/mongo/repl_set_connection.rb, line 288
    def slave_ok?
      true
    end

[Source]

# File lib/mongo/repl_set_connection.rb, line 427
    def tag_map
      @manager ? @manager.tag_map : {}
    end

[Validate]