class UniCache
{UniCache} is Universal purpose Cache with Least Recently Used replacement policy by default. Cache can be configured with another policy.
{UniCache} is created with defined size (or without size limitations). {UniCache} inherits Hash and thus almost all Hash methods are usable. The cache content is set and referenced using Hash methods.
User can register callbacks that are run at various {UniCache} events (see: {UniCache#registerCallback}). “:getdata” callback is used to retreive cache data if not in cache. Other callbacks don't effect the UniCache
state (unless explicitly changed).
Cache can be setup with content using {UniCache#open} and content can be stored after use with {UniCache#close}. The “open”/“close” actions are defined in the corresponding callbacks.
{UniCache} is intended to be Thread safe. It uses Mutex to implement access control.
Usage example:
require 'unicache' # Create cache with size 2. c = UniCache.new( 2 ) # Register callbacks for some events (two for hit). c.registerCallback( :hit, Proc.new{ |k,v| puts "Hit: #{k}:#{v}" } ) c.registerCallback( :hit, Proc.new{ |k,v| puts "Found: #{k}:#{v}" } ) c.registerCallback( :miss, Proc.new{ |k,v| puts "Miss: #{k}:<NA>" } ) # Set some values. c[0] = 'foo' # set 0 as 'foo' c.put( 'bar', 'foo' ) # Get (or try to get) some values. a = c[ 'bar' ] # hit, a == 'foo' b = c.get( 0 ) # hit, b == 'foo' c.get( 'foo' ) # miss c.get( 2 ) # miss
Produces:
Hit: bar:foo Found: bar:foo Hit: 0:foo Found: 0:foo Miss: foo:<NA> Miss: 2:<NA>
Constants
- VERSION
Attributes
Access lock.
Cache size.
Public Class Methods
Cache initialization.
@param size [Integer] Cache size (> 0), nil for infinite size. @param evict [Object] Eviction policy.
# File lib/unicache.rb, line 84 def initialize( size, evict = LruEviction.new ) super() # Access control @lock = Mutex.new # Set cache size. resize( size ) # Set eviction policy. setEviction( evict ) # Declare all callbacks. @cb = NotifyHub.declare( :open, :close, :getdata, :add, :replace, :put, :overwrite, :remove, :valueremove, :hit, :miss, :peek ) end
# File lib/version.rb, line 3 def UniCache.version UniCache::VERSION end
Public Instance Methods
Get operator (See: {UniCache#get})
# File lib/unicache.rb, line 193 def []( key ) get( key ) end
Put operator (See: {UniCache#put})
# File lib/unicache.rb, line 167 def []=( key, value ) self.put( key, value ) end
Clear all Cache entries.
# File lib/unicache.rb, line 335 def clear @lock.lock self.each do |k,v| removeEntry( k ) end @evict.clear @lock.unlock end
Close {UniCache} access. The “:close” callback is executed. Typically the user would perform {UniCache} content store with the callback.
# File lib/unicache.rb, line 141 def close runCallbacks( :close, nil ) end
Get Cache entry existance by key (no effect to eviction). Uses {UniCache#peek}, i.e. peek CB is run.
@param key [Object] Entry key or tag. @return [Boolean] True if value found.
# File lib/unicache.rb, line 213 def exist?( key ) if peek( key ) true else false end end
Get Cache entry by key or return nil if not in Cache.
If block is provided, it is run under {UniCache} lock and will protect the used data from being removed (concurrently).
If “:getdata” callback is defined, it is used to get data. Data is always used, also when nil. {UniCache} lock is released before callback is called.
@param key [Object] Key (or tag) of the Cache entry. @yield Procedure to run with the data. @return [Object] Cache data.
# File lib/unicache.rb, line 184 def get( key, &blk ) @lock.lock ret = _get( key, &blk ) @lock.unlock ret end
Open {UniCache} for access. The “:open” callback is executed. Typically the user would perform {UniCache} content initialization with the callback.
# File lib/unicache.rb, line 133 def open runCallbacks( :open, nil ) end
Get Cache entry by key (no effect to eviction).
@param key [Object] Entry key or tag. @return [Object] Cache data.
# File lib/unicache.rb, line 202 def peek( key ) runCallbacks( :peek, key ) hash_fetch( key, nil ) end
Put new entry to the Cache. Make space for the new entry if needed.
@param key [Object] Key (or tag) of the Cache entry. @param value [Object] Value of the Cache entry.
# File lib/unicache.rb, line 158 def put( key, value ) @lock.lock ret = _put( key, value ) @lock.unlock ret end
Register a callback to be executed on Cache event. Callbacks are passed with following arguments: CacheKey, CacheValue, CacheObject.
Possible events:
- :open
-
Called when {UniCache#open} is executed. This is typically used to initialize the
UniCache
content. - :close
-
Called when {UniCache#close} is executed. This is typically used to store the
UniCache
content for next session. - :getdata
-
Data not found in cache, callback is used to fetch it. Data is always added to cache unless an exception is raised. Also all retrys should be captured into “:getdata”. <key,value> from request.
- :add
-
Item is added to Cache without anything being replaced. <key,value> from request.
- :replace
-
Item is added to Cache and another item is removed. <key,value> is evicted entry.
- :put
-
Item is added to Cache. Cache conditions has no effect i.e. always run for “put”. <key,value> from request.
- :overwrite
-
Existing entry value is replaced by new item value. <key,value> from request.
- :remove
-
Entry is deleted from Cache.
- :valueremove
-
Entry value is removed (remove or overwrite). <key,value> from old entry.
- :hit
-
Entry is found in Cache. <key,value> from cache.
- :miss
-
Entry is not found in Cache. <key> from request. Callback is called before “:getdata”.
- :peek
-
Cache peek. <key,value> from request.
Example:
registerCallback( :add, Proc.new do |k,v,o| puts "Key: #{k} with value #{v} added" end )
@param type [Symbol] Callback event. @param proc [Proc] Callback called with args: <key>, <value>, <self>.
# File lib/unicache.rb, line 311 def registerCallback( type, proc ) begin @cb[ type ].action( &proc ) rescue raise CallbackError, "UniCache: Trying to register invalid callback..." end end
Remove oldest Cache entry (Least Recently Used) or given.
@param key [Object] Key to remove. @return [Object, Object] Key/value pair removed or nil if no entries.
# File lib/unicache.rb, line 226 def remove( key = nil ) @lock.lock ret = _remove( key ) @lock.unlock ret end
Remove all callbacks for type or all.
@param type [Symbol] Remove callback by type.
# File lib/unicache.rb, line 323 def removeCallback( type = nil ) if type @cb.remove( type ) else @cb.ids.each do |id| @cb[id].remove end end end
Resize the Cache.
@param size [Integer] New Cache size, “> 0” or “nil”. @return [Integer] New Cache size.
# File lib/unicache.rb, line 238 def resize( size ) return nil if size == nil raise SizeError, "UniCache: Size must be bigger than 0" unless size > 0 @lock.lock # Remove entries that does not fit anymore. if @size && size < @size ( @size - size ).times do _remove end end ret = @size = size @lock.unlock ret end
Set the eviction policy. Evictor should have the same interface as {UniCache.LruEviction}.
@param evict [Object] Cache eviction policy.
# File lib/unicache.rb, line 108 def setEviction( evict ) @evict = evict end
Dummy definition for “store” just for removal.
# File lib/unicache.rb, line 147 def store(); end
Private Instance Methods
# File lib/unicache.rb, line 424 def _full if @size && self.length >= @size true else false end end
# File lib/unicache.rb, line 466 def _get( key, &blk ) ret = hash_fetch( key, nil ) if ret @evict.update( key ) runCallbacks( :hit, key ) else runCallbacks( :miss, key, nil ) if @cb[ :getdata ][0] # Get value using callback. @lock.unlock if @lock.locked? ret = runCallbacks( :getdata, key, nil ) @lock.lock _put( key, ret ) end end if block_given? # Get value using block. yield( ret ) else ret end end
# File lib/unicache.rb, line 433 def _put( key, value ) runAdd = false if hash_fetch( key, nil ) # Entry exists already. runCallbacks( :overwrite, key, value ) runCallbacks( :valueremove, key ) elsif _full # Overflow. runCallbacks( :replace, @evict.nextEvict ) _remove else # Delay add callback to have the entry value set. runAdd = true end @evict.update( key ) hash_store( key, value ) runCallbacks( :add, key ) if runAdd runCallbacks( :put, key ) self end
# File lib/unicache.rb, line 507 def _remove( key = nil ) if key unless keys.index( key ) @lock.unlock if @lock.locked? raise RemoveError, "Key \"#{key}\" does not exist..." end else key = @evict.remove end value = removeEntry( key ) [ key, value ] end
Remove entry from Cache.
# File lib/unicache.rb, line 525 def removeEntry( key ) if hash_fetch( key, nil ) runCallbacks( :remove, key ) runCallbacks( :valueremove, key ) value = hash_delete( key ) else nil end end
Run all callbacks per type.
# File lib/unicache.rb, line 537 def runCallbacks( type, key, value = nil ) unless value value = hash_fetch( key, nil ) end @cb[ type ].notify( key, value, self ) end