class PEROBS::PersistentObjectCache
Public Class Methods
This cache class manages the presence of objects that primarily live in a backing store but temporarily exist in memory as well. To work with these objects, direct references must be only very short lived. Indirect references can be done via a unique ID that the object must provide. Due to the indirect references the Ruby garbage collector can collect these objects. To reduce the read and write latencies of the backing store this class keeps a subset of the objects in memory which prevents them from being collected. All references to the objects must be resolved via the get() method to prevent duplicate instances in memory of the same in-store object. The cache uses a least-recently-used (LRU) scheme to cache objects. @param size [Integer] Minimum number of objects to be cached at a time @param flush_delay [Integer] Determines how often non-forced flushes are
ignored in a row before the flush is really done. If flush_delay is smaller than 0 non-forced flushed will always be ignored.
@param klass [Class] The class of the objects to be cached. Objects must
provide a uid() method that returns a unique ID for every object.
@param collection [] The object collection the objects belong to. It
must provide a ::load method.
# File lib/perobs/PersistentObjectCache.rb, line 53 def initialize(size, flush_delay, klass, collection) @size = size @klass = klass @collection = collection @flush_delay = @flush_counter = flush_delay @flush_times = 0 clear end
Public Instance Methods
Remove all entries from the cache.
# File lib/perobs/PersistentObjectCache.rb, line 128 def clear # This Array stores all unmodified entries. It has a fixed size and uses # a % operation to compute the index from the object ID. @unmodified_entries = ::Array.new(@size) # This Hash stores all modified entries. It can grow and shrink as # needed. A flush operation writes all modified objects into the backing # store. @modified_entries = ::Hash.new end
Remove a object from the cache. @param uid [Integer] unique ID of object to remove.
# File lib/perobs/PersistentObjectCache.rb, line 101 def delete(uid) @modified_entries.delete(uid) index = uid % @size if (object = @unmodified_entries[index]) && object.uid == uid @unmodified_entries[index] = nil end end
Write all excess modified objects into the backing store. If now is true all modified objects will be written. @param now [Boolean]
# File lib/perobs/PersistentObjectCache.rb, line 113 def flush(now = false) if now || (@flush_delay >= 0 && (@flush_counter -= 1) <= 0) @modified_entries.each do |id, object| object.save # Add the object to the unmodified object cache. We might still need # it again soon. @unmodified_entries[object.uid % @size] = object end @modified_entries = ::Hash.new @flush_counter = @flush_delay end @flush_times += 1 end
Retrieve a object reference from the cache. @param uid [Integer] uid of the object to retrieve. @param ref [Object] optional reference to be used by the load method
# File lib/perobs/PersistentObjectCache.rb, line 84 def get(uid, ref = nil) # First check if it's a modified object. if (object = @modified_entries[uid]) return object end # Then check the unmodified object list. if (object = @unmodified_entries[uid % @size]) && object.uid == uid return object end # If we don't have it in memory we need to load it. @klass::load(@collection, uid, ref) end
Insert an object into the cache. @param object [Object] Object
to cache @param modified [Boolean] True if the object was modified, false otherwise
# File lib/perobs/PersistentObjectCache.rb, line 66 def insert(object, modified = true) unless object.is_a?(@klass) raise ArgumentError, "You can insert only #{@klass} objects in this " + "cache. You have tried to insert a #{object.class} instead." end if modified @modified_entries[object.uid] = object else @unmodified_entries[object.uid % @size] = object end nil end