Class: PEROBS::PersistentObjectCache

Inherits:
Object
  • Object
show all
Defined in:
lib/perobs/PersistentObjectCache.rb

Instance Method Summary collapse

Constructor Details

#initialize(size, flush_delay, klass, collection) ⇒ PersistentObjectCache

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.

Parameters:

  • size (Integer)

    Minimum number of objects to be cached at a time

  • flush_delay (Integer)

    Determines how often non-forced flushes are ignored in a row before the flush is really done.

  • klass (Class)

    The class of the objects to be cached. Objects must provide a uid() method that returns a unique ID for every object.

  • collection

    The object collection the objects belong to. It

    must provide a ::load method.



52
53
54
55
56
57
58
59
60
# File 'lib/perobs/PersistentObjectCache.rb', line 52

def initialize(size, flush_delay, klass, collection)
  @size = size
  @klass = klass
  @collection = collection
  @flush_delay = @flush_counter = flush_delay
  @flush_times = 0

  clear
end

Instance Method Details

#clearObject

Remove all entries from the cache.



125
126
127
128
129
130
131
132
133
134
# File 'lib/perobs/PersistentObjectCache.rb', line 125

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) ⇒ Object

Remove a object from the cache.

Parameters:

  • uid (Integer)

    unique ID of object to remove.



101
102
103
104
105
106
107
108
# 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) ⇒ Object

Write all excess modified objects into the backing store. If now is true all modified objects will be written.

Parameters:

  • now (Boolean) (defaults to: false)


113
114
115
116
117
118
119
120
121
122
# File 'lib/perobs/PersistentObjectCache.rb', line 113

def flush(now = false)
  if now || (@flush_counter -= 1) <= 0
    @modified_entries.each do |id, object|
      object.save
    end
    @modified_entries = ::Hash.new
    @flush_counter = @flush_delay
  end
  @flush_times += 1
end

#get(uid, ref = nil) ⇒ Object

Retrieve a object reference from the cache.

Parameters:

  • uid (Integer)

    uid of the object to retrieve.

  • ref (Object) (defaults to: nil)

    optional reference to be used by the load method



84
85
86
87
88
89
90
91
92
93
94
95
96
97
# 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) ⇒ Object

Insert an object into the cache.

Parameters:

  • object (Object)

    Object to cache

  • modified (Boolean) (defaults to: true)

    True if the object was modified, false otherwise



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/perobs/PersistentObjectCache.rb', line 65

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
    index = object.uid % @size
    @unmodified_entries[index] = object
  end

  nil
end