mongo-ruby-driver/lib/mongo/util/node.rb

188 lines
5.0 KiB
Ruby
Raw Normal View History

2011-08-09 13:45:36 +00:00
module Mongo
class Node
attr_accessor :host, :port, :address, :config, :connection, :socket,
:last_state
2011-08-16 20:47:07 +00:00
def initialize(connection, data)
2011-09-15 21:46:59 +00:00
@connection = connection
2011-08-16 20:47:07 +00:00
if data.is_a?(String)
2011-09-15 21:46:59 +00:00
@host, @port = split_nodes(data)
2011-08-16 20:47:07 +00:00
else
2011-09-15 21:46:59 +00:00
@host = data[0]
@port = data[1].nil? ? Connection::DEFAULT_PORT : data[1].to_i
2011-08-16 20:47:07 +00:00
end
2011-09-15 21:46:59 +00:00
@address = "#{host}:#{port}"
@config = nil
@socket = nil
2011-08-09 13:45:36 +00:00
end
2011-08-16 20:47:07 +00:00
2011-08-09 13:45:36 +00:00
def eql?(other)
other.is_a?(Node) && host == other.host && port == other.port
end
alias :== :eql?
2011-08-16 20:47:07 +00:00
def host_string
2011-09-01 15:42:56 +00:00
address
end
def inspect
"<Mongo::Node:0x#{self.object_id.to_s(16)} @host=#{@host} @port=#{@port}>"
end
2011-08-16 20:47:07 +00:00
# Create a connection to the provided node,
# and, if successful, return the socket. Otherwise,
# return nil.
def connect
begin
socket = nil
socket = @connection.socket_class.new(@host, @port,
@connection.op_timeout, @connection.connect_timeout
)
2011-08-16 20:47:07 +00:00
2012-04-08 14:48:25 +00:00
return nil if socket.nil?
rescue OperationTimeout, ConnectionFailure, OperationFailure, SocketError, SystemCallError, IOError => ex
2011-09-15 21:46:59 +00:00
@connection.log(:debug, "Failed connection to #{host_string} with #{ex.class}, #{ex.message}.")
socket.close if socket
return nil
2011-08-16 20:47:07 +00:00
end
2011-09-15 21:46:59 +00:00
@socket = socket
2011-08-16 20:47:07 +00:00
end
def close
2011-11-07 18:36:57 +00:00
if @socket && !@socket.closed?
2011-09-15 21:46:59 +00:00
@socket.close
2011-08-16 20:47:07 +00:00
end
2011-11-07 18:36:57 +00:00
@socket = nil
@config = nil
2011-08-16 20:47:07 +00:00
end
def connected?
2011-09-15 21:46:59 +00:00
@socket != nil
2011-08-16 20:47:07 +00:00
end
def active?
begin
2011-09-15 21:46:59 +00:00
result = @connection['admin'].command({:ping => 1}, :socket => @socket)
return result['ok'] == 1
2012-03-16 20:17:33 +00:00
rescue OperationFailure, SocketError, SystemCallError, IOError
return nil
end
end
2011-08-16 20:47:07 +00:00
# Get the configuration for the provided node as returned by the
# ismaster command. Additionally, check that the replica set name
# matches with the name provided.
def set_config
begin
@config = @connection['admin'].command({:ismaster => 1}, :socket => @socket)
2011-08-16 20:47:07 +00:00
2011-09-15 21:46:59 +00:00
if @config['msg'] && @logger
@connection.log(:warn, "#{config['msg']}")
2011-08-16 20:47:07 +00:00
end
check_set_membership(config)
check_set_name(config)
rescue ConnectionFailure, OperationFailure, OperationTimeout, SocketError, SystemCallError, IOError => ex
2011-09-15 21:46:59 +00:00
@connection.log(:warn, "Attempted connection to node #{host_string} raised " +
"#{ex.class}: #{ex.message}")
2012-03-03 00:09:51 +00:00
# Socket may already be nil from issuing command
if @socket && !@socket.closed?
@socket.close
end
2012-03-03 00:09:51 +00:00
2011-08-16 20:47:07 +00:00
return nil
end
2011-09-15 21:46:59 +00:00
@config
2011-08-16 20:47:07 +00:00
end
# Return a list of replica set nodes from the config.
# Note: this excludes arbiters.
def node_list
connect unless connected?
2011-09-15 21:46:59 +00:00
set_config unless @config
return [] unless config
2011-08-16 20:47:07 +00:00
nodes = []
nodes += config['hosts'] if config['hosts']
nodes += config['passives'] if config['passives']
nodes
end
def arbiters
connect unless connected?
2011-09-15 21:46:59 +00:00
set_config unless @config
return [] unless config['arbiters']
2011-08-16 20:47:07 +00:00
config['arbiters'].map do |arbiter|
split_nodes(arbiter)
end
end
def tags
connect unless connected?
2011-09-15 21:46:59 +00:00
set_config unless @config
return {} unless config['tags'] && !config['tags'].empty?
config['tags']
end
2011-08-16 20:47:07 +00:00
def primary?
2011-09-15 21:46:59 +00:00
@config['ismaster'] == true || @config['ismaster'] == 1
2011-08-16 20:47:07 +00:00
end
def secondary?
2011-09-15 21:46:59 +00:00
@config['secondary'] == true || @config['secondary'] == 1
2011-08-16 20:47:07 +00:00
end
def host_port
2011-09-15 21:46:59 +00:00
[@host, @port]
2011-08-16 20:47:07 +00:00
end
2011-08-09 13:45:36 +00:00
def hash
address.hash
end
2011-08-16 20:47:07 +00:00
private
def split_nodes(host_string)
data = host_string.split(":")
host = data[0]
port = data[1].nil? ? Connection::DEFAULT_PORT : data[1].to_i
2011-08-16 20:47:07 +00:00
[host, port]
end
# Ensure that this node is a healty member of a replica set.
def check_set_membership(config)
if !config['hosts']
message = "Will not connect to #{host_string} because it's not a member " +
"of a replica set."
raise ConnectionFailure, message
elsif config['hosts'].length == 1 && !config['ismaster'] &&
!config['secondary']
message = "Attempting to connect to an unhealthy, single-node replica set."
raise ConnectionFailure, message
end
end
# Ensure that this node is part of a replica set of the expected name.
def check_set_name(config)
2011-09-15 21:46:59 +00:00
if @connection.replica_set_name
if !config['setName']
2011-09-15 21:46:59 +00:00
@connection.log(:warn, "Could not verify replica set name for member #{host_string} " +
2011-08-16 20:47:07 +00:00
"because ismaster does not return name in this version of MongoDB")
2011-09-15 21:46:59 +00:00
elsif @connection.replica_set_name != config['setName']
message = "Attempting to connect to replica set '#{config['setName']}' on member #{host_string} " +
2011-09-15 21:46:59 +00:00
"but expected '#{@connection.replica_set_name}'"
2011-08-31 15:46:33 +00:00
raise ReplicaSetConnectionError, message
2011-08-16 20:47:07 +00:00
end
end
end
2011-08-09 13:45:36 +00:00
end
2011-08-16 20:47:07 +00:00
end