lib/perobs/Cache.rb in perobs-2.1.1 vs lib/perobs/Cache.rb in perobs-2.2.0
- old
+ new
@@ -67,11 +67,13 @@
# to increase performance.
if obj.respond_to?(:is_poxreference?)
# If this condition triggers, we have a bug in the library.
raise RuntimeError, "POXReference objects should never be cached"
end
+
if @transaction_stack.empty?
+ # We are not in transaction mode.
idx = index(obj)
if (old_obj = @writes[idx]) && old_obj._id != obj._id
# There is another old object using this cache slot. Before we can
# re-use the slot, we need to sync it to the permanent storage.
old_obj._sync
@@ -81,49 +83,33 @@
# When a transaction is active, we don't have a write cache. The read
# cache is used to speed up access to recently used objects.
cache_read(obj)
# Push the reference of the modified object into the write buffer for
# this transaction level.
- unless @transaction_stack.last.include?(obj)
- @transaction_stack.last << obj
+ unless @transaction_stack.last.include?(obj._id)
+ @transaction_stack.last << obj._id
+ @transaction_objects[obj._id] = obj
end
end
end
- # Remove an object from the write cache. This will prevent a modified
- # object from being written to the back-end store.
- def unwrite(obj)
- if @transaction_stack.empty?
- idx = index(obj)
- if (old_obj = @writes[idx]).nil? || old_obj._id != obj._id
- raise RuntimeError, "Object to unwrite is not in cache"
- end
- @writes[idx] = nil
- else
- unless @transaction_stack.last.include?(obj)
- raise RuntimeError, 'unwrite failed'
- end
- @transaction_stack.last.delete(obj)
- end
- end
-
# Return the PEROBS::Object with the specified ID or nil if not found.
# @param id [Fixnum or Bignum] ID of the cached PEROBS::ObjectBase
- def object_by_id(id)
- idx = id & @mask
- # The index is just a hash. We still need to check if the object IDs are
- # actually the same before we can return the object.
- if (obj = @writes[idx]) && obj._id == id
- # The object was in the write cache.
- return obj
- elsif (obj = @reads[idx]) && obj._id == id
- # The object was in the read cache.
- return obj
- end
+ #def object_by_id(id)
+ # idx = id & @mask
+ # # The index is just a hash. We still need to check if the object IDs are
+ # # actually the same before we can return the object.
+ # if (obj = @writes[idx]) && obj._id == id
+ # # The object was in the write cache.
+ # return obj
+ # elsif (obj = @reads[idx]) && obj._id == id
+ # # The object was in the read cache.
+ # return obj
+ # end
- nil
- end
+ # nil
+ #end
# Flush all pending writes to the persistant storage back-end.
def flush
@writes.each { |w| w._sync if w }
@writes = ::Array.new(2 ** @bits)
@@ -138,16 +124,18 @@
# Tell the cache to start a new transaction. If no other transaction is
# active, the write cached is flushed before the transaction is started.
def begin_transaction
if @transaction_stack.empty?
- # This is the top-level transaction. Flush the write buffer to save
- # the current state of all objects.
+ # The new transaction is the top-level transaction. Flush the write
+ # buffer to save the current state of all objects.
flush
else
- @transaction_stack.last.each do |o|
- o._stash(@transaction_stack.length - 1)
+ # Save a copy of all objects that were modified during the enclosing
+ # transaction.
+ @transaction_stack.last.each do |id|
+ @transaction_objects[id]._stash(@transaction_stack.length - 1)
end
end
# Push a transaction buffer onto the transaction stack. This buffer will
# hold a reference to all objects modified during this transaction.
@transaction_stack.push(::Array.new)
@@ -161,11 +149,12 @@
when 0
raise RuntimeError, 'No ongoing transaction to end'
when 1
# All transactions completed successfully. Write all modified objects
# into the backend storage.
- @transaction_stack.pop.each { |o| o._sync }
+ @transaction_stack.pop.each { |id| @transaction_objects[id]._sync }
+ @transaction_objects = ::Hash.new
else
# A nested transaction completed successfully. We add the list of
# modified objects to the list of the enclosing transaction.
transactions = @transaction_stack.pop
# Merge the two lists
@@ -180,21 +169,24 @@
# the transaction started.
def abort_transaction
if @transaction_stack.empty?
raise RuntimeError, 'No ongoing transaction to abort'
end
- @transaction_stack.pop.each { |o| o._restore(@transaction_stack.length) }
+ @transaction_stack.pop.each do |id|
+ @transaction_objects[id]._restore(@transaction_stack.length)
+ end
end
# Clear all cached entries. You must call flush before calling this
# method. Otherwise unwritten objects will be lost.
def reset
# The read and write caches are Arrays. We use the _bits_ least
# significant bits of the PEROBS::ObjectBase ID to select the index in
# the read or write cache Arrays.
@reads = ::Array.new(2 ** @bits)
@writes = ::Array.new(2 ** @bits)
- @transaction_stack = []
+ @transaction_stack = ::Array.new
+ @transaction_objects = ::Hash.new
end
# Don't include the cache buffers in output of other objects that
# reference Cache.
def inspect