lib/perobs/ObjectBase.rb in perobs-2.1.1 vs lib/perobs/ObjectBase.rb in perobs-2.2.0

- old
+ new

@@ -118,27 +118,29 @@ attr_reader :_id, :store, :myself # New PEROBS objects must always be created by calling # Store.new(). # PEROBS users should never call this method or equivalents of derived # methods directly. - def initialize(store) - @store = store - unless @store.object_creation_in_progress - ::Kernel.raise ::RuntimeError, - "All PEROBS objects must exclusively be created by calling " + - "Store.new(). Never call the object constructor directly." - end - @_id = @store._new_id + # @param p [PEROBS::Handle] PEROBS handle + def initialize(p) + _initialize(p) + end + + # This is the real code for initialize. It is called from initialize() but + # also when we restore objects from the database. In the later case, we + # don't call the regular constructors. But this code must be exercised on + # object creation with new() and on restore from DB. + # param p [PEROBS::Handle] PEROBS handle + def _initialize(p) + @store = p.store + @_id = p.id @store._register_in_memory(self, @_id) ObjectSpace.define_finalizer(self, ObjectBase._finalize(@store, @_id)) @_stash_map = nil # Allocate a proxy object for this object. User code should only operate # on this proxy, never on self. @myself = POXReference.new(@store, @_id) - - # Let the store know that we have a modified object. - @store.cache.cache_write(self) end # This method generates the destructor for the objects of this class. It # is done this way to prevent the Proc object hanging on to a reference to # self which would prevent the object from being collected. This internal @@ -148,12 +150,14 @@ end # This method can be overloaded by derived classes to do some massaging on # the data after it has been restored from the database. This could either # be some sanity check or code to migrate the object from one version to - # another. - def post_restore + # another. It is also the right place to initialize non-persistent + # instance variables as initialize() will only be called when objects are + # created for the first time. + def restore end # Two objects are considered equal if their object IDs are the same. def ==(obj) return false unless obj.is_a?(ObjectBase) @@ -179,13 +183,14 @@ # Read the object from database. db_obj = store.db.get_object(id) klass = store.class_map.id_to_class(db_obj['class_id']) # Call the constructor of the specified class. - obj = store._construct_po(Object.const_get(klass), id) + obj = Object.const_get(klass).allocate + obj._initialize(Handle.new(store, id)) obj._deserialize(db_obj['data']) - obj.post_restore + obj.restore obj end # Restore the object state from the storage back-end. @@ -193,52 +198,35 @@ def _restore(level) # Find the most recently stored state of this object. This could be on # any previous stash level or in the regular object DB. If the object # was created during the transaction, there is not previous state to # restore to. - id = nil + data = nil if @_stash_map (level - 1).downto(0) do |lvl| if @_stash_map[lvl] - id = @_stash_map[lvl] + data = @_stash_map[lvl] break end end end - unless id - if @store.db.include?(@_id) - id = @_id - end - end - if id - db_obj = store.db.get_object(id) + if data + # We have a stashed version that we can restore from. + _deserialize(data) + elsif @store.db.include?(@_id) + # We have no stashed version but can restore from the database. + db_obj = store.db.get_object(@_id) _deserialize(db_obj['data']) end end # Save the object state for this transaction level to the storage # back-end. The object gets a new ID that is stored in @_stash_map to map # the stash ID back to the original data. def _stash(level) - db_obj = { - 'class' => self.class.to_s, - 'data' => _serialize - } - @_stash_map = [] unless @_stash_map + @_stash_map ||= ::Array.new # Get a new ID to store this version of the object. - @_stash_map[level] = stash_id = @store._new_id - @store.db.put_object(db_obj, stash_id) - end - - # Library internal method. Do not use outside of this library. - # @private - def _change_id(id) - # Unregister the object with the old ID from the write cache to prevent - # cache corruption. The objects are index by ID in the cache. - @store.cache.unwrite(self) - @store._collect(@_id) - @store._register_in_memory(self, id) - @_id = id + @_stash_map[level] = _serialize end end end