class RingCache
Constants
- VERSION
Attributes
capacity[R]
target_hit_rate[R]
Public Class Methods
new(options = {})
click to toggle source
# File lib/ring_cache.rb, line 9 def initialize(options = {}) @duplicate_on_store = options.fetch(:duplicate_on_store, false) @duplicate_on_retrieve = options.fetch(:duplicate_on_retrieve, false) execute_on_retrieve = options.fetch(:execute_on_retrieve, []) @execute_on_retrieve = execute_on_retrieve.kind_of?(Array) ? execute_on_retrieve : [execute_on_retrieve] @capacity = options.fetch(:capacity, nil) @target_hit_rate = options.fetch(:target_hit_rate, nil) unless @target_hit_rate.nil? or (@target_hit_rate > 0.0 and @target_hit_rate < 1.0) raise ArgumentError, 'Invalid target_hit_rate' end reset end
Public Instance Methods
evict(key)
click to toggle source
# File lib/ring_cache.rb, line 25 def evict(key) if @cache.has_key?(key) @access_time_index.delete([@cache[key][:last_accessed_at], key]) @cache.delete(key) true else false end end
fetch(key, options = {}, &block)
click to toggle source
# File lib/ring_cache.rb, line 35 def fetch(key, options = {}, &block) cache_nil = options.fetch(:cache_nil, true) unless (data = read(key)) data = catch(:dont_cache) do data_to_cache = block.call write(key, data_to_cache) unless data_to_cache.nil? and !cache_nil data_to_cache end end data end
has_key?(key)
click to toggle source
# File lib/ring_cache.rb, line 48 def has_key?(key) @cache.has_key?(key) end
hit_rate()
click to toggle source
# File lib/ring_cache.rb, line 52 def hit_rate (@access_count > 0) ? (@hit_count / @access_count.to_f) : 0.0 end
last_access(key)
click to toggle source
# File lib/ring_cache.rb, line 56 def last_access(key) has_key?(key) ? @cache[key][:last_accessed_at] : nil end
read(key)
click to toggle source
# File lib/ring_cache.rb, line 93 def read(key) read!(key) rescue KeyNotFoundError return nil end
read!(key)
click to toggle source
# File lib/ring_cache.rb, line 60 def read!(key) @access_count += 1 if @cache.has_key?(key) access_time = Time.now @access_time_index.delete([@cache[key][:last_accessed_at], key]) @access_time_index << [access_time, key] @cache[key][:last_accessed_at] = access_time @hit_count += 1 data = @cache[key][:data] data = data.dup if @duplicate_on_retrieve and !data.nil? unless @execute_on_retrieve.empty? or data.nil? @execute_on_retrieve.each do |method| method = method.to_sym if data.respond_to?(method) data.send(method) elsif data.kind_of?(Enumerable) and data.all? { |d| d.respond_to?(method) } data.each { |d| d.send(method) } else raise RuntimeError, "Retrieved data does not respond to #{method.inspect}" end end end data else fail KeyNotFoundError, "Cache does not have content indexed by #{key}" end end
reset()
click to toggle source
# File lib/ring_cache.rb, line 99 def reset @cache = {} @access_time_index = SortedSet.new @access_count = 0 @hit_count = 0 true end
size()
click to toggle source
# File lib/ring_cache.rb, line 107 def size @cache.size end
write(key, data)
click to toggle source
# File lib/ring_cache.rb, line 111 def write(key, data) unless evict(key) evict_oldest if must_evict? end data = data.dup if @duplicate_on_store and !data.nil? access_time = Time.now @cache[key] = { last_accessed_at: access_time, data: data } @access_time_index << [access_time, key] true end
Private Instance Methods
evict_oldest()
click to toggle source
# File lib/ring_cache.rb, line 124 def evict_oldest access_time_index_entry = @access_time_index.first @cache.delete(access_time_index_entry[1]) @access_time_index.delete(access_time_index_entry) end
must_evict?()
click to toggle source
# File lib/ring_cache.rb, line 130 def must_evict? (capacity and size >= capacity) or (target_hit_rate and hit_rate >= target_hit_rate) end