Skip to content

Commit

Permalink
Initial addition of ttl cache under the names LruRedux::TTL::Cache an…
Browse files Browse the repository at this point in the history
…d LruRedux::TTL::ThreadSafeCache.

Added #ttl method (noop) to lru cache to keep cache api consistent.
  • Loading branch information
Seberius committed Mar 29, 2015
1 parent ca99733 commit e4f4b6d
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 7 deletions.
2 changes: 2 additions & 0 deletions lib/lru_redux.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@

require "lru_redux/thread_safe_cache"

require "lru_redux/ttl"

require "lru_redux/version"
17 changes: 14 additions & 3 deletions lib/lru_redux/cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,29 @@
#
# This is an ultra efficient 1.9 freindly implementation
class LruRedux::Cache
def initialize(max_size)
def initialize(*args)
max_size, _ = args

raise ArgumentError.new(:max_size) if @max_size < 1

@max_size = max_size
@data = {}
end

def max_size=(size)
def max_size=(max_size)
max_size ||= @max_size

raise ArgumentError.new(:max_size) if @max_size < 1
@max_size = size

@max_size = max_size

@data.shift while @data.size > @max_size
end

def ttl=(_)
nil
end

def getset(key)
found = true
value = @data.delete(key){ found = false }
Expand Down
4 changes: 4 additions & 0 deletions lib/lru_redux/ttl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require "lru_redux/util"

require "lru_redux/ttl/cache"
require "lru_redux/ttl/thread_safe_cache"
186 changes: 186 additions & 0 deletions lib/lru_redux/ttl/cache.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
module LruRedux
module TTL
class Cache
def initialize(*args)
max_size, ttl = args

ttl ||= :none

raise ArgumentError.new(:max_size) if
max_size < 1
raise ArgumentError.new(:ttl) unless
ttl == :none || ((ttl.is_a? Numeric) && ttl >= 0)

@max_size = max_size
@ttl = ttl
@data_lru = {}
@data_ttl = {}
end

def max_size=(max_size)
max_size ||= @max_size

raise ArgumentError.new(:max_size) if
max_size < 1

@max_size = max_size

resize
end

def ttl=(ttl)
ttl ||= @ttl

raise ArgumentError.new(:ttl) unless
ttl == :none || ((ttl.is_a? Numeric) && ttl >= 0)

@ttl = ttl

ttl_evict
end

def getset(key)
ttl_evict

found = true
value = @data_lru.delete(key){ found = false }
if found
@data_lru[key] = value
else
result = @data_lru[key] = yield
@data_ttl = Time.now

if @data_lru.size > @max_size
key, _ = @data_lru.tail

@data_ttl.delete(key)
@data_lru.delete(key)
end

result
end
end

def fetch(key)
ttl_evict

found = true
value = @data_lru.delete(key){ found = false }
if found
@data_lru[key] = value
else
yield if block_given?
end
end

def [](key)
ttl_evict

found = true
value = @data_lru.delete(key){ found = false }
if found
@data_lru[key] = value
else
nil
end
end

def []=(key, val)
ttl_evict

@data_lru.delete(key)
@data_ttl.delete(key)

@data_lru[key] = val
@data_ttl[key] = Time.now

if @data_lru.size > @max_size
key, _ = @data_lru.tail

@data_ttl.delete(key)
@data_lru.delete(key)
end

val
end

def each
ttl_evict

array = @data_lru.to_a
array.reverse!.each do |pair|
yield pair
end
end

# used further up the chain, non thread safe each
alias_method :each_unsafe, :each

def to_a
ttl_evict

array = @data_lru.to_a
array.reverse!
end

def delete(key)
ttl_evict

@data_lru.delete(key)
@data_ttl.delete(key)
end

alias_method :evict, :delete

def key?(key)
ttl_evict

@data_lru.key?(key)
end

alias_method :has_key?, :key?

def clear
@data_lru.clear
@data_ttl.clear
end

def count
@data_lru.size
end

# for cache validation only, ensures all is sound
def valid?
@data_lru.size == @data_ttl.size
end

protected

def ttl_evict
return if @ttl == :none

ttl_horizon = Time.now - @ttl
key, time = @data_ttl.tail

until time.nil? || time > ttl_horizon
@data_ttl.delete(key)
@data_lru.delete(key)

key, time = @data_ttl.tail
end
end

def resize
ttl_evict

while @data_lru.size > @max_size
key, _ = @data_lru.tail

@data_ttl.delete(key)
@data_lru.delete(key)
end
end
end
end
end

3 changes: 3 additions & 0 deletions lib/lru_redux/ttl/thread_safe_cache.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class LruRedux::TTL::ThreadSafeCache < LruRedux::TTL::Cache
include LruRedux::Util::SafeSync
end
14 changes: 10 additions & 4 deletions lib/lru_redux/util/safe_sync.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ module Util
module SafeSync
include MonitorMixin

def initialize(max_size)
super(max_size)
def initialize(*args)
super(*args)
end

def max_size=(size)
def max_size=(max_size)
synchronize do
super(size)
super(max_size)
end
end

def ttl=(ttl)
synchronize do
super(ttl)
end
end

Expand Down

0 comments on commit e4f4b6d

Please sign in to comment.