Class: PEROBS::ObjectBase

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

Overview

Base class for all persistent objects. It provides the functionality common to all classes of persistent objects.

Direct Known Subclasses

Array, Hash, Object

Constant Summary collapse

NATIVE_CLASSES =
[
  NilClass, Integer, Float, String, Time,
  TrueClass, FalseClass
]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(p) ⇒ ObjectBase

New PEROBS objects must always be created by calling # Store.new(). PEROBS users should never call this method or equivalents of derived methods directly.

Parameters:



148
149
150
# File 'lib/perobs/ObjectBase.rb', line 148

def initialize(p)
  _initialize(p)
end

Instance Attribute Details

#_idObject (readonly)

Returns the value of attribute _id.



142
143
144
# File 'lib/perobs/ObjectBase.rb', line 142

def _id
  @_id
end

#myselfObject (readonly)

Returns the value of attribute myself.



142
143
144
# File 'lib/perobs/ObjectBase.rb', line 142

def myself
  @myself
end

#storeObject (readonly)

Returns the value of attribute store.



142
143
144
# File 'lib/perobs/ObjectBase.rb', line 142

def store
  @store
end

Class Method Details

._finalize(store, id, ruby_object_id) ⇒ Object

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 method is not intended for users to call.



173
174
175
# File 'lib/perobs/ObjectBase.rb', line 173

def ObjectBase._finalize(store, id, ruby_object_id)
  proc { store._collect(id, ruby_object_id) }
end

.read(store, id) ⇒ Object

Read an raw object with the specified ID from the backing store and instantiate a new object of the specific type.



241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/perobs/ObjectBase.rb', line 241

def ObjectBase.read(store, id)
  # 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 = Object.const_get(klass).allocate
  obj._initialize(Handle.new(store, id))
  obj._deserialize(db_obj['data'])
  obj.restore

  obj
end

Instance Method Details

#==(obj) ⇒ Object

Two objects are considered equal if their object IDs are the same.



202
203
204
205
# File 'lib/perobs/ObjectBase.rb', line 202

def ==(obj)
  return false unless obj.is_a?(ObjectBase)
  obj && @_id == obj._id
end

#_check_assignment_value(val) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/perobs/ObjectBase.rb', line 221

def _check_assignment_value(val)
  if val.respond_to?(:is_poxreference?)
    # References to other PEROBS::Objects must be handled somewhat
    # special.
    if @store != val.store
      PEROBS.log.fatal 'The referenced object is not part of this store'
    end
  elsif val.is_a?(ObjectBase)
    PEROBS.log.fatal 'A PEROBS::ObjectBase object escaped! ' +
      'Have you used self() instead of myself() to get the reference ' +
      'of the PEROBS object that you are trying to assign here?'
  elsif !NATIVE_CLASSES.include?(val.class)
    PEROBS.log.fatal "Assigning objects of class #{val.class} is not " +
      "supported. Only PEROBS objects or one of the following classes " +
      "are supported: #{NATIVE_CLASSES.join(', ')}"
  end
end

#_initialize(p) ⇒ Object

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



157
158
159
160
161
162
163
164
165
166
167
# File 'lib/perobs/ObjectBase.rb', line 157

def _initialize(p)
  @store = p.store
  @_id = p.id
  @store._register_in_memory(self, @_id)
  ObjectSpace.define_finalizer(
    self, ObjectBase._finalize(@store, @_id, object_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)
end

#_restore(level) ⇒ Object

Restore the object state from the storage back-end.

Parameters:

  • level (Integer)

    the transaction nesting level



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/perobs/ObjectBase.rb', line 257

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 no previous state to
  # restore to.
  data = nil
  if @_stash_map
    (level - 1).downto(0) do |lvl|
      break if (data = @_stash_map[lvl])
    end
  end
  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

#_stash(level) ⇒ Object

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.



281
282
283
284
285
# File 'lib/perobs/ObjectBase.rb', line 281

def _stash(level)
  @_stash_map ||= ::Array.new
  # Get a new ID to store this version of the object.
  @_stash_map[level] = _serialize
end

#_syncObject

Write the object into the backing store database.



208
209
210
211
212
213
214
215
216
217
218
# File 'lib/perobs/ObjectBase.rb', line 208

def _sync
  # Reset the stash map to ensure that it's reset before the next
  # transaction is being started.
  @_stash_map = nil

  db_obj = {
    'class_id' => @store.class_map.class_to_id(self.class.to_s),
    'data' => _serialize
  }
  @store.db.put_object(db_obj, @_id)
end

#_transfer(store) ⇒ Object

Library internal method to transfer the Object to a new store.

Parameters:

  • store (Store)

    New store



179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/perobs/ObjectBase.rb', line 179

def _transfer(store)
  @store = store
  # Remove the previously defined finalizer as it is attached to the old
  # store.
  ObjectSpace.undefine_finalizer(self)
  # Register the object as in-memory object with the new store.
  @store._register_in_memory(self, @_id)
  # Register the finalizer for the new store.
  ObjectSpace.define_finalizer(
    self, ObjectBase._finalize(@store, @_id, object_id))
  @myself = POXReference.new(@store, @_id)
end

#restoreObject

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. 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.



198
199
# File 'lib/perobs/ObjectBase.rb', line 198

def restore
end