Next: , Previous: Serialization, Up: Tutorial

2.6 Persistent Classes

Fortunately we can solve these problems for CLOS objects.

     * (defclass my-persistent-class ()
        ((slot1 :accessor slot1)
         (slot2 :accessor slot2))
        (:metaclass persistent-metaclass))
     * (setq foo (make-instance 'my-persistent-class))
     => #<MY-PERSISTENT-CLASS {492F4F85}>
     * (add-to-root "foo" foo)
     => NIL
     * (add-to-root "bar" foo)
     => NIL
     * (eq (get-from-root "foo")
           (get-from-root "bar"))
     => T

What's going on here? Persistent classes, that is, classes which use the persistent-metaclass metaclass, are given unique IDs (accessable through ele::oid.) They are serialized simply by their OID and class. Their slot values are stored in separate entries, keyed by OID and slot. Loading (deserializing) a persistent class

     * (get-from-root "foo")
     => #<MY-PERSISTENT-CLASS {492F4F85}>

instantiates the object or finds it from the cache, if it already exists. (The cache is a weak hash-table, so gets flushed on GCs.) The slot values are NOT loaded until you ask for them. (In fact, the persisted slots don't have space allocated for them in the instances, because we're reading from the database.)

     * (setf (slot1 foo) "one")
     => "one"
     * (setf (slot2 foo) "two")
     => "two"
     * (slot1 foo)
     => "one"
     * (slot2 foo)
     => "two"

Changes made to them propogate automatically:

     * (setf (slot1 foo) "three")
     => "three"
     * (slot1 (get-from-root "bar"))
     => "three"

Although it is hard to see here, serialization / deserialization of persistent classes is fast, much faster than ordinary CLOS objects. Finally, they do not suffer from merge-conflicts (more on this later.)

In short: persistent classes solve the problems associated with storing ordinary CLOS objects. We'll see later that BTrees solve the problems associated with storing hash-tables.