minor: cleanup and test fix

This commit is contained in:
Kyle Banker 2011-09-15 17:46:59 -04:00
parent b910e3e635
commit 3e3f05813a
4 changed files with 59 additions and 57 deletions

View File

@ -23,7 +23,8 @@ module Mongo
# Instantiates and manages connections to a MongoDB replica set.
class ReplSetConnection < Connection
attr_reader :nodes, :secondaries, :arbiters, :secondary_pools,
:replica_set_name, :read_pool, :seeds, :tags_to_pools, :refresh_interval, :auto_refresh
:replica_set_name, :read_pool, :seeds, :tags_to_pools,
:refresh_interval, :background_refresh
# Create a connection to a MongoDB replica set.
#
@ -56,11 +57,12 @@ module Mongo
# @option opts [Float] :connect_timeout (nil) 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] :auto_refresh (false) Set this to true to enable a background thread that
# @option opts [Boolean] :background_refresh (false) Set this to true to enable a background thread that
# periodically updates the state of the connection. If, for example, you initially connect while a secondary
# is down, :auto_refresh will reconnect to that secondary behind the scenes to
# prevent you from having to reconnect manually.
# @option opts [Integer] :refresh_interval (90) If :auto_refresh is enabled, this is the number of seconds
# is down, :background_refresh will reconnect to that secondary behind the scenes to
# prevent you from having to reconnect manually. If set to +false+, background refresh will happen
# synchronously.
# @option opts [Integer] :refresh_interval (90) If :background_refresh is enabled, this is the number of seconds
# that the background thread will sleep 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.
@ -118,7 +120,7 @@ module Mongo
@arbiters = []
# Refresh
@auto_refresh = opts.fetch(:auto_refresh, false)
@background_refresh = opts.fetch(:background_refresh, false)
@refresh_interval = opts[:refresh_interval] || 90
# Are we allowing reads from secondaries?
@ -151,7 +153,7 @@ module Mongo
end
# Require a primary node to connect?
@require_primary = opts.fetch(:require_primary, false)
@require_primary = opts.fetch(:require_primary, true)
setup(opts)
end
@ -163,14 +165,14 @@ module Mongo
# Initiate a connection to the replica set.
def connect
log(:debug, "Connecting.")
log(:debug, "Connecting...")
sync_synchronize(:EX) do
return if @connected
manager = PoolManager.new(self, @seeds)
manager.connect
update_config(manager)
initiate_auto_refresh
initiate_background_refresh
if @require_primary && @primary.nil? #TODO: in v2.0, we'll let this be optional and do a lazy connect.
raise ConnectionFailure, "Failed to connect to primary node."
@ -241,7 +243,8 @@ module Mongo
end
def nodes
warn "DEPRECATED"
warn "ReplSetConnection#nodes is DEPRECATED and will be removed in v2.0. " +
"Please use ReplSetConnection#seeds instead."
@seeds
end
@ -261,7 +264,6 @@ module Mongo
end
# Close the connection to the database.
# TODO: we should get an exclusive lock here.
def close
sync_synchronize(:EX) do
@connected = false
@ -331,8 +333,8 @@ module Mongo
private
def initiate_auto_refresh
if @auto_refresh
def initiate_background_refresh
if @background_refresh
return if @refresh_thread && @refresh_thread.alive?
@refresh_thread = Thread.new do
while true do
@ -441,7 +443,9 @@ module Mongo
end
end
if !@auto_refresh &&
# Refresh synchronously every @refresh_interval seconds
# if @background_refresh is false.
if !@background_refresh &&
((Time.now - @last_refresh) > @refresh_interval)
refresh
end

View File

@ -4,15 +4,15 @@ module Mongo
attr_accessor :host, :port, :address, :config, :connection, :socket
def initialize(connection, data)
self.connection = connection
@connection = connection
if data.is_a?(String)
self.host, self.port = split_nodes(data)
@host, @port = split_nodes(data)
else
self.host = data[0]
self.port = data[1].nil? ? Connection::DEFAULT_PORT : data[1].to_i
@host = data[0]
@port = data[1].nil? ? Connection::DEFAULT_PORT : data[1].to_i
end
self.address = "#{host}:#{port}"
self.config = nil
@address = "#{host}:#{port}"
@config = nil
end
def eql?(other)
@ -34,12 +34,12 @@ module Mongo
def connect
begin
socket = nil
if self.connection.connect_timeout
Mongo::TimeoutHandler.timeout(self.connection.connect_timeout, OperationTimeout) do
socket = self.connection.socket_class.new(self.host, self.port)
if @connection.connect_timeout
Mongo::TimeoutHandler.timeout(@connection.connect_timeout, OperationTimeout) do
socket = @connection.socket_class.new(@host, @port)
end
else
socket = self.connection.socket_class.new(self.host, self.port)
socket = @connection.socket_class.new(@host, @port)
end
if socket.nil?
@ -48,29 +48,29 @@ module Mongo
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
end
rescue OperationTimeout, OperationFailure, SocketError, SystemCallError, IOError => ex
self.connection.log(:debug, "Failed connection to #{host_string} with #{ex.class}, #{ex.message}.")
@connection.log(:debug, "Failed connection to #{host_string} with #{ex.class}, #{ex.message}.")
socket.close if socket
return nil
end
self.socket = socket
@socket = socket
end
def close
if self.socket
self.socket.close
self.socket = nil
self.config = nil
if @socket
@socket.close
@socket = nil
@config = nil
end
end
def connected?
self.socket != nil
@socket != nil
end
def active?
begin
result = self.connection['admin'].command({:ping => 1}, :socket => self.socket)
result = @connection['admin'].command({:ping => 1}, :socket => @socket)
return result['ok'] == 1
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
return nil
@ -82,28 +82,28 @@ module Mongo
# matches with the name provided.
def set_config
begin
self.config = self.connection['admin'].command({:ismaster => 1}, :socket => self.socket)
@config = @connection['admin'].command({:ismaster => 1}, :socket => @socket)
if self.config['msg'] && @logger
self.connection.log(:warn, "#{config['msg']}")
if @config['msg'] && @logger
@connection.log(:warn, "#{config['msg']}")
end
check_set_membership(config)
check_set_name(config)
rescue ConnectionFailure, OperationFailure, SocketError, SystemCallError, IOError => ex
self.connection.log(:warn, "Attempted connection to node #{host_string} raised " +
@connection.log(:warn, "Attempted connection to node #{host_string} raised " +
"#{ex.class}: #{ex.message}")
return nil
end
self.config
@config
end
# Return a list of replica set nodes from the config.
# Note: this excludes arbiters.
def node_list
connect unless connected?
set_config unless self.config
set_config unless @config
return [] unless config
@ -115,7 +115,7 @@ module Mongo
def arbiters
connect unless connected?
set_config unless self.config
set_config unless @config
return [] unless config['arbiters']
config['arbiters'].map do |arbiter|
@ -125,22 +125,22 @@ module Mongo
def tags
connect unless connected?
set_config unless self.config
set_config unless @config
return {} unless config['tags'] && !config['tags'].empty?
config['tags']
end
def primary?
self.config['ismaster'] == true || self.config['ismaster'] == 1
@config['ismaster'] == true || @config['ismaster'] == 1
end
def secondary?
self.config['secondary'] == true || self.config['secondary'] == 1
@config['secondary'] == true || @config['secondary'] == 1
end
def host_port
[self.host, self.port]
[@host, @port]
end
def hash
@ -168,13 +168,13 @@ module Mongo
# Ensure that this node is part of a replica set of the expected name.
def check_set_name(config)
if self.connection.replica_set_name
if @connection.replica_set_name
if !config['setName']
self.connection.log(:warn, "Could not verify replica set name for member #{host_string} " +
@connection.log(:warn, "Could not verify replica set name for member #{host_string} " +
"because ismaster does not return name in this version of MongoDB")
elsif self.connection.replica_set_name != config['setName']
elsif @connection.replica_set_name != config['setName']
message = "Attempting to connect to replica set '#{config['setName']}' on member #{host_string} " +
"but expected '#{self.connection.replica_set_name}'"
"but expected '#{@connection.replica_set_name}'"
raise ReplicaSetConnectionError, message
end
end

View File

@ -20,12 +20,12 @@ class ReplicaSetRefreshTest < Test::Unit::TestCase
x.report("Connect") do
10.times do
ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
[RS.host, RS.ports[2]], :auto_refresh => false)
[RS.host, RS.ports[2]], :background_refresh => false)
end
end
@con = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
[RS.host, RS.ports[2]], :auto_refresh => false)
[RS.host, RS.ports[2]], :background_refresh => false)
x.report("manager") do
man = Mongo::PoolManager.new(@con, @con.seeds)
@ -41,7 +41,7 @@ class ReplicaSetRefreshTest < Test::Unit::TestCase
rescue_connection_failure do
@conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
[RS.host, RS.ports[2]], :auto_refresh => false)
[RS.host, RS.ports[2]], :background_refresh => false)
end
assert_equal [], @conn.secondaries
@ -70,7 +70,7 @@ class ReplicaSetRefreshTest < Test::Unit::TestCase
rescue_connection_failure do
@conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
[RS.host, RS.ports[2]], :refresh_interval => 2, :auto_refresh => true)
[RS.host, RS.ports[2]], :refresh_interval => 2, :background_refresh => true)
end
assert_equal [], @conn.secondaries
@ -87,7 +87,7 @@ class ReplicaSetRefreshTest < Test::Unit::TestCase
def test_automated_refresh_with_removed_node
@conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
[RS.host, RS.ports[2]], :refresh_interval => 2, :auto_refresh => true)
[RS.host, RS.ports[2]], :refresh_interval => 2, :background_refresh => true)
assert_equal 2, @conn.secondary_pools.length
assert_equal 2, @conn.secondaries.length
@ -103,13 +103,13 @@ class ReplicaSetRefreshTest < Test::Unit::TestCase
def test_adding_and_removing_nodes
@conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
[RS.host, RS.ports[2]], :refresh_interval => 2, :auto_refresh => true)
[RS.host, RS.ports[2]], :refresh_interval => 2, :background_refresh => true)
RS.add_node
sleep(5)
@conn2 = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
[RS.host, RS.ports[2]], :refresh_interval => 2, :auto_refresh => true)
[RS.host, RS.ports[2]], :refresh_interval => 2, :background_refresh => true)
assert @conn2.secondaries == @conn.secondaries
assert_equal 3, @conn.secondary_pools.length

View File

@ -5,7 +5,7 @@ class PoolManagerTest < Test::Unit::TestCase
context "Initialization: " do
def setup
should "populate pools correctly" do
TCPSocket.stubs(:new).returns(new_mock_socket)
@db = new_mock_db
@ -14,9 +14,7 @@ class PoolManagerTest < Test::Unit::TestCase
@connection.stubs(:pool_size).returns(2)
@connection.stubs(:socket_class).returns(TCPSocket)
@connection.stubs(:[]).returns(@db)
end
should "populate pools correctly" do
@connection.stubs(:replica_set_name).returns(nil)
@connection.stubs(:log)
@arbiters = ['localhost:27020']