I really like the the acts_as_cached interface for model caching, but there are a few models that we wanted to cache in the process memory, but still maintain expiration functionality.  We came up with this:
class InMemoryCacheStore < Hash
  def initialize(options={})
    @expire_entries = options[:expire_entries]
  end
  def set(key, data, ttl = nil)
    if @expire_entries && ttl
      self[key] = Entry.new(data.dup, Time.now.to_i + ttl) rescue data
    else
      self[key] = Entry.new(data.dup, nil) rescue data 
    end
  end
  def get(key)
    r = self[key]
    if @expire_entries && r && r.expires_at < Time.now.to_i
      self.delete(key)
      r = nil
    end
    r ? r.obj : nil
  end
private
  class Entry
    attr_accessor :obj            attr_accessor :expires_at 
    def initialize(obj, expires_at)
      @obj = obj
      @expires_at = expires_at
    end
  end
end
Example without expiration:
class SomeModel < ActiveRecord::Base
  acts_as_cached :store => InMemoryCacheStore.new
end
Example with expiration:
class SomeModel < ActiveRecord::Base
  acts_as_cached :store => InMemoryCacheStore.new(:expire_entires => true)
  def self.ttl
    24.hours
  end
end
Performance for 1000 lookups:
db on localhost: 1.52 secs
memcached on localhost: 0.78 secs
InMemoryCacheStore: 0.345 secs
No comments:
Post a Comment