module Iowa
# Simple LRU cache for caching pages.
class LRUCache
# Initialize the empty LRU cache, and set the maximum number of elements
# that it will contain or the max time to live (in seconds) of a cache item.
# If both a max and a maxttl are set, the max is a hard maximum that will
# not be exceeded.
def initialize(max=20, maxttl=nil)
@cache = {}
@queue = []
@ttl_cache = {}
@max = max
@maxttl = maxttl
@finalizers = []
end
# Check to see if the cache contains the given key.
def include?(key)
@cache.include?(key)
end
# Return the element identified by the given key.
def [](key)
r = nil
if @cache.has_key? key
r = @cache[key]
@queue.push @queue.delete(key)
@ttl_cache[key] = Time.now.to_i
end
r
end
# Set the element of the cache identified by the given key.
def []=(key, val)
if @queue.length == @max
d = @queue.shift
@cache.delete d
end
if @queue.first and @maxttl
now = Time.now.to_i
while ((@ttl_cache[@queue.first] + @maxttl) < now)
d = @queue.shift
do_finalization(d,@cache[d])
@cache.delete d
end
end
@cache[key] = val
@ttl_cache[key] = Time.now.to_i
@queue.push key
end
# Allows one to set the maximum size of the cache queue. If the queue
# is currently larger than the size that it is being set to, elements
# will be expired until the queue is at the maximum size.
def size=(max)
@max = max
while @queue.length > @max
d = @queue.shift
do_finalization(d,@cache[d])
@cache.delete d
end
@max
end
alias maxsize= size=
# Return the maximum size of the cache.
def maxsize
@max
end
# Return the current size of the cache.
def size
@queue.length
end
# Return a copy of current set of keys to cache elements.
def queue
@queue.dup
end
def add_finalizer(*args,&block)
@finalizers.push [block,args]
end
def do_finalization(key,obj)
begin
@finalizers.each do |f|
f[0].call(key,obj,*f[1])
end
rescue Exception => e
puts e, e.backtrace
raise e
end
end
end
end