class TaskJuggler::DataCache
This class provides a global data cache that can be used to store and retrieve values indexed by a key. The cache is size limited. When maximum capacity is reached, a certain percentage of the least requested values is dropped from the cache. The primary purpose of this global cache is to store values that are expensive to compute but may be need on several occasions during the program execution.
Public Class Methods
# File lib/taskjuggler/DataCache.rb, line 56 def initialize resize flush # Counter for the number of writes to the cache. @stores = 0 # Counter for the number of found values. @hits = 0 # Counter for the number of not found values. @misses = 0 # Counter for hash collisions @collisions = 0 end
Public Instance Methods
Ruby 1.8 has a buggy hash key generation algorithm that leads to many hash collisions. We completely disable caching on 1.8.
# File lib/taskjuggler/DataCache.rb, line 89 def cached(*args) yield end
Completely flush the cache. The statistic counters will remain intact, but all data values are lost.
# File lib/taskjuggler/DataCache.rb, line 80 def flush @entries = {} end
For now, we use this randomly determined size.
# File lib/taskjuggler/DataCache.rb, line 70 def resize(size = 100000) @highWaterMark = size # Flushing out the least used entries is fairly expensive. So we only # want to do this once in a while. The lowWaterMark determines how much # of the entries will survive the flush. @lowWaterMark = size * 0.9 end
# File lib/taskjuggler/DataCache.rb, line 120 def to_s <<"EOT" Entries: #{@entries.size} Stores: #{@stores} Collisions: #{@collisions} Hits: #{@hits} Misses: #{@misses} Hit Rate: #{@hits * 100.0 / (@hits + @misses)}% EOT end
Private Instance Methods
Store value into the cache using key to tag it. key must be unique and must be used to load the value from the cache again. You cannot store nil values!
# File lib/taskjuggler/DataCache.rb, line 133 def store(value, unhashedKey, key) @stores += 1 if @entries.size > @highWaterMark while @entries.size > @lowWaterMark # How many entries do we need to delete to get to the low watermark? toDelete = @entries.size - @lowWaterMark @entries.delete_if do |foo, e| # Hit counts age with every cleanup. (e.hits -= 1) < 0 && (toDelete -= 1) >= 0 end end end @entries[key] = DataCacheEntry.new(unhashedKey, value) value end