Update of /project/elephant/cvsroot/elephant/doc
In directory clnet:/tmp/cvs-serv14127/doc
Modified Files:
make-ref.lisp user-guide.texinfo
Log Message:
Default inihibit annoying warnings
--- /project/elephant/cvsroot/elephant/doc/make-ref.lisp 2007/04/21 17:22:35 1.9
+++ /project/elephant/cvsroot/elephant/doc/make-ref.lisp 2007/04/24 12:58:10 1.10
@@ -34,7 +34,7 @@
;; (sb-texinfo:generate-includes #p"/Users/eslick/Work/fsrc/elephant-cvs/doc/includes/"
(sb-texinfo:generate-includes include-dir-path
(find-package :elephant)
- (find-package :elephant-backend)
+ (find-package :elephant-data-store)
(find-package :elephant-memutil)
(find-package :elephant-system))))
--- /project/elephant/cvsroot/elephant/doc/user-guide.texinfo 2007/04/24 03:02:26 1.14
+++ /project/elephant/cvsroot/elephant/doc/user-guide.texinfo 2007/04/24 12:58:10 1.15
@@ -398,12 +398,17 @@
and their accesses cannot be protected by transactions. (Ordinary
multi-process synchronization would be required instead).
+The @code{:index} option tells Elephant whether to maintain an
+inverted index that maps slot values to their parent objects. The
+behavior of indexed classes and class slots are discussed in depth in
+@ref{Class Indices}.
+
Persistent classes have their metaobject protocols modified through
specializations on @code{persistent-metaclass}. These specializations
-create special slot metaobjects: @code{transient-slot-definition},
-@code{persistent-slot-definition} and direct and effective versions of
-each. For the MOP aficionado the highlights of the new class
-initialization protocols are as follows:
+include the creation of special slot metaobjects:
+@code{transient-slot-definition}, @code{persistent-slot-definition}
+and direct and effective versions of each. For the MOP aficionado the
+highlights of the new class initialization protocols are as follows:
@itemize
@item @code{shared-initialize :around} ensures that this class inherits from
@@ -432,15 +437,15 @@
@subsection Instance Creation
-To the user, persistent objects are created as usual with a call to
-@code{make-instance}. Initforms and slot initargs behave as the user
-expects. The call to @code{make-instance} of a persistent class will
-fail unless there is a default @code{store-controller} instance in the
-variable @code{*store-controller*} or the @code{:sc} keyword argument
-is provided a valid store controller object. The store controller is
-required to provide a unique object id, initialize the specification
-pointer of the instance and to store the values of any initialized
-slots. The initialization process is as follows:
+Persistent objects are created just like standard objects, with a call
+to @code{make-instance}. Initforms and slot initargs behave as the
+user expects. The call to @code{make-instance} of a persistent class
+will fail unless there is a default @code{store-controller} instance
+in the variable @code{*store-controller*} or the @code{:sc} keyword
+argument is provided a valid store controller object. The store
+controller is required to provide a unique object id, initialize the
+specification pointer of the instance and to store the values of any
+initialized slots. The initialization process is as follows:
@itemize
@item @code{initialize-instance :before} is called to initialize the
@@ -455,82 +460,107 @@
are updated appropriately.
@end itemize
-Persistent slots are initialized under the following conditions:
+Persistent slots are initialized only under the following conditions:
-@enumerate
+@itemize
@item An initarg is provided to @code{make-instance}
-@item The database slot value is unbound, an initform exists and from-oid was not provided
-@end enumerate
-
-@subsection Persistent Class Lifecycle
-
+@item The database slot value is unbound, an initform exists and from-oid was not specified
+@end itemize
+After initialization the persistent instance is added to its host
+store controller's object cache. This cache is a weak hash table that
+maps oids to object instances. So after initialization the following
+state has been created:
-The initialize instance protocol and persistent slot initialization
-provides us some insight into how persistent class instances are
-recreated in a fresh lisp image. To get a persistent instance, the
-instance must be retrieved from the database via the root or a class
-index. When a reference to an instance is deserialized, the deserializer
-looks in a
+@itemize
+@item @strong{Placeholder Instance:} An instance of the class is in memory, containing storage for
+ the oid, the specification reference, lisp instance data and any
+ transient slot values. We call this the placeholder instance which
+ mediates access to persistent values, but does not itself persist.
+@item @strong{Cached Reference:} A weak reference to the instance is in the store controller object cache
+@item @strong{Memory References:} A normal reference to the instance is (maybe) retained by the caller of
+ @code{make-instance}.
+@item @strong{Database Slot Values:} The data store contains the persistent slot values that were initialized,
+ indexed by the object id and slot name.
+@item @strong{Database References:} If the resulting placeholder instance was written to a persistent slot,
+ added to a btree or the class is indexed, a @strong{reference}
+to the instance was written into the data store. Today this reference
+consists of an oid and a class name. If this reference is reachable,
+then the persistent object can be reconstructed using the
+@code{:from-oid} argument.
+@end itemize
-Because the oid is already known
-when we deserialize the class reference from the database, the use the
-@code{:from-oid} argument to indicate that this object already exists.
-Because any initializable values are set
+If you mnanually create an object using an OID which already exists in
+the database, @code{initargs} to @code{make-instance} take precedence
+over existing values in the database, which in turn take precedence
+over any @code{initforms} defined in the class.
+
+@subsection Persistent Instance Lifecycle
+
+The distributed nature of persistent instance storage results in some
+interesting behaviors, especially with respect to transient slots.
+The prior section detailed the state of the system after the original
+initialization of an object. The object can then be in a number of
+different states:
+@itemize
+@item @strong{Resident:} The canonical state of an in-use persistent
+ object as described in the initialization section above.
+@item @strong{Unreferenced, Unreclaimed:} All memory references to the
+ object have been dropped but the placeholder instance has not yet
+ been garbage collected. The weak pointer still exists in the cache.
+ If a database reference is fetched from the data store, the cached
+ value will be used.
+@item @strong{Non-resident:} The object only exists as reachable database
+ references and slot values. This is the state after garbage collection
+ of the placeholder instance.
+@item @strong{Recreated:} An intermediary state where a non resident object
+ is fetched from the data store and its placeholder object must be
+ recreated prior to the object enter the resident state.
+@end itemize
- The two properties of
-@code{persistent} can be specified explicitly during instance
-creation:
+The garbage collection of the placeholder instance is an important
+feature. This means that we can have more objects in our system than
+are currently resident in memory. If this were not the case, what
+would be the point of an object database?
+
+The recreated state deserves to be discussed in more detail. We
+learned earlier that the database reference contains the oid and class
+of the object, and of course we know the store-controller the
+reference is stored into@footnote{If you attempt to store an object
+from one store into another, the system will issue an error condition
+called @code{cross-reference-error}}, so this information is
+sufficient to reconstruct the placeholder instance.
+
+When the reference is deserialized, its oid is used to look up the
+object in the store controller's object cache. If this fails, then
+the instance is created with a call much like this:
@lisp
-(make-instance 'my-pclass :from-oid 100 :sc *store-controller*)
+(make-instance 'pclass :from-oid 2000 :sc *store-controller*)
@end lisp
-These three elements, class, oid and store controller is all that is
-needed to create a new instance
-
-
-If you do make an instance with a specified OID which already exists
-in the database, @code{initargs} to @code{make-instanc} take
-precedence over values in the database, which take precedences over
-any @code{initforms} defined in the class.
-
-Think of it this way. If you get a value from a persistent index and that value is a persistent object, then you want object identity, the ability to inspect it's type, slot access, etc. The only way to do that is to create something in memory which provides this. The only way to that is to make sure your lisp has had the chance to construct everything it needs via make-instance.
-
-The :from-oid argument to make-instance overrides some of the normal make-instance behavior by inhibiting all initform initialization as the object's slots are assumed to already be valid, so you have exactly the behavior you want.
-
-There are two caveats to this nice model: transient slots and make-instance methods.
-
-Transient Slots: they have the semantics of ordinary lisp slots - you cannot expect them to persist between images or after their placeholder has been garbage collected. If you drop all references to an object with transient slots, those slots are reclaimed by the GC. If you try to access them again later, they are reset to their default state (unbound, initforms or make-instance computations).
-
-Make-instance specializers: If you override the typical make-instance via :before, :after, :around or specialized on your class, you have to make sure that you predicate on :from-oid (this will be documented in the new manual) to avoid resetting persistent values. If :from-oid is given a value, then you can assume the object is being reconstituted and you don't need to do anything special for the persistent slots.
-
-However, if you want to use persistent slots to compute the value of some transient slots, then a make-instance specializer is a good place to do it. indexed-btree is an example of this, an in-memory hash is cached in the transient slot for reads and writes are mirrored to a serialized hash in a persistent slot.
-
-@subsection Using Persistent Slots
-
-* What happens to persistent objects when store-controller is closed?
+The @code{:from-oid} argument to @code{make-instance} overrides some
+of the normal make-instance behavior by inhibiting all initform
+initialization as the object's slots are assumed to be properly
+initialized from the original call to @code{make-instance}.
@subsection Using Transient Slots
-The best policy for initializing transient slots is an @code{:after}
-method on @code{initialize-instance}.
+What about transient slots? Transients slots are tied to the
+placeholder object where their storage is allocated. While the
+persistent slots are permanently stored in the data store, transient
+slots can be garbage collected when all memory references have been
+dropped, even if database references exist.
-During a given lisp session transient values will be cached regardless
-of how often you retrieve an object from the store as long as there is
-a reference to it in memory or there are zero references but the
-object has not yet been collected by the lisp garbage collector.
-After collection, if you retrieve an object from the store its
+After collection, if you retrieve an object from the store, its
transient slots will be reset to the slot initforms from the class
-definition. You can only use @code{:initargs} to initialize transient
-or persistent slots during the initial call to @code{make-instance} or
-by manually creating the instance from an oid (see below).
+definition. You can only reliably use @code{:initargs} to initialize
+transient or persistent slots during the initial call to
+@code{make-instance} or when manually creating the instance from an oid.
-A good policy is to initialize transient values using an @code{:after}
-method on @code{initialize-instance} to initialize transient values
-using system defaults or from persistent slot values. That way
-whether the slots are valid when the object is pulled from
+Here is an example illustrating the ephemeral nature of transient
+slots:
@lisp
(setf pobj1 (make-instance 'my-pclass :pslot1 1 :tslot3 3))
@@ -560,14 +590,56 @@
@end lisp
The implications of this behavior is that you need to think carefully
-about how to use transient values. Essentially you cannot make
+about how to use employ transient values. Essentially you cannot make
assumptions about the state of transient values in objects loaded from
-the store unless you know that they were loaded and cannot be GC'ed.
+the store unless you know that they were loaded at some point in time
+and cannot be GC'ed (i.e. they are stored in a list or hash table).
-The @code{:index} option tells Elephant whether to maintain an
-inverted index that maps slot values to their parent objects. The
-behavior of indexed classes and class slots are discussed in depth in
-@ref{Class Indices}.
+A good policy is to initialize transient values using an @code{:after}
+method on @code{initialize-instance}. This allows you to initialize
+transient values using either system defaults or persistent slot
+values. That way you can ensure that the transient slots are always
+in a consistent state when accessed by the application, regardless of
+when the placeholder object was recreated.
+
+In general, transient slots are a good place for intermediate values
+in a computation or to cache frequently read items to avoid
+deserialization overhead. @code{indexed-btree} is an example of this
+approach, an in-memory hash is cached in the transient slot for reads
+and writes are mirrored to a serialized hash in a persistent slot.
+The @code{:after} method just copies the persistent hash value to the
+transient slot.
+
+@subsection Using Persistent Slots
+
+Persistent slot use is straightforward. You can read from them, write
+to them or make them unbound. Remember that every access goes to the
+data store. This makes reads relatively expensive as they may result
+in a disk seek. Writes can be doubly expensive, especially outside a
+transaction, as the write will result in a synchronous disk synch
+operation.
+
+Reads and writes require the home store controller to be valid and
+open. The placeholder object's specification pointer is used to
+retrieve the @code{store-controller} object. If this object is closed
+or mising, the system will give you a restart option to reopen the
+controller and continue.
+
+Persistent slot behavior is implemented by overloading the relevant
+MOP functions controlling slot access:
+
+@itemize
+@item @code{slot-value-using-class}
+@item @code{(setf slot-value-using-class)}
+@item @code{slot-boundp-using-class}
+@item @code{slot-makunbound-using-class}
+@end itemize
+
+Each of these functions retrieves the home store-controller for the
+instance and then calls a method specialized on the class of that
+store controller. This method is responsible for mapping the oid and
+slotname of the slot access to the appropriate value in the data
+store.
@subsection Class Redefinition
@@ -580,52 +652,12 @@
- What if you connect to an old database with a new class specification?
(ref to class indicies behavior)
-@subsection Synchronizing Code and Database
-
-
-@subsection Persistent objects and the MOP
-
-This section provides increased detail on the use of the MOP to create
-and support persistent objects.
-
-new slot types
-- transient-slot
-- persistent-slot
-
-slot instantiation protocols
-- effective-slot-definition
-- direct-slot-definition-class
-- compute-effective-slot-definition
-- compute-effective-slot-definition-initargs
-
-class initialization protocols
-- shared-initialize :around (class)
-- finalize-inheritance :around (class)
-- reinitialize-instance :around (class)
-
-instance initialization protocols
-- initialize-instance :before (instance)
-- shared-initialize :around
+MOP:
- update-instance-for-redefinied-class
- update-instance-for-different-class
-slot access protocol
-- slot-value-using-class (setf)
-- slot-boundp-using-class
-- slot-makunbound-using-clas
-
-@subsection Overriding methods on persistent objects
-
-* slot types
-* caching
-* slot access protocol
-
-Readers, writers, accessors, and @code{slot-value-using-class} are
-employed in redirecting slot accesses to the database, so override
-these with care. Because @code{slot-value, slot-boundp,
-slot-makunbound} are not generic functions, they are not guaranteed by
-the specification to work properly with persistent slots. However the
-proper behavior has been verified on SBCL, Allegro and Lispworks.
+@subsection Synchronizing Code and Database
+
@node Class Indices
@comment node-name, next, previous, up