class Emcache

Constants

STATUS_LOCKED
STATUS_NOT_EXIST
STATUS_SUCCESS
VERSION

Attributes

logger[R]
prefix[R]
redis[R]
timeout[R]
ttl[R]

Public Class Methods

new(options = {}) click to toggle source
# File lib/emcache.rb, line 15
def initialize(options = {})
  parse_option(options.dup)

  @lua = {
    get: scripts('base', 'get'),
    set: scripts('base', 'set'),
    del: scripts('base', 'del')
  }
end

Public Instance Methods

call(method, keys, args) click to toggle source
# File lib/emcache.rb, line 25
def call(method, keys, args)
  logger.debug("method: #{method} sha: #{@lua[method].sha}"\
               " key: #{keys.inspect} args: #{args.inspect}")
  redis.with do |conn|
    begin
      ret = conn.evalsha(@lua[method].sha, keys, args)
      logger.debug("method: #{method} return: #{ret}")
      ret
    rescue Redis::CommandError => ex
      logger.debug("exception: #{ex.inspect}")
      raise ex unless ex.message.start_with? 'NOSCRIPT '

      load_script(conn, method)
      retry
    end
  end
end
del(key) click to toggle source
# File lib/emcache.rb, line 58
def del(key)
  call :del, [key], [prefix]
end
get(key) { |key| ... } click to toggle source
# File lib/emcache.rb, line 43
def get(key)
  status, value = call :get, [key], [prefix, block_given? ? timeout : 0]
  if block_given? && status != STATUS_SUCCESS
    lock = value
    value = yield(key)

    _set(key, lock, value) if status == STATUS_NOT_EXIST
  end
  value
end
set(key, value) click to toggle source
# File lib/emcache.rb, line 54
def set(key, value)
  _set(key, '*', value)
end

Private Instance Methods

_set(key, lock, value) click to toggle source
# File lib/emcache.rb, line 66
def _set(key, lock, value)
  call :set, [key, value], [prefix, lock, ttl]
end
load_script(conn, method) click to toggle source
# File lib/emcache.rb, line 70
def load_script(conn, method)
  logger.debug("load script: #{method}")
  server_sha = conn.script('load', @lua[method].code)
  fail('sha mismatch') if server_sha != @lua[method].sha
end
parse_option(options) click to toggle source
# File lib/emcache.rb, line 86
def parse_option(options)
  @prefix = options.fetch(:prefix, 'DEFAULT')
  @timeout = options.fetch(:timeout, 100)
  @ttl = options.fetch(:ttl, 0)
  @logger = Logger.new(STDOUT)
  @logger.level = options.fetch(:log_level, Logger::WARN)

  cpo_opts = { size: 5, timeout: 5 }
  cpo_opts.merge!(options.fetch(:connection_pool, {}))

  redis_opts = {}
  redis_opts.merge!(options.fetch(:redis, {}))
  @redis = ConnectionPool.new(cpo_opts) { Redis.new(redis_opts) }
end
script(name) click to toggle source
# File lib/emcache.rb, line 76
def script(name)
  File.read("#{File.dirname(__FILE__)}/../scripts/#{name}.lua")
end
scripts(*names) click to toggle source
# File lib/emcache.rb, line 80
def scripts(*names)
  code = names.map { |name| script(name) }.join("\n")
  sha = Digest::SHA1.hexdigest(code)
  OpenStruct.new code: code, sha: sha
end