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

lock[R]

Access lock.

size[R]

Cache size.

Public Class Methods

new( size, evict = LruEviction.new ) click to toggle source

Cache initialization.

@param size [Integer] Cache size (> 0), nil for infinite size. @param evict [Object] Eviction policy.

Calls superclass method
# 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
version() click to toggle source
# File lib/version.rb, line 3
def UniCache.version
    UniCache::VERSION
end

Public Instance Methods

[]( key ) click to toggle source

Get operator (See: {UniCache#get})

# File lib/unicache.rb, line 193
def []( key )
    get( key )
end
Also aliased as: hash_get_op
[]=( key, value ) click to toggle source

Put operator (See: {UniCache#put})

# File lib/unicache.rb, line 167
def []=( key, value )
    self.put( key, value )
end
Also aliased as: hash_set_op
clear() click to toggle source

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() click to toggle source

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
exist?( key ) click to toggle source

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( key, &blk ) click to toggle source

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
hash_get_op( key )
Alias for: []
hash_set_op( key, value )
Alias for: []=
hash_store()
Alias for: store
open() click to toggle source

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
peek( key ) click to toggle source

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( key, value ) click to toggle source

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
registerCallback( type, proc ) click to toggle source

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( key = nil ) click to toggle source

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
removeCallback( type = nil ) click to toggle source

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( size ) click to toggle source

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
setEviction( evict ) click to toggle source

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
store() click to toggle source

Dummy definition for “store” just for removal.

# File lib/unicache.rb, line 147
def store(); end
Also aliased as: hash_store

Private Instance Methods

_full() click to toggle source
# File lib/unicache.rb, line 424
def _full
    if @size && self.length >= @size
        true
    else
        false
    end
end
_get( key ) { |ret| ... } click to toggle source
# 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
_put( key, value ) click to toggle source
# 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
_remove( key = nil ) click to toggle source
# 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
removeEntry( key ) click to toggle source

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
runCallbacks( type, key, value = nil ) click to toggle source

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