class Moneta::Server

Moneta server to be used together with Moneta::Adapters::Client @api public

Constants

MAXSIZE
TIMEOUT

Public Class Methods

new(store, options = {}) click to toggle source

@param [Hash] options @option options [Integer] :port (9000) TCP port @option options [String] :socket Alternative Unix socket file name

# File lib/moneta/server.rb, line 10
def initialize(store, options = {})
  @store = store
  @server = start(options)
  @ios = [@server]
  @clients = {}
  @running = false
end

Public Instance Methods

run() click to toggle source

Run the server

@note This method blocks!

# File lib/moneta/server.rb, line 28
def run
  raise 'Already running' if @running
  @stop = false
  @running = true
  begin
    until @stop
      mainloop
    end
  ensure
    File.unlink(@socket) if @socket
  end
end
running?() click to toggle source

Is the server running

@return [Boolean] true if the server is running

# File lib/moneta/server.rb, line 21
def running?
  @running
end
stop() click to toggle source

Stop the server

# File lib/moneta/server.rb, line 42
def stop
  raise 'Not running' unless @running
  @stop = true
  @server.close
  @server = nil
end

Private Instance Methods

delete_client(io) click to toggle source
# File lib/moneta/server.rb, line 80
def delete_client(io)
  @ios.delete(io)
  @clients.delete(io)
end
handle(io, buffer) click to toggle source
# File lib/moneta/server.rb, line 90
def handle(io, buffer)
  buffer = @clients[io]
  return if buffer.bytesize < 8 # At least 4 bytes for the marshalled array
  size = buffer[0,4].unpack('N').first
  if size > MAXSIZE
    delete_client(io)
    return
  end
  return if buffer.bytesize < 4 + size
  buffer.slice!(0, 4)
  method, *args = Marshal.load(buffer.slice!(0, size))
  case method
  when :key?, :load, :delete, :increment, :create, :features
    io.write(pack @store.send(method, *args))
  when :store, :clear
    @store.send(method, *args)
    io.write(@nil ||= pack(nil))
  else
    raise 'Invalid method call'
  end
rescue IOError => ex
  warn "Moneta::Server - #{ex.message}" unless ex.message =~ /closed/
  delete_client(io)
rescue Exception => ex
  warn "Moneta::Server - #{ex.message}"
  io.write(pack Exception.new(ex.message))
end
mainloop() click to toggle source
# File lib/moneta/server.rb, line 54
def mainloop
  if ios = IO.select(@ios, nil, @ios, TIMEOUT)
    ios[2].each do |io|
      io.close
      delete_client(io)
    end
    ios[0].each do |io|
      if io == @server
        if client = @server.accept
          @ios << client
          @clients[client] = ''
        end
      elsif io.closed? || io.eof?
        delete_client(io)
      else
        handle(io, @clients[io] << io.readpartial(0xFFFF))
      end
    end
  end
rescue SignalException => ex
  warn "Moneta::Server - #{ex.message}"
  raise if ex.signo == 15 || ex.signo == 2 # SIGTERM or SIGINT
rescue Exception => ex
  warn "Moneta::Server - #{ex.message}"
end
pack(o) click to toggle source
# File lib/moneta/server.rb, line 85
def pack(o)
  s = Marshal.dump(o)
  [s.bytesize].pack('N') << s
end
start(options) click to toggle source
# File lib/moneta/server.rb, line 118
def start(options)
  if @socket = options[:socket]
    begin
      UNIXServer.open(@socket)
    rescue Errno::EADDRINUSE
      if client = (UNIXSocket.open(@socket) rescue nil)
        client.close
        raise
      end
      File.unlink(@socket)
      tries ||= 0
      (tries += 1) < 3 ? retry : raise
    end
  else
    TCPServer.open(options[:host] || '127.0.0.1', options[:port] || 9000)
  end
end