class PEROBS::PersistentObjectCache

Public Class Methods

new(size, flush_delay, klass, collection) click to toggle source

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

clear() click to toggle source

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

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
flush(now = false) click to toggle source

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
get(uid, ref = nil) click to toggle source

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(object, modified = true) click to toggle source

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