[ZODB-Dev] persisting "immutable" classes

Jeremy Hylton jeremy at zope.com
Sat Feb 28 11:30:18 EST 2004


On Sat, 2004-02-28 at 11:05, John Belmonte wrote:
> > Beware, however, that the containing persistent object does
> > not recognized modifications of the non-persistent object.
> > If you are not careful, modifications may be lost -- in an
> > apparently non-deterministic fashion (it is in fact
> > deterministic but asynchronous to "normal" operation).
> 
> My question was regarding immutable classes, where the "non-persistent" 
> (in your words) object is never modified.  An example would be a class 
> representing a time+ID tuple that has total ordering, for use as a key 
> in a BTree job queue.   I'd like to know in this case if there are any 
> other issues I should be aware of.  Also I'd like to know what kind of 
> space overhead there is in deriving from Persistent, and whether doing 
> so negates the savings I get by defining slots.

The other issue to be aware of is that the immutable object is persisted
by value instead of by reference.  That is, if two different first-class
persistent objects refer to the same second-class persistent object,
each first-class object will get a copy of the second-class object in
its database record.  (First-class means inherits from Persistent;
second-class means anything else that can be pickled.)  Since the
objects are immutable, it may not be a problem if copies are made.  On
the other hand, they may waste space and they would break code that did
"is" tests.

Another issue to consider is how many objects are instantiated when a
first-class object is loaded.  When you load object id 0, the root, you
load all the keys and values that are stored in the root.  If those
objects are second-class persistent objects, they are immediately
created in memory.  If they are first-class persistent object, a ghost
is created; the actual object state isn't loaded until it is accessed. 
When would this be an issue?  Say you've got an attribute that points to
a large blob of binary data that is seldomly used.  It may be helpful to
create a Persistent blob class to hold the object, so that it isn't
loaded until it is used.  I've found a PersistentString class useful on
occasion for this reason.

As far for the space overhead, I recently added a comment to
cPersistence.h that describes the space overhead:

/* How big is a persistent object?
 
   12  PyGC_Head is two pointers and an int
    8  PyObject_HEAD is an int and a pointer
  
   12  jar, oid, cache pointers
    8  ring struct
    8  serialno
    4  state + extra
 
  (52) so far
 
    4  dict ptr
    4  weaklist ptr
  -------------------------
   64  only need 62, but obmalloc rounds up to multiple of eight
                                                                                
  Even a ghost requires 64 bytes.  It's possible to make a persistent
  instance with slots and no dict, which changes the storage needed.
                                                                                
*/

There are other costs to consider:
144 bytes for instance dict (holding up to 5 attrs) (if the object is
not a ghost)
28 bytes for PyStringObject for 8-byte oid

Jeremy





More information about the ZODB-Dev mailing list