Next: , Previous: Serialization, Up: Tutorial


2.5 Persistent Classes

The Common Lisp Object System and the Metaobject Protocol, gives us the tools to solve these problems for 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. Slot values are stored separately (and invisible to the user) keyed by OID and slot. Loading (deserializing) a persistent class

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

instantiates the object or finds it in a memory cache if it already exists. (The cache is a weak hash-table, so gets flushed on GCs if no other references to the persistent object are kept in memory). 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"

You can also create persistent classes using the convenience macro defpclass.

     (defpclass my-persistent-class ()
       ((slot1 :accessor slot1)
        (slot2 :accessor slot2)))

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 when accessed within a transaction (see below). 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.