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

157 lines
4.0 KiB
Ruby

module Mongo
class Node
attr_accessor :host, :port, :address, :config, :repl_set_status, :connection, :socket
def initialize(connection, data)
self.connection = connection
if data.is_a?(String)
self.host, self.port = split_nodes(data)
else
self.host, self.port = data
end
self.address = "#{host}:#{port}"
end
def eql?(other)
other.is_a?(Node) && host == other.host && port == other.port
end
alias :== :eql?
def host_string
"#{@host}:#{@port}"
end
# Create a connection to the provided node,
# and, if successful, return the socket. Otherwise,
# return nil.
def connect
begin
socket = nil
if self.connection.connect_timeout
Mongo::TimeoutHandler.timeout(self.connection.connect_timeout, OperationTimeout) do
socket = TCPSocket.new(self.host, self.port)
end
else
socket = TCPSocket.new(self.host, self.port)
end
if socket.nil?
return nil
else
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}.")
socket.close if socket
return nil
end
self.socket = socket
end
def disconnect
if self.socket
self.socket.close
self.socket = nil
self.config = nil
end
end
def connected?
self.socket != nil
end
def active?
begin
result = self.connection['admin'].command({:ping => 1}, :socket => self.socket)
return result['ok'] == 1
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
return nil
end
end
# 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
self.config = self.connection['admin'].command({:ismaster => 1}, :socket => self.socket)
if self.config['msg'] && @logger
self.connection.logger.warn("MONGODB #{config['msg']}")
end
check_set_name
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
return nil
end
self.config
end
# Return a list of replica set nodes from the config.
# Note: this excludes arbiters.
def node_list
connect unless connected?
set_config
return [] unless config
nodes = []
nodes += config['hosts'] if config['hosts']
nodes += config['passives'] if config['passives']
nodes
end
def arbiters
connect unless connected?
return [] unless config['arbiters']
config['arbiters'].map do |arbiter|
split_nodes(arbiter)
end
end
def primary?
self.config['ismaster'] == true || self.config['ismaster'] == 1
end
def secondary?
self.config['secondary'] == true || self.config['secondary'] == 1
end
def host_port
[self.host, self.port]
end
def hash
address.hash
end
private
def split_nodes(host_string)
data = host_string.split(":")
host = data[0]
port = data[1].to_i || Connection::DEFAULT_PORT
[host, port]
end
# Make sure that we're connected to the expected replica set.
def check_set_name
if self.connection.replica_set_name
if !self.config['setName']
self.connection.logger.warn("MONGODB [warning] could not verify replica set name " +
"because ismaster does not return name in this version of MongoDB")
elsif self.connection.replica_set_name != self.config['setName']
raise ReplicaSetConnectionError,
"Attempting to connect to replica set '#{config['setName']}' " +
"but expected '#{self.connection.replica_set_name}'"
end
end
end
end
end