class Memcache::PGServer

Attributes

db[R]
table[R]

Public Class Methods

new(opts) click to toggle source
# File lib/memcache/pg_server.rb, line 15
def initialize(opts)
  @table = opts[:table]
  @db    = opts[:db] || ActiveRecord::Base.connection.raw_connection
end

Public Instance Methods

add(key, value, expiry = 0, flags = 0) click to toggle source
# File lib/memcache/pg_server.rb, line 87
def add(key, value, expiry = 0, flags = 0)
  delete_expired(key)
  insert(key, value, expiry, flags)
  value
rescue PGError => e
  nil
end
append(key, value) click to toggle source
# File lib/memcache/pg_server.rb, line 101
def append(key, value)
  delete_expired(key)
  result = db.exec %Q{
    UPDATE #{table}
      SET value = value || #{quote(value)}, updated_at = NOW()
      WHERE key = #{quote(key)} AND #{prefix_clause}
  }
  result.cmdtuples == 1
end
decr(key, amount = 1) click to toggle source
# File lib/memcache/pg_server.rb, line 67
def decr(key, amount = 1)
  incr(key, -amount)
end
delete(key) click to toggle source
# File lib/memcache/pg_server.rb, line 71
def delete(key)
  result = db.exec %Q{
    DELETE FROM #{table}
      WHERE key = #{quote(key)} AND #{prefix_clause}
  }
  result.cmdtuples == 1
end
flush_all(delay = nil) click to toggle source
# File lib/memcache/pg_server.rb, line 27
def flush_all(delay = nil)
  db.exec("TRUNCATE #{table}")
end
get(keys, cas = false) click to toggle source
# File lib/memcache/pg_server.rb, line 31
def get(keys, cas = false)
  # cas ignored for now
  return get([keys])[keys.to_s] unless keys.kind_of?(Array)
  return {} if keys.empty?

  keys = keys.collect {|key| quote(key.to_s)}.join(',')
  sql = %Q{
    SELECT key, value, flags FROM #{table}
      WHERE key IN (#{keys}) AND #{prefix_clause} AND #{expiry_clause}
  }

  results = {}
  db.query(sql).each do |row|
    results[row['key']] = {:value => row['value'], :flags => row['flags'].to_i}
  end
  results
end
incr(key, amount = 1) click to toggle source
# File lib/memcache/pg_server.rb, line 49
def incr(key, amount = 1)
  transaction do
    result = get(key)
    return unless result

    value = result[:value]
    return unless value =~ /^\d+$/

    value = value.to_i + amount
    value = 0 if value < 0
    db.exec %Q{
      UPDATE #{table} SET value = #{quote(value)}, updated_at = NOW()
        WHERE key = #{quote(key)} AND #{prefix_clause}
    }
    value
  end
end
name() click to toggle source
# File lib/memcache/pg_server.rb, line 20
def name
  @name ||= begin
    db_config = db.instance_variable_get(:@config)
    "#{db_config[:host]}:#{db_config[:database]}:#{table}"
  end
end
prepend(key, value) click to toggle source
# File lib/memcache/pg_server.rb, line 111
def prepend(key, value)
  delete_expired(key)
  result = db.exec %Q{
    UPDATE #{table}
      SET value = #{quote(value)} || value, updated_at = NOW()
      WHERE key = #{quote(key)} AND #{prefix_clause}
  }
  result.cmdtuples == 1
end
replace(key, value, expiry = 0, flags = 0) click to toggle source
# File lib/memcache/pg_server.rb, line 95
def replace(key, value, expiry = 0, flags = 0)
  delete_expired(key)
  result = update(key, value, expiry, flags)
  result.cmdtuples == 1 ? value : nil
end
set(key, value, expiry = 0, flags = 0) click to toggle source
# File lib/memcache/pg_server.rb, line 79
def set(key, value, expiry = 0, flags = 0)
  transaction do
    delete(key)
    insert(key, value, expiry, flags)
  end
  value
end

Private Instance Methods

delete_expired(key) click to toggle source
# File lib/memcache/pg_server.rb, line 163
def delete_expired(key)
  db.exec "DELETE FROM #{table} WHERE key = #{quote(key)} AND #{prefix_clause} AND NOT (#{expiry_clause})"
end
expiry_clause() click to toggle source
# File lib/memcache/pg_server.rb, line 167
def expiry_clause
  "expires_at IS NULL OR expires_at > NOW()"
end
expiry_sql(expiry) click to toggle source
# File lib/memcache/pg_server.rb, line 171
def expiry_sql(expiry)
  expiry = Time.at(expiry) if expiry > 60*60*24*30
  if expiry.kind_of?(Time)
    quote(expiry.to_s(:db))
  else
    expiry == 0 ? 'NULL' : "NOW() + interval '#{expiry} seconds'"
  end
end
insert(key, value, expiry, flags) click to toggle source
# File lib/memcache/pg_server.rb, line 123
def insert(key, value, expiry, flags)
  db.exec %Q{
    INSERT INTO #{table} (prefix, key, value, flags, updated_at, expires_at)
      VALUES (#{quoted_prefix}, #{quote(key)}, #{quote(value)}, #{flags.to_i}, NOW(), #{expiry_sql(expiry)})
  }
end
prefix_clause() click to toggle source
# File lib/memcache/pg_server.rb, line 184
def prefix_clause
  "prefix = #{quoted_prefix}"
end
quote(string) click to toggle source
# File lib/memcache/pg_server.rb, line 158
def quote(string)
  string.to_s.gsub(/'/,"\'")
  "'#{string}'"
end
quoted_prefix() click to toggle source
# File lib/memcache/pg_server.rb, line 180
def quoted_prefix
  quote(prefix || '')
end
transaction() { || ... } click to toggle source
# File lib/memcache/pg_server.rb, line 141
def transaction
  return yield if @in_transaction

  begin
    @in_transaction = true
    db.exec('BEGIN')
    value = yield
    db.exec('COMMIT')
    value
  rescue Exception => e
    db.exec('ROLLBACK')
    raise e
  ensure
    @in_transaction = false
  end
end
update(key, value, expiry, flags) click to toggle source
# File lib/memcache/pg_server.rb, line 130
def update(key, value, expiry, flags)
  db.exec %Q{
    UPDATE #{table}
      SET value = #{quote(value)}, 
          flags = #{flags.to_i},
          updated_at = NOW(),
          expires_at = #{expiry_sql(expiry)}
      WHERE key = #{quote(key)} AND #{prefix_clause}
  }
end