class Tarantool16::Connection::Connection

Constants

EXCEPTION_FALSE

Public Class Methods

new(host, opts = {}) click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 14
def initialize(host, opts = {})
  _init_common(host, opts)
  @reconnect_time = now_f - 1
  @socket = nil
  _connect
end

Public Instance Methods

close() click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 48
def close
  @reconnect = false
  if @socket
    @socket.close rescue nil
    @socket = false
    @s = 0
  end
end
connected?() click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 57
def connected?
  @socket
end
could_be_connected?() click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 61
def could_be_connected?
  @socket || (@socket.nil? && (@reconnect || @reconnect_time < now_f))
end
disconnect() click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 40
def disconnect
  if @socket
    @socket.close rescue nil
    @socket = nil
    @s = 0
  end
end
send_request(code, body, cb) click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 21
def send_request(code, body, cb)
  _connect
  syswrite format_request(code, next_sync, body)
  written = true
  response = _read_response
rescue ::Errno::EPIPE, Retry => e
  @socket.close rescue nil
  @socket = nil
  if !written && @retry && @reconnect
    @retry = false
    retry
  end
  cb.call Option.error(nil, Disconnected, e.message)
rescue StandardError => e
  cb.call Option.error(nil, e, nil)
else
  cb.call response
end

Private Instance Methods

_connect() click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 66
def _connect
  return if @socket
  unless could_be_connected?
    raise Disconnected, "connection is closed"
  end
  if _unix?
    @socket = Socket.unix(_unix_sock_path)
  elsif _tcp?
    @socket = Socket.new((_ipv6? ? Socket::AF_INET6 : Socket::AF_INET), Socket::SOCK_STREAM)
    @socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
    @socket.sync = true
    sockaddr = Socket.pack_sockaddr_in(*host_port.reverse)
    @retry = @reconnect
    if @timeout
      _connect_nonblock(sockaddr)
    else
      @socket.connect(sockaddr)
    end
  else
    raise "unsupported host option: #{@host.inspect}"
  end

  greeting = _read(IPROTO_GREETING_SIZE)
  unless greeting && greeting.bytesize == IPROTO_GREETING_SIZE
    raise Disconnected, "mailformed greeting #{greeting.inspect}"
  end
  @nbuf = "\x00\x00\x00\x00\x00".force_encoding('BINARY')
  parse_greeting greeting
  authenticate if @user
rescue ::Errno::ECONNREFUSED, ::Errno::EPIPE, Disconnected, Timeout => e
  @socket.close rescue nil
  @socket = nil
  if !@reconnect
    @socket = false
    @s = 0
  else
    @reconnect_time = now_f + @reconnect_timeout
  end
  raise CouldNotConnect, e.message
end
_connect_nonblock(sockaddr) click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 107
def _connect_nonblock(sockaddr)
  expire = now_f + @timeout
  begin
    @socket.connect_nonblock(sockaddr)
  rescue IO::WaitWritable
    t = [@socket]
    IO.select(t, t, nil, expire - now_f)
    begin
      @socket.connect_nonblock(sockaddr)
    rescue Errno::EISCONN
    end
  end
end
_read(n, buf=nil) click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 177
def _read(n, buf=nil)
  unless @timeout
    buf ? @socket.read(n, buf) : @socket.read(n)
  else
    expire = now_f + @timeout
    rbuf = nil
    while n > 0
      case tbuf = _read_nonblock(n, buf)
      when String
        if rbuf
          rbuf << tbuf
        else
          rbuf = tbuf
        end
        buf = nil
        n -= tbuf.size
      when :wait_readable
        nf = now_f
        if expire <= nf
          raise Timeout, "response timeouted"
        else
          _wait_readable(expire - nf)
        end
      when nil
        raise EOFError
      end
    end
    return rbuf
  end
end
_read_nonblock(n, buf) click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 210
def _read_nonblock(n, buf)
  if buf
    @socket.read_nonblock(n, buf, EXCEPTION_FALSE)
  else
    @socket.read_nonblock(n, EXCEPTION_FALSE)
  end
end
_read_response() click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 152
def _read_response
  str = _read(5, @nbuf)
  unless str && str.bytesize == 5
    # check if we sent request or not
    begin
      @socket.send("\x00", 0)
    rescue ::Errno::EPIPE
      # if OS knows that socket is closed, then request were not sent
      raise Retry
    else
      # otherwise request were sent
      raise Disconnected, "disconnected while read length"
    end
  end
  n = parse_size(str)
  raise n unless ::Integer === n
  resp = _read(n)
  raise Disconnected, "disconnected while read response" unless resp && resp.bytesize == n
  r = parse_response(resp)
  if r.ok? && r.sync != @s
    raise UnexpectedResponse, "sync mismatch: #{@s} != #{r.sync}"
  end
  r
end
_wait_readable(timeout) click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 238
def _wait_readable(timeout)
  IO.select([@socket], nil, nil, timeout)
end
_wait_writable(timeout) click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 247
def _wait_writable(timeout)
  @socket.wait_writable(timeout)
end
authenticate() click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 147
def authenticate
  syswrite format_authenticate(@user, @passwd, @salt)
  _read_response.raise_if_error!
end
syswrite(req) click to toggle source
# File lib/tarantool16/connection/dumb.rb, line 121
def syswrite(req)
  unless @timeout
    if @socket.syswrite(req) != req.bytesize
      raise Retry, "Could not write message"
    end
  else
    expire = now_f
    begin
      until req.empty?
        n = @socket.write_nonblock(req)
        req = req[n..-1]
      end
    rescue IO::WaitWritable
      nf = now_f
      if expire <= nf
        raise Timeout, "response timeouted"
      else
        _wait_writable(expire - nf)
        retry
      end
    rescue Errno::EINTR
      retry
    end
  end
end