elephant-cvs
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
April 2007
- 2 participants
- 99 discussions
Update of /project/elephant/cvsroot/elephant/doc
In directory clnet:/tmp/cvs-serv14475/doc
Modified Files:
user-guide.texinfo
Log Message:
Handle error conditions in change-class protocol; more docs
--- /project/elephant/cvsroot/elephant/doc/user-guide.texinfo 2007/04/24 12:58:10 1.15
+++ /project/elephant/cvsroot/elephant/doc/user-guide.texinfo 2007/04/24 16:39:30 1.16
@@ -10,10 +10,9 @@
* Serialization details:: The devil hides in the details.
* Persistent Classes and Objects:: All the dirt on persistent objects.
* Class Indices:: In-depth discussion about indexing persistent indices.
-@c * Querying persistent instances:: Retrieving instances of classes.
* Using BTrees:: Using the native btree.
* Using Cursors:: Low-level access to BTrees.
-* BTree Indices:: Alternative ways to index collections.
+* The BTree index:: Alternative ways to reference objects in btrees
* Transaction Details:: Develop a deeper understanding of transactions and avoid the pitfalls.
* Multi-repository Operation:: Specifying repositories.
* Multi-threaded Applications:: What considerations are required for safe multi-threading
@@ -643,21 +642,70 @@
@subsection Class Redefinition
-This section discusses the appropriate model a user should employ in
-thinking about the behavior of persistent object when their clases are
-redefined.
-
-- What happens when you redefine a class online?
-- Drop & add slots? Change slot status?
-- What if you connect to an old database with a new class specification?
- (ref to class indicies behavior)
-
-MOP:
-- update-instance-for-redefinied-class
-- update-instance-for-different-class
+Class redefinition is problematic in the current (0.9) version of
+Elephant. The usual CLOS mechanisms are properly implemented, but
+updating instances will only work for those instances that are in
+memory at the time. Instances that are non-resident will not be
+updated. This is usually not as big a problem as it seems, because
+the slot values are stored independently. An outline of the update
+procedure follows:
+
+The function @code{update-instance-for-redefined-class} is called by
+CLOS whenever @code{defclass} is re-evaluated and results in a change
+in the list of slots.
-@subsection Synchronizing Code and Database
+For transient slots the behavior is the same as it is in CLOS for
+all in-memory slots.
+@itemize
+@item Added slots: are added to the object and their initforms
+ called just as if they were created without initargs
+@item Discarded slots: are dropped and their values lost
+@end itemize
+
+Persistent slots have a slightly different behavior, as only resident
+(those with valid placeholder objects) objects are updated.
+
+@itemize
+@item Added slots (resident): are added to the object and the initforms
+ are called only on in-memory objects, as in an empty call to
+ @code{make-instance}
+@item Added slots (non-resident): the added slots will have unbound values
+@item Discarded slots (resident): slots are dropped from the class and become
+ inaccessible, but their values are not deleted from the database. This
+ is a precautionary measure as losing persistent data because of an
+ accidental re-evaluation while editing a defclass could be painful. If
+ you add the slot back, the original value will be accessible regardless of
+ the initform.
+@item Discarded slots (non-resident): This has the same behavior as resident objects,
+ as no side effects are made on the objects or their slots
+@end itemize
+
+There are additional considerations for matching class indexing
+options in the class object to the actual indices in the database.
+The following section will discuss synchronizing these if they
+diverge.
+
+@emph{(Note: release 0.9.1 should fix this by providing an oid->class map that allows
+the system to cheaply iterate over all objects and update them appropriately. This
+hasn't been done yet due to performance implications. See Trac system for the appropriate
+tickets)}
+
+@subsection Support for @code{change-class}
+
+Elephant also supports the @code{change-class} by overloading
+@code{update-instance-for-different-class}. The handling of slots in
+this case is identical to the class redefinition above. Persistent
+and transient slot values are retained if their name matches a
+slotname in the new class and initforms are called on newly added
+slots. Valid initargs for any slot will override this default behavior
+and set the slot value to the initarg value.
+
+Because the instance is guaranteed to be resident, the operation has none of the
+resident/non-resident conflicts above.
+
+Changing a persistent instance to a non-persistent class is not
+allowed and will result in an error.
@node Class Indices
@comment node-name, next, previous, up
@@ -706,111 +754,43 @@
somewhat user customizable; documentation for this exists in the source
file referenced above.
-@c @node Querying persistent instances
-@c @comment node-name, next, previous, up
-@c @section Querying persistent instances
-@c
-@c A SQL select-like interface is in the works, but for now queries are
-@c limited to manual mapping over class instances or doing small queries
-@c with @code{get-instances-*} functions. One advantage of this is that
-@c it is easy to estimate the performance costs of your queries and to
-@c choose standard and derived indices that give you the ordering and
-@c performance you want.
-@c
-@c There is, however, a quick and dirty query API example that is not
-@c officially supported in the release but is intended to invite comment.
-@c This is an example of a full query system that would automatically
-@c perform joins, use the appropriate indices and perhaps even adaptively
-@c suggest or add indices to facilitate better performance on common
-@c queries.
-@c
-@c There are two functions @ref{Function elephant:get-query-instances}
-@c and @ref{Function elephant:map-class-query} which accept a set of
-@c constraints instead of the familiar value or range arguments.
-@c
-@c We'll use the classes @code{person} and @code{department} to
-@c illustrate how to perform queries over a set of objects that may be
-@c constrainted by their relationships to other objects.
-@c
-@c @lisp
-@c (defpclass person ()
-@c ((name :initarg :name :index t)
-@c (salary :initarg :salary :index t)
-@c (department :initarg :dept)))
-@c
-@c (defmethod print-object ((p person) stream)
-@c (format stream "#<PERS: ~A>" (slot-value p 'name)))
-@c
-@c (defun print-name (inst)
-@c (format t "Name: ~A~%" (slot-value inst 'name)))
-@c
-@c (defpclass department ()
-@c ((name :initarg :name)
-@c (manager :initarg :manager)))
-@c
-@c (defmethod print-object ((d department) stream)
-@c (format stream "#<DEPT ~A, mgr = ~A>"
-@c (slot-value d 'name)
-@c (when (slot-boundp d 'manager)
-@c (slot-value (slot-value d 'manager) 'name))))
-@c @end lisp
-@c
-@c Here we have a simple employee database with managers (also of type
-@c person) and departments. This simple system will provide fodder for
-@c some reasonably complex constraints. Let's create a few departments.
-@c
-@c @lisp
-@c (setf marketing (make-instance 'department :name "Marketing"))
-@c (setf engineering (make-instance 'department :name "Engineering"))
-@c (setf sales (make-instance 'department :name "Sales"))
-@c @end lisp
-@c
-@c And manager @code{people} for the departments.
-@c
-@c @lisp
-@c (make-instance 'person :name "George" :salary 140000 :department marketing)
-@c (setf (slot-value marketing 'manager) *)
-@c
-@c (make-instance 'person :name "Sally" :salary 140000 :department engineering)
-@c (setf (slot-value engineering 'manager) *)
-@c
-@c (make-instance 'person :name "Freddy" :salary 180000 :department sales)
-@c (setf (slot-value sales 'manager) *)
-@c @end lisp
-@c
-@c And of course we need some folks to manage
-@c
-@c @lisp
-@c (defparameter *names*
-@c '("Jacob" "Emily" "Michael" "Joshua" "Andrew" "Olivia" "Hannah" "Christopher"))
-@c
-@c (defun random-element (list)
-@c "Choose a random element from the list and return it"
-@c (nth (random (length list)) list))
-@c
-@c (with-transaction ()
-@c (loop for i from 0 upto 40 do
-@c (make-instance 'person
-@c :name (format nil "~A~A" (random-elephant *names*) i)
-@c :salary (floor (+ (* (random 1000) 100) 30000))
-@c :department (case (random 3)
-@c (0 marketing)
-@c (1 engineering)
-@c (2 sales)))))
-@c @end lisp
-@c
-@c
-@c Now we can look at a few queries.
-@c
-@c @lisp
-@c (defun get-managers ()
-@c (get-query-instances `((person
-@c
-@c For those familiar with SQL, if an instance of @code{person} has a
-@c pointer to an instance of @code{department} then that relation can be
-@c used to perform a join. Of course joins in the object world won't
-@c return a table, instead they will return conjunctions of objects that
-@c satisfy a mutual set of constraints.
+@subsection Synchronizing Classes and Data Stores
+
+Sometimes you may change a defclass form and then connect to a
+database with instances that do not match the current defclass
+definition. Because of the defclass behavior above, there is no need
+to detect this case as the behavior will be as if all instances were
+non-resident at redefinition time. However, this is an issue for
+indexed classes as the cost of indexing is high. There is a
+synchronization policy which updates either the class or the online
+class indexing mechanism at the time you try to perform an index
+operation (i.e. when @code{find-class-index} is called).
+
+A policy is selected by setting the value of
+@code{*default-indexed-class-synch-policy*} with the appropriate
+policy:
+
+@itemize
+@item :class - The class is the master, and indices are deleted for any slots
+ that are no longer indexed
+@item :db - The database is the master and the class indexing annotations are
+ updated so that the slots that satisfy @code{class-indexedp-by-name}
+ are isomorphic to the existing indices in the db.
+@item :union - This does what you would expect, updates the class to match any
+ existing indices and creates new indices.
+@end itemize
+
+Derived slots can be problematic as they may depend on slot values
+that no longer exist in the changed defclass. This will result in an
+error, so for now you will have to manage any mismatches such as this
+yourself.
+
+@emph{Note: release 0.9.1 should fix both mismatches and performance issues related
+to derived indices by allowing the user to provide hints as to which slot values the
+index depends. This will allow the system to only update when the appropriate slots
+change and to delete or inhibit derived indicies when slots are deleted. We will also
+improve error handling for this case, so you can delete the derived index and continue
+performing the write to a persistent object that flagged the error.}
@node Using BTrees
@comment node-name, next, previous, up
@@ -829,15 +809,17 @@
blocks of data is relatively inexpensive after a seek and comparisons
on objects that are stored in memory is cheap.
+
+
@node Using Cursors
@comment node-name, next, previous, up
@section Using Cursors
-Empty.
+- initialized, not-initialized
-@node BTree Indicies
+@node The BTree Index
@comment node-name, next, previous, up
-@section BTree Indicies
+@section The BTree Index
Empty.
@@ -1103,10 +1085,123 @@
@section CL-SQL Data Store
+
@node Postmodern Data Store
@comment node-name, next, previous, up
@section Postmodern Data Store
+The postmodern data store is not yet integrated. It should be documented
+for the forthcoming release 0.9.1 or 0.9.2.
+
@node Native Lisp Data Store
@comment node-name, next, previous, up
@section Native Lisp Data Store
+
+The native lisp data store is vaporware at this time.
+
+@c @node Querying persistent instances
+@c @comment node-name, next, previous, up
+@c @section Querying persistent instances
+@c
+@c A SQL select-like interface is in the works, but for now queries are
+@c limited to manual mapping over class instances or doing small queries
+@c with @code{get-instances-*} functions. One advantage of this is that
+@c it is easy to estimate the performance costs of your queries and to
+@c choose standard and derived indices that give you the ordering and
+@c performance you want.
+@c
+@c There is, however, a quick and dirty query API example that is not
+@c officially supported in the release but is intended to invite comment.
+@c This is an example of a full query system that would automatically
+@c perform joins, use the appropriate indices and perhaps even adaptively
+@c suggest or add indices to facilitate better performance on common
+@c queries.
+@c
+@c There are two functions @ref{Function elephant:get-query-instances}
+@c and @ref{Function elephant:map-class-query} which accept a set of
+@c constraints instead of the familiar value or range arguments.
+@c
+@c We'll use the classes @code{person} and @code{department} to
+@c illustrate how to perform queries over a set of objects that may be
+@c constrainted by their relationships to other objects.
+@c
+@c @lisp
+@c (defpclass person ()
+@c ((name :initarg :name :index t)
+@c (salary :initarg :salary :index t)
+@c (department :initarg :dept)))
+@c
+@c (defmethod print-object ((p person) stream)
+@c (format stream "#<PERS: ~A>" (slot-value p 'name)))
+@c
+@c (defun print-name (inst)
+@c (format t "Name: ~A~%" (slot-value inst 'name)))
+@c
+@c (defpclass department ()
+@c ((name :initarg :name)
+@c (manager :initarg :manager)))
+@c
+@c (defmethod print-object ((d department) stream)
+@c (format stream "#<DEPT ~A, mgr = ~A>"
+@c (slot-value d 'name)
+@c (when (slot-boundp d 'manager)
+@c (slot-value (slot-value d 'manager) 'name))))
+@c @end lisp
+@c
+@c Here we have a simple employee database with managers (also of type
+@c person) and departments. This simple system will provide fodder for
+@c some reasonably complex constraints. Let's create a few departments.
+@c
+@c @lisp
+@c (setf marketing (make-instance 'department :name "Marketing"))
+@c (setf engineering (make-instance 'department :name "Engineering"))
+@c (setf sales (make-instance 'department :name "Sales"))
+@c @end lisp
+@c
+@c And manager @code{people} for the departments.
+@c
+@c @lisp
+@c (make-instance 'person :name "George" :salary 140000 :department marketing)
+@c (setf (slot-value marketing 'manager) *)
+@c
+@c (make-instance 'person :name "Sally" :salary 140000 :department engineering)
+@c (setf (slot-value engineering 'manager) *)
+@c
+@c (make-instance 'person :name "Freddy" :salary 180000 :department sales)
+@c (setf (slot-value sales 'manager) *)
+@c @end lisp
+@c
+@c And of course we need some folks to manage
+@c
+@c @lisp
+@c (defparameter *names*
+@c '("Jacob" "Emily" "Michael" "Joshua" "Andrew" "Olivia" "Hannah" "Christopher"))
+@c
+@c (defun random-element (list)
+@c "Choose a random element from the list and return it"
+@c (nth (random (length list)) list))
+@c
+@c (with-transaction ()
+@c (loop for i from 0 upto 40 do
+@c (make-instance 'person
+@c :name (format nil "~A~A" (random-elephant *names*) i)
+@c :salary (floor (+ (* (random 1000) 100) 30000))
+@c :department (case (random 3)
+@c (0 marketing)
+@c (1 engineering)
+@c (2 sales)))))
+@c @end lisp
+@c
+@c
+@c Now we can look at a few queries.
+@c
+@c @lisp
+@c (defun get-managers ()
+@c (get-query-instances `((person
+@c
+@c For those familiar with SQL, if an instance of @code{person} has a
+@c pointer to an instance of @code{department} then that relation can be
+@c used to perform a join. Of course joins in the object world won't
+@c return a table, instead they will return conjunctions of objects that
+@c satisfy a mutual set of constraints.
+
1
0
Update of /project/elephant/cvsroot/elephant/src/elephant
In directory clnet:/tmp/cvs-serv14127/src/elephant
Modified Files:
classindex.lisp variables.lisp
Log Message:
Default inihibit annoying warnings
--- /project/elephant/cvsroot/elephant/src/elephant/classindex.lisp 2007/04/24 03:02:27 1.38
+++ /project/elephant/cvsroot/elephant/src/elephant/classindex.lisp 2007/04/24 12:58:10 1.39
@@ -99,7 +99,8 @@
(defun ensure-finalized (class)
(when (not (class-finalized-p class))
- (warn "Manually finalizing class ~A" (class-name class))
+ (when *warn-on-manual-class-finalization*
+ (warn "Manually finalizing class ~A" (class-name class)))
(finalize-inheritance class)))
(defun cache-existing-class-index (class btree sc)
--- /project/elephant/cvsroot/elephant/src/elephant/variables.lisp 2007/04/12 02:47:33 1.15
+++ /project/elephant/cvsroot/elephant/src/elephant/variables.lisp 2007/04/24 12:58:10 1.16
@@ -60,6 +60,13 @@
(defvar *current-transaction* nil
"The transaction which is currently in effect.")
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Enables warnings of various kinds
+
+(defvar *warn-on-manual-class-finalization* nil
+ "Issue a printed warnings when the class mechanism has
+ to finalize a class to access indexing information")
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Forward references
;;
1
0
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
1
0
Update of /project/elephant/cvsroot/elephant/src/elephant
In directory clnet:/tmp/cvs-serv23327/src/elephant
Modified Files:
classes.lisp classindex.lisp collections.lisp
Log Message:
More documentation edits; performance and feature enhancements for map-index (from-end, collect); fix bug in slot initialization under from-oid
--- /project/elephant/cvsroot/elephant/src/elephant/classes.lisp 2007/04/22 03:35:09 1.29
+++ /project/elephant/cvsroot/elephant/src/elephant/classes.lisp 2007/04/24 03:02:27 1.30
@@ -129,7 +129,7 @@
(unwind-protect
(progn
;; initialize the persistent slots ourselves
- (initialize-persistent-slots class instance persistent-slot-inits initargs)
+ (initialize-persistent-slots class instance persistent-slot-inits initargs from-oid)
;; let the implementation initialize the transient slots
(apply #'call-next-method instance transient-slot-inits initargs))
(uninhibit-indexing oid))
@@ -144,7 +144,7 @@
(setf (get-value oid class-index) instance))))
))))
-(defun initialize-persistent-slots (class instance persistent-slot-inits initargs)
+(defun initialize-persistent-slots (class instance persistent-slot-inits initargs object-exists)
(flet ((initialize-from-initarg (slot-def)
(loop for initarg in initargs
with slot-initargs = (slot-definition-initargs slot-def)
@@ -157,7 +157,7 @@
(loop for slot-def in (class-slots class)
unless (initialize-from-initarg slot-def)
when (member (slot-definition-name slot-def) persistent-slot-inits :test #'eq)
- unless (slot-boundp-using-class class instance slot-def)
+ unless (or object-exists (slot-boundp-using-class class instance slot-def))
do
(let ((initfun (slot-definition-initfunction slot-def)))
(when initfun
--- /project/elephant/cvsroot/elephant/src/elephant/classindex.lisp 2007/04/23 02:26:53 1.37
+++ /project/elephant/cvsroot/elephant/src/elephant/classindex.lisp 2007/04/24 03:02:27 1.38
@@ -394,8 +394,8 @@
(declare (dynamic-extent map-fn))
(map-btree #'map-fn class-idx))))
-(defun map-class-index (fn class index &rest args &key start end value from-end)
- "map-class-index maps a function of two variables, taking key
+(defun map-inverted-index (fn class index &rest args &key start end value from-end)
+ "map-inverted-index maps a function of two variables, taking key
and instance, over a subset of class instances in the order
defined by the index. Specify the class and index by quoted
name. The index may be a slot index or a derived index.
--- /project/elephant/cvsroot/elephant/src/elephant/collections.lisp 2007/04/23 02:41:11 1.24
+++ /project/elephant/cvsroot/elephant/src/elephant/collections.lisp 2007/04/24 03:02:27 1.25
@@ -22,6 +22,10 @@
(in-package "ELEPHANT")
+#-elephant-without-optimize
+(eval-when (:compile-toplevel)
+ (declaim (optimize (speed 3) (safety 1) (space 1))))
+
;;; collection types
;;; we're slot-less
(defclass persistent-collection (persistent) ()
@@ -382,7 +386,7 @@
(funcall fn k v)
(return nil)))))))))
-(defgeneric map-index (fn index &rest args &key start end value from-end)
+(defgeneric map-index (fn index &rest args &key start end value from-end collect)
(:documentation "Map-index is like map-btree but for secondary indices, it
takes a function of three arguments: key, value and primary
key. As with map-btree the keyword arguments start and end
@@ -393,6 +397,72 @@
use the value keyword which will override any values of start
and end."))
+(defmethod map-index (fn (index btree-index) &rest args
+ &key start end (value nil value-set-p) from-end collect)
+ (declare (dynamic-extent args))
+ (unless (or (null start) (null end) (lisp-compare<= start end))
+ (error "map-index called with start = ~A and end = ~A. Start must be less than or equal to end according to elephant::lisp-compare<=."
+ start end))
+ (let ((sc (get-con index))
+ (end (or value end))
+ (results nil))
+ (flet ((collector (k v pk)
+ (push (funcall fn k v pk) results)))
+ (let ((fn (if collect #'collector fn)))
+ (declare (dynamic-extent (function collector)))
+ (ensure-transaction (:store-controller sc)
+ (with-btree-cursor (cur index)
+ (labels ((continue-p (key)
+ ;; Do we go to the next value?
+ (or (if from-end (null start) (null end))
+ (if from-end
+ (or (not (lisp-compare<= key start))
+ (lisp-compare-equal key start))
+ (lisp-compare<= key end))))
+ (value-increment ()
+ ;; Step to the next key value
+ (if from-end
+ (pprev-hack cur)
+ (cursor-pnext-nodup cur)))
+ (next-value ()
+ ;; Handle the next key value
+ (multiple-value-bind (exists? skey val pkey)
+ (value-increment)
+ (if (and exists? (continue-p skey))
+ (progn
+ (funcall fn skey val pkey)
+ (map-duplicates skey))
+ (return-from map-index
+ (nreverse results)))))
+ (map-duplicates (key)
+ ;; Map all duplicates for key value
+ (multiple-value-bind (exists? skey val pkey)
+ (cursor-pnext-dup cur)
+ (if exists?
+ (progn
+ (funcall fn skey val pkey)
+ (map-duplicates key))
+ (progn
+ (cursor-pset-range cur key)
+ (next-value))))))
+ (declare (dynamic-extent (function next-value) (function next-value-increment)
+ (function continue-p) (function map-duplicates)))
+ (multiple-value-bind (exists? skey val pkey)
+ (cond (value-set-p
+ (cursor-pset cur value))
+ ((and (not from-end) (null start))
+ (cursor-pfirst cur))
+ ((and from-end (null end))
+ (cursor-last-range-hack cur))
+ (t (if from-end
+ (cursor-pset-range cur end)
+ (cursor-pset-range cur start))))
+ (if (and exists? (continue-p skey))
+ (progn
+ (funcall fn skey val pkey)
+ (map-duplicates skey))
+ nil)))))))))
+
(defun pprev-hack (cur)
"Get the first duplicate instance of the prior value off the current cursor"
(let ((e? (cursor-pprev-nodup cur)))
@@ -411,57 +481,6 @@
(cursor-pnext cur)
(cursor-pfirst cur))))))
-
-(defmethod map-index (fn (index btree-index) &rest args &key start end (value nil value-set-p) from-end)
- (declare (dynamic-extent args)
- (ignorable args))
- (unless (or (null start) (null end) (lisp-compare<= start end))
- (error "map-index called with start = ~A and end = ~A. Start must be less than or equal to end according to elephant::lisp-compare<=."
- start end))
- (let ((sc (get-con index))
- (end (or value end)))
- (ensure-transaction (:store-controller sc)
- (with-btree-cursor (cur index)
- (labels ((continue-p (key) ;; Do we got to the next value?
- (or (if from-end (null start) (null end))
- (if from-end
- (or (not (lisp-compare<= key start))
- (lisp-compare-equal key start))
- (lisp-compare<= key end))))
- (value-increment () ;; Step to the next key value
- (if from-end
- (pprev-hack cur)
- (cursor-pnext-nodup cur)))
- (next-value () ;; Handle the next key value
- (multiple-value-bind (exists? skey val pkey)
- (value-increment)
- (if (and exists? (continue-p skey))
- (progn
- (funcall fn skey val pkey)
- (map-duplicates skey))
- (return-from map-index nil))))
- (map-duplicates (key) ;; Map all duplicates for key value
- (loop as (exists? skey val pkey) = (multiple-value-list (cursor-pnext-dup cur))
- while exists? do (funcall fn skey val pkey))
- (cursor-pset-range cur key)
- (next-value)))
- (declare (dynamic-extent next-value next-value-increment continue-p map-duplicates))
- (multiple-value-bind (exists? skey val pkey)
- (cond (value-set-p
- (cursor-pset cur value))
- ((and (not from-end) (null start))
- (cursor-pfirst cur))
- ((and from-end (null end))
- (cursor-last-range-hack cur))
- (t (if from-end
- (cursor-pset-range cur end)
- (cursor-pset-range cur start))))
- (if (and exists? (continue-p skey))
- (progn
- (funcall fn skey val pkey)
- (map-duplicates skey))
- nil)))))))
-
;; ===============================
;; Some generic utility functions
;; ===============================
1
0
Update of /project/elephant/cvsroot/elephant/doc
In directory clnet:/tmp/cvs-serv23327/doc
Modified Files:
IntroTalk1.ppt user-guide.texinfo
Log Message:
More documentation edits; performance and feature enhancements for map-index (from-end, collect); fix bug in slot initialization under from-oid
Binary files /project/elephant/cvsroot/elephant/doc/IntroTalk1.ppt 2007/04/23 04:58:15 1.1 and /project/elephant/cvsroot/elephant/doc/IntroTalk1.ppt 2007/04/24 03:02:26 1.2 differ
--- /project/elephant/cvsroot/elephant/doc/user-guide.texinfo 2007/04/22 03:35:09 1.13
+++ /project/elephant/cvsroot/elephant/doc/user-guide.texinfo 2007/04/24 03:02:26 1.14
@@ -340,53 +340,186 @@
(initialization of slots, slot-access, etc).
All persistent classes create objects that inherit from the
-@code{persistent} class. The persistent class has two slots that
-contain a unique object identifier (oid) and a reference to the
-@code{store-controller} specification they are associated with.
+@code{persistent} class. The @code{persistent} class provides two
+slots that contain a unique object identifier (oid) and a reference to
+the @code{store-controller} specification they are associated with.
Persistent slots do not take up any storage space in memory, instead
-the slot access protocol is changed into calls to the configured data
-store via the store controller. Typically, data stores then perform
-reads and writes to disk.
+the @code{persistent-metaclass} slot access protocol redirects slot
+accesses into calls to the store controller. Typically, the
+underlying data store will then perform the necessary serialization,
+deserialization to read and write data to disk.
When a reference to a @code{persistent} instance itself is written to
the database, for example as a key or value in a @code{btree}, only
the unique ID and class of the instance is stored. When read, a
persistent object instance is re-created (see below). This means that
serialization of persistent objects is exceedingly cheap compared to
-standard objects, but slot access time can be much more expensive.
+standard objects. The subsection on instance creation below will
+discuss the lifecycle of a persistent object in more detail.
@subsection Persistent Class Definition
To create persistent classes, the user needs to specify the
@code{persistent-metaclass} to the class initarg @code{:metaclass}.
-The only differences between standard and persistent class definitions
-is the specification of a slot storage policy and an index policy.
+
+@lisp
+(defclass my-pclass ()
+ ((slot1 :accessor slot1 :initarg :slot1 :initform 1))
+ (:metaclass persistent-metaclass))
+@end lisp
+
+The only differences between the syntax of standard and persistent
+class definitions is the ability to specify a slot storage policy and
+an index policy. Slot value storage policies are specified by a
+boolean argument to the slot initargs @code{:persistent},
+@code{:transient} and @code{:indexed}. Slots are @code{:persistent}
+and not @code{:indexed} by default.
+
The @code{defpclass} macro is provided as a convenience to hide the
@code{:metaclass} slot option.
-Slot value storage policies are specified by a boolean argument to the
-new slot initargs @code{:persistent}, @code{:transient} and
-@code{indexed}. Slots are @code{:persistent} by default.
-
@lisp
-(defclass my-pclass ()
+(defpclass my-pclass ()
((pslot1 :accessor pslot1 :initarg :pslot1 :initform 'one)
(pslot2 :accessor pslot2 :initarg :pslot2 :initform 'two :persistent t)
- (tslot1 :accessor tslot1 :initarg :tslot1 :initform 'three :transient t))
- (:metaclass persistent-metaclass))
+ (tslot1 :accessor tslot1 :initarg :tslot1 :initform 'three :transient t)))
@end lisp
-In the definition above, @code{pslot1} and @code{pslot2} are
-persistent while @code{tslot1} is transient and stored in memory.
+In the definition above the class @code{my-pclass} is an instance of
+the metaclass @code{persistent-metaclass}. According to this
+definition @code{pslot1} and @code{pslot2} are persistent while
+@code{tslot1} is transient and stored in memory.
Slot storage class implications are straightforward. Persistent slot
-writes are durably stored to disk. Transient slots are initialized on
-instance creation according to initforms or initargs. Transient slot
-values are never stored to nor loaded from the database.
+writes are durably stored to disk and reads are made from disk and can
+be part of a ACID compliant transaction . Transient slots are
+initialized on instance creation according to initforms or initargs.
+Transient slot values are never stored to nor loaded from the database
+and their accesses cannot be protected by transactions. (Ordinary
+multi-process synchronization would be required instead).
+
+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:
+
+@itemize
+@item @code{shared-initialize :around} ensures that this class inherits from
+ @code{persistent-object} and @code{persistent} if it doesn't
+ already and that the class option @code{:index} results in class indexes
+ being indexed;.
+@item @code{direct-slot-initialization-class} returns the appropriate slot
+ metaobject based on the values of the @code{:transient} and @code{:persistent}
+ slot definition keywords. It also does some simple error checking for invalid
+ combinations, for example, indexed transient slots.
+@item @code{effective-slot-definition-class} performs the same role as the above for
+ effective slots.
+@item @code{slot-definition-allocation} returns the @code{:database} allocation for
+ persistent slot definitions so the underlying lisp will not allocate instance or
+ class storage under some lisps.
+@item @code{compute-effective-slot-definition-initargs} performs some error checking
+ to ensure a subclass does not try to make an inherited persistent slot transient.
+@item @code{finalize-inheritance} called before the first instance is created in order
+ to finalize the list of persistent slots to account for any
+ forward referenced classes in the inheritence list. Similarly the
+ list of indexed slots is computed. This function is also called by the class indexing
+ code if any calls are made that depend on knowing which slots are indexed.
+@end itemize
+
+Reinitialization is discussed in the section on class redefinition.
+
+@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:
+
+@itemize
+@item @code{initialize-instance :before} is called to initialize the
+ @code{oid} slot and the data store specification slot @code{dbcn-spc-pst}.
+ The oid is set by the argument @code{:from-oid} or by calling the store
+ controller for a new oid.
+@item @code{shared-initialize :around} is called to ensure that the underlying
+ lisp does not bypass the metaobject protocol during slot
+ initialization by manually initializing the persistent slots
+ and passing the transient slots to the underlying lisp.
+ Finally it adds the instance to the class index so that any inverted indicies
+ are updated appropriately.
+@end itemize
+
+Persistent slots are initialized under the following conditions:
+
+@enumerate
+@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
+
+
+
+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
+
+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
+
+
+ The two properties of
+@code{persistent} can be specified explicitly during instance
+creation:
+
+@lisp
+(make-instance 'my-pclass :from-oid 100 :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?
+
+@subsection Using Transient Slots
+
+The best policy for initializing transient slots is an @code{:after}
+method on @code{initialize-instance}.
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 stored in memory or tere are zero references but the
+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
transient slots will be reset to the slot initforms from the class
@@ -394,6 +527,11 @@
or persistent slots during the initial call to @code{make-instance} or
by manually creating the instance from an oid (see below).
+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
+
@lisp
(setf pobj1 (make-instance 'my-pclass :pslot1 1 :tslot3 3))
=> #<MY-PCLASS>
@@ -431,48 +569,6 @@
behavior of indexed classes and class slots are discussed in depth in
@ref{Class Indices}.
-@subsection Instance Creation
-
-To the user, persistent objects are created normally with a call to
-@code{make-instance} with the desired slot initargs as illustrated in
-the last section. However, this call 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 with a valid store controller object.
-
-An instance of the class is created and any initforms and initarg
-values are written to transient or persistent slots as one would
-expect.
-
-* Default store controller & instance creation
-* What happens to persistent objects when store-controller is closed?
-
-The best policy for initializing transient slots is an @code{:after}
-method on @code{initialize-instance}.
-
-The two properties of @code{persistent} can be specified explicitly
-during instance creation:
-
-@lisp
-(make-instance 'my-pclass :from-oid 100 :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.
-
-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
-
-Also currently there is a bug where @code{initforms} are always
-evaluated, so beware. (What is the current model here?)
-
@subsection Class Redefinition
This section discusses the appropriate model a user should employ in
1
0
Update of /project/elephant/cvsroot/elephant/doc
In directory clnet:/tmp/cvs-serv21560
Added Files:
IntroTalk1.ppt
Log Message:
Expand on talk sketch
--- /project/elephant/cvsroot/elephant/doc/IntroTalk1.ppt 2007/04/23 04:58:15 NONE
+++ /project/elephant/cvsroot/elephant/doc/IntroTalk1.ppt 2007/04/23 04:58:15 1.1
ÐÏࡱá>þÿ vþÿÿÿxÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿÿ
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuþÿÿÿýÿÿÿz{|}~RÿÿÿÿÿÿÿÿdOÏꪹ)èu\B
Çw@PowerPoint Document(ÿÿÿÿ²,SummaryInformation(ÿÿÿÿÿÿÿÿyô7DocumentSummaryInformation8ÿÿÿÿÿÿÿÿÿÿÿÿäèæSé(àà â
×jÓºVhttp://www.common-lisp.net/project/elephant×\ÓºHhttp://trac.common-lisp.net/elephantòþ/È0ÒÕ0·DArialNew Romaÿ¿Ñÿ¿0Íú@Èÿ¿Ñÿ¿0Í1
æP·D-ÿ3ÿ 0ÿŽ0·0Ã0¯0 Romaÿ¿Ñÿ¿0Íú@Èÿ¿Ñÿ¿0Í1
æP ·DWingdingsRomaÿ¿Ñÿ¿0Íú@Èÿ¿Ñÿ¿0Í1
æP0·DTimes New Romanÿ¿0Íú@Èÿ¿Ñÿ¿0Í1
æP€dÿÿÿÿ¥.©
@£nÿý?" dþ| ÿÿïÿÿÿÿþ @@``tðlð!)
cð$žÿ¿Àÿ ñ÷÷÷ffÿ@ñ÷ðóÐè1ÿúgþý4gdgdÐHPÍÿ¿À
ÿÿÿøýÿÿpûppû@<ý4ªÈªÈ°Íÿ¿°%øgÊ;ðüÿÿšÿÿÿúgþý4;d;dÐHPÍÿ¿LKÑÿ¿(ùÿÿžÿÿÿpû@pûpºuìÊ;2NÍÉÊ;<ý4dddd°Íÿ¿°%øºuìÊ;<ý4dddd°Íÿ¿°%øºuìÊ;ö/°º___PPT10³¯±H¯±`
¯
±8¯
±(¯±@¯±@¯ ±X
º___PPT9p®h¯¬¯¬À
¯
¬p¯
¬P¯¬¯¬¯ ¬°
hº___PPT2001D<4XÑà0(º___PPTMac11
(@f èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography x!¯4 èhnamd`
Arial&Monotype Typography ¯ èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography ¯
l èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography ¯
4 èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography ¯0 èhnamd`
Arial&Monotype Typography ¯P èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography ¯ Ü èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography ?ÙÚ
%OÙÚ
=ðóšWElephant:A Persistent Metaobject Protocoland Object Oriented Database for Common Lisp¡(X
Mª,)šTPersistent object protocol
persistent-metaclass specializes slot accesses
Enables persistent links between objects
Enables automatic indexing of class instances by slot value
Efficient mapping operators over class, slot values, etc.
Simple persistent collection APIs
Persistent sets (add, remove, find)
Btrees (insert, delete, pred, succ)¡Ï"H(x!H ªB5óª šÐTransactional architecture
Provides support for concurrent transactions
Provides full ACID compliance
Modular Data Store design
The interface to disk storage is abstracted
Currently supports Berkeley DB (direct/fast) and CL-SQL (general/slower) for flexible speed, license issues
Full support for migration between database instances
Migration also provides compaction and garbage collection
Runtime database configuration
Schema evolution
Add/remove slot indexes
¡ØrKrrrr*r-,l69 $$((*,,ª>ü"óª ª óª ª ó
šPersistent Referencesª
óšTransactionsª
óšPersistent Setsª
óšBTreesª
ª
ó
šFast Binary Object SerializerªšAll numeric types
Strings, symbols and pathnames
Full Unicode support
Persistent objects
Standard objects and structs
Arrays, hash-tables and lists¡h1rrNr ªnó
šFlexible Indexing Schemeš
Don't optimize prematurely...index a slot when you need to
Functional indexes provide lots of power; you can index objects by the values returned from arbitrary lisp functions
Indexes can be ordered by
Any numeric quantity
Lexical ordering of strings, symbols and paths¡RÊrDr°.ª>zN/óšBroad Platform SupportšóMultiple Lisp environments:
SBCL, ACL, LispWorks, OpenMCL
Multiple Platforms:
Linux, Mac, Windows
32 and 64 bit
Multiple data store implementations
Berkeley DB and CL-SQL (PostgreSQL and SQLite)
Native PostgreSQL and Lisp data store planned¡Šrrr"r$r]r"$/-ª !< ó šMultiple Data StoresšBerkeley DB: fast, not free for a website unless website is open-source
Postgres via CLSQL: slower, liberal license, very solid and well-supported
SQLite3 via CLSQL: simple, slowest, good for prototyping
Easy to migrate your application between them and more data stores are on the way¡R=9zª,H zRóš
The Future A robust, long-term supported 1.0 release planned by end of summer 07
Referential integrity and full support for schema evolution (changing persistent class slots)
Better support for class hierarchies when indexing
Better postgres usage with postmodern
Object query language (and compiler?)
Post 1.0 features under consideration
Native LISP data store
Object prevalence or Object management (DCM)¡GrÞr&rErG_3K&-ªb!: b-ó šElephant Pointers
http://www.common-lisp.net/project/elephant
Available via CVS and tar archive (not asdf-installable today)
Add feature requests and log bug reports to the TRAC project database at http://trac.common-lisp.net/elephant
Authors
Original Elephant Implementation by Andrew Blumberg and Ben Lee
New Elephant Versions 05- 07 by Ian Eslick and Robert Read
Numerous patches, features, examples and significant testing support from a growing user base!
¡À rÚrrÛrr +?n@ $$((ªL +(L$æòóÆß 4òóÆßœá/ðóó
óóóóóóó ó
óóó
ó!PÿÿÿpêøŒï^à`ð ÿÿÿÌ33ÌÌÌÿ²²²`ð ÿÿÿÿÿÿÿÿÿÿ`ð ÿÿÌff3333ÌÿÌf`ð ÿÿÿ333ÝÝÝMMMêêê`ð ÿÿÿÿÌfÿÌÌÀÀÀ`ð ÿÿÿÀÀÀfÿÿ`ð ÿÿÿ3ÿÿÌÌ̲²²£tÿý?" dþ| ÿÿïÿÿÿÿ,þÐlð- š £ÿý?" dþ|Àÿ× ÿÿïÿÿÿÿ þ% ÈÿÓ %" ÐÿÐ@% Øÿð`» £vÿý?" dþd ÿÿïÿÿÿÿÿÿþ Ô " Ð@ ð`»@£nÿý?" dþ| ÿÿïÿÿÿÿþ @@``P£b )Àÿ )Àÿ@ )Àÿ` )Àÿ `£< p£t1" dØ1 dÔ0" d0 d0»d£t1" dØ1 dÔ0" d0 d0»dðððð( ðÿÿÿÿ
ððf"
ð
ð0
ffÿ¿ÀffÿË>ßÿ"ñ¿ðÀðPðä
ð
ÃðH`³z¿¿Öÿ ð$°Ï«ðÃJ
ðTš Click to edit Master title style¢!ª
!ð(
ð
³ðBÀ|Ö¿¿Öÿ ðà°ÏÿðÃJ
ðšRClick to edit Master text styles
Second level
Third level
Fourth level
Fifth level¢!
ª
Sð
ð
³ðB_Ö_ж_ж¿¿Öÿ ð`°_ðÃJ
ð *¡øª
Š6@À @
À@Àð
ð
³ðB`CÙ_ж_ж¿¿Öÿ ð`°Ïðà J
ð *¡úª
Š6@À @
À@Àð
ð
³ðB "3_ж_ж¿¿Öÿ ð` ÏðÃJ
ð *¡Øª
Š6@À @
À@ÀðB
ðsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²² º$Blank PresentationðñÐðPððºð( ðÿÿÿÿ
ððÀ
ð
ÃðHC~¿¿Öÿ ðÛÛðÃJ
ð0¢ª ðº
ð
³ðB@F~¿¿Öÿ ð°
°/ÏðÃJ
ð0¢ª ð<
ðcð$Þœh¿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²80º___PPT10ë.ØÒs9$¡îbï
?`ùØ?`ÙÚ%xðp ððð( ðÿÿÿÿ
ððì
ð óðZÍÕ
¿¿ÀÂÿÿÿÖÿ ?ðÐðÃ
J
ðJŠ6@À @
À@Àðè
ð óðZ ÕÕ
¿¿ÀÂÿÿÿÖÿ ?ðÐ ððÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð<
ðcð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++îtï
?`ùØ?`ÙÚ%ð0ðLð&ð( ð
ðLðî
ðL ð`À²8
¿¿ÀÂÿÿÿÖÿ ?ð° ððÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð<
ðLcð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++îÂï
?`ùØ?`ÙÚ%ØðÐ0ð((ðtð( ðÿÿÿÿ
ððR
ð(
sð*
¿Àÿðàðü"
ð
óðZP¢Ö_ж_ж
¿ÿÿ¿Ë$Öÿ?ð0`
ðršPSET¡Š6@À @
À@Àð"
ð
óðZ{_ж_ж
¿ÿÿ¿Ë$Öÿ?ðÀ
ð|šClassIndexing¡Š6@À @
À@Àð"
ð
óðZp{_ж_ж
¿ÿÿ¿Ë$Öÿ?ð Ð
ð~šPersistentSlots¡Š6@À @
À@Àð^"
ð
ð6
ÿÿ¿Ë$Öÿ?ðh ð^"
ð
ð6
ÿÿ¿Ë$Öÿ?ðð ðX
ð
ð0
ÿÿ¿Öÿ ?ðΧ.ðñ¢
ð
£ð<`"{_ж_ж¿¿Öÿ ?ðûåwR
ð
šBTree¡ ÿª
Š6@À @
À@Àð"
ð
óðZà6{_ж_ж
¿ÿÿ¿Ë$Öÿ?ð p
ðš
Serializer¡ª
Š6@À @
À@Àð"
ð
óðZ<{_ж_ж
¿ÿÿ¿Ë$Öÿ?ðÐ
ðš
Memutils/UFFI¡ª
Š6@À @
À@Àð
"
ð
óðZPI{_ж_ж
¿ÿÿ¿Ë$Öÿ?ðð
ðšMOP¡ª
Š6@À @
À@Àðâ¢
ð
£ð<pV{_ж_ж¿¿Öÿ ?ð W
ðvšUser API¡ ÿ Š6@À @
À@ÀðLB
ð
cð$D¿Ë$Öÿ?ð P !ðü¢
ð
£ð<l{_ж_ж¿¿Öÿ ?ðHï
ðš"Data Store Interface and Utilities¡# ÿ#Š6@À @
À@Àð"
ð
óðZq{_ж_ж
¿ÿÿ¿Ë$Öÿ?ð0 @
ðšdb-bdb¡ª
Š6@À @
À@Àð"
ð
óðZÐ
{_ж_ж
¿ÿÿf¿Ë$Öÿ?ð0 p@
ðš
db-postmodern¡ª
Š6@À @
À@Àð"
ð
óðZp{_ж_ж
¿ÿÿ¿Ë$Öÿ?ð0 `@
ðšdb-clsql¡ ª
Š6@À @
À@Àð"
ð
óðZ@{_ж_ж
¿ÿff¿Ë$Öÿ?ð0 à@
ðšdb-lisp¡ª
Š6@À @
À@Àð"
ð
óðZ`¥{_ж_ж
¿«««TTT¿Ë$Öÿ?ð`pðp
ðš
BerkeleyDB¡ª
Š6@À @
À@Àð"
ð
óðZ²{_ж_ж
¿«««TTT¿Ë$Öÿ?ð`à
p
ðš
PostgreSQL¡ª
Š6@À @
À@Àð"
ð
óðZP¿{_ж_ж
¿«««TTT¿Ë$Öÿ?ð`@Àp
ðšSQLite¡ª
Š6@À @
À@ÀðRB
ð
sð*D¿Ë$ÑÖÿ?ð@0`ðRB
ð
sð*D¿Ë$ÑÖÿ?ð@Ð0 `ðRB
ð@
sð*D¿Ë$ÑÖÿ?ð@/Q
`ðRB
ð
sð*D¿Ë$ÑÖÿ?ð@`ðLB
ð
cð$D¿Ë$Öÿ?ðP ðLB
ð
cð$D¿Ë$Öÿ?ðÐP ÑðLB
ð
cð$D¿Ë$Öÿ?ðÐP Ñð
"
ð
óðZÐÔ{_ж_ж
¿ÿÿf¿Ë$Öÿ?ðà
@
ðšDCM¡ª
Š6@À @
À@ÀðX
ð
ð0
ÿÿ¿Ë$ÿ?ðgðú¢
ð
³ðBÐá{_ж_ж
¿¿Öÿ ?ðÐçYÉ
ðšUser API¡ ª
Š6@À @
À@ÀðX
ð
ð0
ÿÿ¿Ë$ÿ?ðãCðú¢
ð
³ðBPð{_ж_ж
¿¿Öÿ ?ð¬ç¥
ðšInternal¡ ª
Š6@À @
À@ÀðX
ð!
ð0
ÿÿf¿Ë$ÿ?ð0 @gð¢
ð"
³ðBÿ{_ж_ж
¿¿Öÿ ?ðÐ É
ðšReady to integrate¡ª
Š6@À @
À@ÀðX
ð#
ð0
ÿff¿Ë$ÿ?ðã0 @Cðõ¢
ð$
³ðB°
|_ж_ж
¿¿Öÿ ?ð¬
¥
ðšTBD¡ª
Š6@À @
À@ÀðX
ð%
ð0
«««TTT¿Ë$ÿ?ð°À`ðé¢
ð&
³ðB|_ж_ж
¿¿Öÿ ?ðÉÂ
ðwš 3rd party¡
Š6@À @
À@Àð<
ð'cð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++îôï
?`ùØ?`ÙÚ%
ð`ððŠð( ðÿÿÿÿ
ðð^
¢
ð
£ð<pWÑ_ȯ_ȯ¿¿Öÿ ?ð:Ç ÀðÈÀpº___PPT10P±H¶º___PPT9¬º___PPTMac11\T èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography èhnamd`
Arial&Monotype Typography
ð" V(defpclass friend ()
((name :accessor name :initarg :name)
(birthday :initarg :birthday :index t))
=> #<PERSISTENT-METACLASS FRIEND>
(make-instance 'friend :name "Carlos" :birthday (encode-birthday '(1 1 1972)))
(make-instance 'friend :name "Adriana" :birthday (encode-birthday '(24 4 1980)))
(make-instance 'friend :name "Zaid" :birthday (encode-birthday '(14 8 1976)))
NOW SOMEONE TRIPS OVER THE POWER CORD...
Restart your LISP and do:
(get-instances-by-class 'friends)
=> (#<Carlos> #<Adriana> #<Zaid>)
(map-class-index #'(format t " name: ~A birthdate: ~A~%"
(name friend) (birthday friend))
'friend birthday)
name: Carlos birthdate: (1 1 1972)
name: Zaid birthdate: (14 8 1976)
name: Adriana birthdate: (24 4 1980)
=> nil¡x,yDÿþ""} ªò
õ±1 $
Š6@À @
À@Àð¢
ð
³ðBÀN@¿¿Öÿ ?ð³°ÐŸ
ðšPersistent Classes¡
,ª
Š6@À @
À@Àð<
ðcð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++îï
?`ùØ?`ÙÚ%.ð&ðð$ðÊð( ðÿÿÿÿ
ð$ðì
ð$ óðZœE
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðè
ð$ óðZ ÉE
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÈðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð®
ð$
£ð<³!,
¿žÿ¿ÀÿðÖy-
ðB¡$ÿÿª ð<
ð$cð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++î$ï
?`ùØ?`ÙÚ%:ð2ðð|ðÖð( ðìÇz
ìOz
ð|ðò
ð| ð`ð¥0
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðî
ð| ð` >€0
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÈðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð®
ð|
£ð<K%,
¿žÿ¿ÀÿðÖy-
ðB¡$ÿÿª ð<
ð|cð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++î$ï
?`ùØ?`ÙÚ%:ð2ðdðÖð( ð
ðdðò
ðd ð`ÀpÆ/
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðî
ðd ð`0kÂ/
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÈðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð®
ðd
£ð< Ç/
¿žÿ¿ÀÿðÖy-
ðB¡$ÿÿª ð<
ðdcð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++î$ï
?`ùØ?`ÙÚ%:ð2°ðlðÖð( ð
ðlðò
ðl ð`pØ.,
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðî
ðl ð`ÀÝ.,
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÈðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð®
ðl
£ð<`è.,
¿žÿ¿ÀÿðÖy-
ðB¡$ÿÿª ð<
ðlcð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++î$ï
?`ùØ?`ÙÚ%:ð2ÐðtðÖð( ð?
ðtðò
ðt ð`À/,
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðî
ðt ð`/,
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÈðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð®
ðt
£ð< }/,
¿žÿ¿ÀÿðÖy-
ðB¡$ÿÿª ð<
ðtcð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++înï
?`ùØ?`ÙÚ%ð|pð\ð ð( ðìÇz
ìOz
ð\ðò
ð\ ð`à-
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðî
ð\ ð` N-
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÈðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð<
ð\cð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++îbï
?`ùØ?`ÙÚ%xðpððð( ðÿÿÿÿ
ððì
ð óðZ°B
¿¿ÀÂÿÿÿÖÿ ?ð1°ÐðÃ
J
ðJŠ6@À @
À@Àðè
ð óðZà¢B
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÈðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð<
ðcð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++îbï
?`ùØ?`ÙÚ%xðpÐð ðð( ðÿÿÿÿ
ð ðì
ð óðZ0D
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðè
ð óðZÔ
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÈðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð<
ð cð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++îbï
?`ùØ?`ÙÚ%xðpð(ðð( ðÿÿÿÿ
ð(ðì
ð( óðZðµF
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðè
ð( óðZпF
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÉðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð<
ð(cð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++înï
?`ùØ?`ÙÚ%ð|PðTð ð( ðrohcngam
ðTðò
ðT ð`ÀÜå,
¿¿ÀÂÿÿÿÖÿ ?ð@°ÐðÃ
J
ðJŠ6@À @
À@Àðî
ðT ð`à{î,
¿¿ÀÂÿÿÿÖÿ ?ðà°ÐÉðÃJ
ðFŠ2>~Ÿþ>~
Ÿþ>~Ÿð<
ðTcð$Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²f^º___PPT10>ë.ù]Ä0Gá+Dñ'ñ k0ÿÿÿÿ=ñ
@Bñ DñÁ'ñ =ñ
@BñAñ?%ñ,(ñ <ñ+O%ñ,(ñ
<ñ++ðäñ "ð@ð,ð&ð( ðÿÿÿÿ
ð,ðR¢
ð,
3ð
?ððÃJð¢
ð,
sð*V~
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ð,sð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ÙÚ5ðäñ "ðpð0ð&ð( ðÿÿÿÿ
ð0ðR¢
ð0
3ð
?ðþV
ÜðÃJð¢
ð0
sð*Y~
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ð0sð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ÙÚ5ðäñ "ðð4ð&ð( ðÿÿÿÿ
ð4ðR¢
ð4
3ð
?ð¶Ð&
ðÃJð¢
ð4
sð*ÐÔ
¿Öÿ ?ð°
°0ÐðÃJ
ð"ª ðB
ð4sð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ÙÚ5ðäñ "ð ð8ð&ð( ðÿÿÿÿ
ð8ðR¢
ð8
3ð
?ððÃJð¢
ð8
sð*ðC
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ð8sð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ÙÚ5ðäñ "ðàð@ð&ð( ðÿÿÿÿ
ð@ðR¢
ð@
3ð
?ððÃJð¢
ð@
sð*0yE
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ð@sð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ÙÚ5ðäñ "ððDð&ð( ðÿÿÿÿ
ðDðR¢
ðD
3ð
?ðþV
ÜðÃJð¢
ðD
sð*{F
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ðDsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ÙÚ5ðäñ "ð ðHð&ð( ðÿÿÿÿ
ðHðR¢
ðH
3ð
?ðþV
ÜðÃJð¢
ðH
sð*BH
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ðHsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ÙÚ5ðÜñ "ð@ðPð2ð( ðÿÿÿÿþ
ðPð^¢
ðP
Sð
¿ÿ?ððÃJð¢
ðP
sð*Ð9
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ðPsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ðÜñ "ð`ðXð2ð( ð4Z"@
ðXð^¢
ðX
Sð
¿ÿ?ðþV
ÜðÃJð¢
ðX
sð*©Ë*
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ðXsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ðÜñ
"ðð`ð2ð( ð@
ð`ð^¢
ð`
Sð
¿ÿ?ðþV
ÜðÃJð¢
ð`
sð*À¯/
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ð`sð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ðÜñ "ð ðhð2ð( ð4Z"@
ðhð^¢
ðh
Sð
¿ÿ?ðþV
ÜðÃJð¢
ðh
sð*Àf-,
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ðhsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ðÜñ "ðÀðpð2ð( ð
ðpð^¢
ðp
Sð
¿ÿ?ðþV
ÜðÃJð¢
ðp
sð*ðò.,
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ðpsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ðÜñ
"ðàðxð2ð( ð
ðxð^¢
ðx
Sð
¿ÿ?ðþV
ÜðÃJð¢
ðx
sð*Ð/,
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ðxsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²ðÜñ "ððð2ð( ð
ðð^¢
ð
Sð
¿ÿ?ðþV
ÜðÃJð¢
ð
sð*ãB1
¿Öÿ ?ð°
°0ðÃJ
ð"ª ðB
ðsð*Þœh¿ÿ ?ð ÿÿÿÌ33ÌÌÌÿ²²²dx»p^ðÁÂRÐ3ÿÿlHbP@ùÿÿAL
ÿGÁøß@;b`BÏù€&V<OmÛåmÇÿPG* Ö~Z¡l?QónrpîS²_Xb>jJ¹ pŽœÂþÊêÌÖÎÂÐ ®ÒÔÖÂfrØÔŽÆVÚ:Ü$ P¥|ªš¯ÞàæáÊã®åõs æ"MèTé(àà â
×jÓºVhttp://www.common-lisp.net/project/elephant×\ÓºHhttp://trac.common-lisp.net/elephantòþ/È
þÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ
ÕÍÕ.+,ù®DÕÍÕ.+,ù®H š°ž À
ÈÐØàèð
øçéýOn-screen Show²,tArialïŒïŒ³ ãŽã·ãã¯
WingdingsTimes New RomanBlank PresentationXElephant: A Persistent Metaobject Protocol and Object Oriented Database for Common Lisp
þÿÿÿþÿÿÿþÿÿÿ ¡¢£€¥Š§š©ª«¬®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿþÿ
à
òùOh«+'³Ù0Ä7 PXx
¬
žÄÌ'PowerPoint PresentationIan EslickIan Eslick3@xa @ãc
Ç&Gî6þÿÿÿPICT6æŽÿÿþHHŽ
ŽÿÐŽHH )lpJŽŽÿÿÿÿÿ±ÿÿÿÿÿÿ±ÿÿÿÿÿÿ±ÿÿÿÿÿÿ±ÿÿÿÿÿÿ±ÿ.ÿ¹ÿýÞº
tlfls
ºÞýÛÿýÞº
tlfls
ºÞýÿ»ÿ6ÿ»ÿäŠsŠÈÝñ÷ÿ÷òÝÈŠsŠäßÿäŠsŠÈÝñ÷ÿ÷òÝÈŠsŠäÿœÿ*ÿœÿátµéÿõÿéµtáãÿátµéÿõÿéµtáÿ¿ÿ*ÿ¿ÿ÷ sÄûÿñÿûÄs ÷çÿ÷ sÄûÿñÿûÄs ÷ÿÁÿ_ÿÀÿßyŠöÐÿÞýyôôÿ¹NðÿéÉÿöŠyàéÿßyŠöÐÿÞýyôôÿ¹NðÿéÉÿöŠyàŽÿÞýyôôÿ¹NðÿéºÿXÿÁÿáfÌÎÿÞüÿôôÿ¹Nðÿ'âÇÿÎrÐëÿáfÌÎÿÞüÿôôÿ¹Nðÿ'âÇÿÎrеÿÞüÿôôÿ¹Nðÿ'âºÿ©ÿÂÿÏfÛÍÿÞüÿ&ôÿøf!%°ÿm.-šÿ¹6D\úýt)Røú@g6à2îX³ÉÿÒfáíÿÏfÛÍÿÞüÿ&ôÿøf!%°ÿm.-šÿ¹6D\úýt)Røú@g6à2îX³ÉÿÒfá¶ÿÞüÿ&ôÿøf!%°ÿm.-šÿ¹6D\úýt)Røú@g6à2îX³œÿ¬ÿÃÿ×sÛÌÿÞýX'ÓôÿT÷Ø,þy+ìâã¹Üö*ÀÅIýø1¶ùÿlyÿ'âÿËçÈÿÑs×ïÿ×sÛÌÿÞýX'ÓôÿT÷Ø,þy+ìâã¹Üö*ÀÅIýø1¶ùÿlyÿ'âÿËçÈÿÑs×·ÿÞýX'ÓôÿT÷Ø,þy+ìâã¹Üö*ÀÅIýø1¶ùÿlyÿ'âÿËçœÿ£ÿÄÿðsÖËÿÞý³$ëôÿ[[(Åy{ÿÿL¬¹Bÿÿd¢ÿæšvšùòÿ¡eÿ'âÄÿÖtðñÿðsÖËÿÞý³$ëôÿ[[(Åy{ÿÿL¬¹Bÿÿd¢ÿæšvšùòÿ¡eÿ'âÄÿÖtðžÿÞý³$ëôÿ[[(Åy{ÿÿL¬¹Bÿÿd¢ÿæšvšùòÿ¡eÿ'âºÿ ÿÅÿþ·ÊÿÞüÿôÿG{þšÜyÿÿQ©¹Nÿÿg¡Ã{žL§ùÿÿ€cÿ'âÃÿ·þóÿþ·ÊÿÞüÿôÿG{þšÜyÿÿQ©¹Nÿÿg¡Ã{žL§ùÿÿ€cÿ'âÃÿ·þ¹ÿÞüÿôÿG{þšÜyÿÿQ©¹Nÿÿg¡Ã{žL§ùÿÿ€cÿ'âºÿ©ÿÅÿÌüÊÿÞüÿ&ôÿhÿùFàyBýòß¹Nÿÿg¡{yÿò!£ùÿÿ€cÿ-ÝÿëöÆÿüÍóÿÌüÊÿÞüÿ&ôÿhÿùFàyBýòß¹Nÿÿg¡{yÿò!£ùÿÿ€cÿ-ÝÿëöÆÿü͹ÿÞüÿ&ôÿhÿùFàyBýòß¹Nÿÿg¡{yÿò!£ùÿÿ€cÿ-Ýÿëöœÿ¬ÿÆÿý|×ÉÿÞý'Nôÿïg:5ÿy3+!ÿ¹Nÿÿg¡Ö/LEQùÿÿ€cÿgÝ>§Åÿ×|ýõÿý|×ÉÿÞý'Nôÿïg:5ÿy3+!ÿ¹Nÿÿg¡Ö/LEQùÿÿ€cÿgÝ>§Åÿ×|ýºÿÞý'Nôÿïg:5ÿy3+!ÿ¹Nÿÿg¡Ö/LEQùÿÿ€cÿgÝ>§œÿQÿÆÿÊŒÿöüÿÿyõú÷ÿíöÿöÁÿÊõÿÊŒÿöüÿÿyõú÷ÿíöÿöÁÿÊ®ÿöüÿÿyõú÷ÿíöÿöºÿ'ÿÆÿÊžÿyšÿÊõÿÊžÿyšÿʪÿy¡ÿ+ÿÇÿðpýžÿçëšÿýpð÷ÿðpýžÿçëšÿýpð«ÿçë¡ÿÿÇÿÉÿÛÿÉ÷ÿÉÿÛÿÉÿÉÿÿÇÿ£ÀÿÛÿÀ£÷ÿ£ÀÿÛÿÀ£ÿÉÿÿÇÿÖáÿþýÿýýõÿþïÿþþÿÿþòÿþþÿþõÿþýþëÿþàÿ×÷ÿÖáÿþýÿýýõÿþïÿþþÿÿþòÿþþÿþõÿþýþëÿþàÿ×ÕÿþýÿýýõÿþïÿþþÿÿþòÿþþÿþõÿþýþëÿþÚÿçÿÇÿuðâÿ·Cýÿ9kf|÷ÿ€òþÿž×ùÿþÿ
Sÿÿ=²ýÿüùÿuíÿÿ¢óúÿþÿUjWåúÿõÿbàÿðu÷ÿuðâÿ·Cýÿ9kf|÷ÿ€òþÿž×ùÿþÿ
Sÿÿ=²ýÿüùÿuíÿÿ¢óúÿþÿUjWåúÿõÿbàÿðuÖÿ·Cýÿ9kf|÷ÿ€òþÿž×ùÿþÿ
Sÿÿ=²ýÿüùÿuíÿÿ¢óúÿþÿUjWåúÿõÿbÚÿSÿÇÿm÷âÿt¬Àþÿ_VÿýPïpmÉZŽWZÉ×WZÉV}Ôolæl
JÏ/Éÿÿ
LðßD²ÿ|oªœ2Æ\V©ñbjÅupPÚî|oªügj€/®ÿÿÌÿÂÞE°inÖ/Ékügj«Òdiâbàÿ÷m÷ÿm÷âÿt¬Àþÿ_VÿýPïpmÉZŽWZÉ×WZÉV}Ôolæl
JÏ/Éÿÿ
LðßD²ÿ|oªœ2Æ\V©ñbjÅupPÚî|oªügj€/®ÿÿÌÿÂÞE°inÖ/Ékügj«Òdiâbàÿ÷mÖÿt¬Àþÿ_VÿýPïpmÉZŽWZÉ×WZÉV}Ôolæl
JÏ/Éÿÿ
LðßD²ÿ|oªœ2Æ\V©ñbjÅupPÚî|oªügj€/®ÿÿÌÿÂÞE°inÖ/Ékügj«ÒdiâbÚÿRÿÇÿfâÿì^Ç^þÿ5Zb»€°htÛÖSŒìwÅSŒìÐr¥MùÌcþÿ!
²×`±WùjåÈg¡ÈüeuÕÖxuÇ`±WÆÿÍcþÿH\ýÚuÿiÿŠ»cøpÿv¶ÿÍtôÙbßÿf÷ÿfâÿì^Ç^þÿ5Zb»€°htÛÖSŒìwÅSŒìÐr¥MùÌcþÿ!
²×`±WùjåÈg¡ÈüeuÕÖxuÇ`±WÆÿÍcþÿH\ýÚuÿiÿŠ»cøpÿv¶ÿÍtôÙbßÿf×ÿì^Ç^þÿ5Zb»€°htÛÖSŒìwÅSŒìÐr¥MùÌcþÿ!
²×`±WùjåÈg¡ÈüeuÕÖxuÇ`±WÆÿÍcþÿH\ýÚuÿiÿŠ»cøpÿv¶ÿÍtôÙbÚÿRÿÇÿfâÿKéÿÿVþÿÀ®tîñÍzwÞÍzÐfžºÂbÿÉcþÿ!
Õfv©²ÈoÀ¢ùj€wÁdÒþVuæÝu¹oÀ¢ÌÿÇcþÿÌþÿÚÿcÿ®Šcñqÿ{ÿÇhúâsbßÿf÷ÿfâÿKéÿÿVþÿÀ®tîñÍzwÞÍzÐfžºÂbÿÉcþÿ!
Õfv©²ÈoÀ¢ùj€wÁdÒþVuæÝu¹oÀ¢ÌÿÇcþÿÌþÿÚÿcÿ®Šcñqÿ{ÿÇhúâsbßÿf×ÿKéÿÿVþÿÀ®tîñÍzwÞÍzÐfžºÂbÿÉcþÿ!
Õfv©²ÈoÀ¢ùj€wÁdÒþVuæÝu¹oÀ¢ÌÿÇcþÿÌþÿÚÿcÿ®Šcñqÿ{ÿÇhúâsbÚÿRÿÇÿfâÿQÿÿœÿÿVþÿCåhy¢tîæ]t¥wÓ]t¥¯oÄrgËbÿÉ]Áÿÿ
×u©²þjÿBry_âhk§uujÝuìjþk|¢ÿÿÌþÿÚÿ|Wë]Á{cükÀsZÎbßÿf÷ÿfâÿQÿÿœÿÿVþÿCåhy¢tîæ]t¥wÓ]t¥¯oÄrgËbÿÉ]Áÿÿ
×u©²þjÿBry_âhk§uujÝuìjþk|¢ÿÿÌþÿÚÿ|Wë]Á{cükÀsZÎbßÿf×ÿQÿÿœÿÿVþÿCåhy¢tîæ]t¥wÓ]t¥¯oÄrgËbÿÉ]Áÿÿ
×u©²þjÿBry_âhk§uujÝuìjþk|¢ÿÿÌþÿÚÿ|Wë]Á{cükÀsZÎbÚÿæÿÇÿfÕÿúüÿùýÿùÿÿüÿýýüÿþý÷ÿúÿÿüÿùýÿúþÿýúbøÿúþÿûÿÿüöÿúÿÿþýÿúþÿûÿÿüýÝÿf÷ÿfÕÿúüÿùýÿùÿÿüÿýýüÿþý÷ÿúÿÿüÿùýÿúþÿýúbøÿúþÿûÿÿüöÿúÿÿþýÿúþÿûÿÿüýÝÿfÊÿúüÿùýÿùÿÿüÿýýüÿþý÷ÿúÿÿüÿùýÿúþÿýúbøÿúþÿûÿÿüöÿúÿÿþýÿúþÿûÿÿüýØÿ#ÿÇÿf£ÿá³¹ÿf÷ÿf£ÿá³¹ÿfÿ᳎ÿÿÇÿfÿÙÿf÷ÿfÿÙÿfÿÉÿÿÇÿfÿÙÿf÷ÿfÿÙÿfÿÉÿÿÇÿfÿÙÿf÷ÿfÿÙÿfÿÉÿªÿÇÿfðÿþûÿøþÿþþÿþóÿøüÿþñÿþþÿýýãÿûö÷ÿ÷æÿþþÿþðÿf÷ÿfðÿþûÿøþÿþþÿþóÿøüÿþñÿþþÿýýãÿûö÷ÿ÷æÿþþÿþðÿfåÿþûÿøþÿþþÿþóÿøüÿþñÿþþÿýýãÿûö÷ÿ÷æÿþþÿþëÿÿÇÿfðÿcýÿ
ñ~jŠÿuíÿÿùÿþÿÁ
yfãÿÿèùÿúÿcÿÿð*jb€ýÿüýÿšºñÿHŒùÿ°hylùèÿVþÿðÿf÷ÿfðÿcýÿ
ñ~jŠÿuíÿÿùÿþÿÁ
yfãÿÿèùÿúÿcÿÿð*jb€ýÿüýÿšºñÿHŒùÿ°hylùèÿVþÿðÿfåÿcýÿ
ñ~jŠÿuíÿÿùÿþÿÁ
yfãÿÿèùÿúÿcÿÿð*jb€ýÿüýÿšºñÿHŒùÿ°hylùèÿVþÿëÿâÿÇÿfúÿ
ŒbKÑl
Jó{a*ýÿ|}ÓÿÿVýupPÚpÿ|oªügj€/®ÿÿQÿÿãq¯PÔolæLÌ/®µrrý{a*ÿÿðeÿÿIþui\œ2Ý_d~šWX·Þ\V©h^þqÿÿž/Ôql¥¯P¢ÿÿXÿÿæ÷kßM[vy±_Mg¹ñbjÅLÕÿÿVþÿpèWZÉgd]öøÿf÷ÿfúÿ
ŒbKÑl
Jó{a*ýÿ|}ÓÿÿVýupPÚpÿ|oªügj€/®ÿÿQÿÿãq¯PÔolæLÌ/®µrrý{a*ÿÿðeÿÿIþui\œ2Ý_d~šWX·Þ\V©h^þqÿÿž/Ôql¥¯P¢ÿÿXÿÿæ÷kßM[vy±_Mg¹ñbjÅLÕÿÿVþÿpèWZÉgd]öøÿfïÿ
ŒbKÑl
Jó{a*ýÿ|}ÓÿÿVýupPÚpÿ|oªügj€/®ÿÿQÿÿãq¯PÔolæLÌ/®µrrý{a*ÿÿðeÿÿIþui\œ2Ý_d~šWX·Þ\V©h^þqÿÿž/Ôql¥¯P¢ÿÿXÿÿæ÷kßM[vy±_Mg¹ñbjÅLÕÿÿVþÿpèWZÉgd]öóÿâÿÇÿfúÿ
ÕÊwMù¿dÿIýÿ^céÿÿ^íuÕÖxb×`±WÆÿÍcÿÿúRÿÿõV§šÝ
r¥vÐÅcÿV±r·dÿIÿÿðeÿÿ[ôĹ5ùjóƯIš¢üRåÈgxÍøL±UñÿÿcÔÿb§šÿÿüVþÿøpÿvÊtûKÿc©§Ê|óo¡ÈüevÐÅÿÿVþÿbÖSŒìOú¥®øÿf÷ÿfúÿ
ÕÊwMù¿dÿIýÿ^céÿÿ^íuÕÖxb×`±WÆÿÍcÿÿúRÿÿõV§šÝ
r¥vÐÅcÿV±r·dÿIÿÿðeÿÿ[ôĹ5ùjóƯIš¢üRåÈgxÍøL±UñÿÿcÔÿb§šÿÿüVþÿøpÿvÊtûKÿc©§Ê|óo¡ÈüevÐÅÿÿVþÿbÖSŒìOú¥®øÿfïÿ
ÕÊwMù¿dÿIýÿ^céÿÿ^íuÕÖxb×`±WÆÿÍcÿÿúRÿÿõV§šÝ
r¥vÐÅcÿV±r·dÿIÿÿðeÿÿ[ôĹ5ùjóƯIš¢üRåÈgxÍøL±UñÿÿcÔÿb§šÿÿüVþÿøpÿvÊtûKÿc©§Ê|óo¡ÈüevÐÅÿÿVþÿbÖSŒìOú¥®óÿâÿÇÿfúÿ
ubÿ¹kÿWýÿ¢ÿþ9ÿuæÝbÈoÀ¢ÌÿÇcþÿC?ùÿ²
§ºÝ
fžºÂvìËcÿQÀ¯ÇkÿWÿÿðeÿþHôLµLøjÒ[ÂRš³þi€wÁdßžDØPÀ§îÿÿcÄÿV§ºþÿQùÿÎqÿ{»ÿbÿc©¹Ñ÷kÒþVvìËÿÿVþÿbñÍzXþ««øÿf÷ÿfúÿ
ubÿ¹kÿWýÿ¢ÿþ9ÿuæÝbÈoÀ¢ÌÿÇcþÿC?ùÿ²
§ºÝ
fžºÂvìËcÿQÀ¯ÇkÿWÿÿðeÿþHôLµLøjÒ[ÂRš³þi€wÁdßžDØPÀ§îÿÿcÄÿV§ºþÿQùÿÎqÿ{»ÿbÿc©¹Ñ÷kÒþVvìËÿÿVþÿbñÍzXþ««øÿfïÿ
[393 lines skipped]
1
0
Update of /project/elephant/cvsroot/elephant/doc
In directory clnet:/tmp/cvs-serv1153
Modified Files:
ArchDiagram1.ppt
Log Message:
My take on a talk
Binary files /project/elephant/cvsroot/elephant/doc/ArchDiagram1.ppt 2007/04/21 18:48:29 1.1 and /project/elephant/cvsroot/elephant/doc/ArchDiagram1.ppt 2007/04/23 03:40:39 1.2 differ
1
0
Update of /project/elephant/cvsroot/elephant/src/elephant
In directory clnet:/tmp/cvs-serv21337/src/elephant
Modified Files:
collections.lisp serializer2.lisp
Log Message:
Fix condition handler; map-index error checking
--- /project/elephant/cvsroot/elephant/src/elephant/collections.lisp 2007/04/23 02:26:53 1.23
+++ /project/elephant/cvsroot/elephant/src/elephant/collections.lisp 2007/04/23 02:41:11 1.24
@@ -415,7 +415,7 @@
(defmethod map-index (fn (index btree-index) &rest args &key start end (value nil value-set-p) from-end)
(declare (dynamic-extent args)
(ignorable args))
- (unless (lisp-compare<= start end)
+ (unless (or (null start) (null end) (lisp-compare<= start end))
(error "map-index called with start = ~A and end = ~A. Start must be less than or equal to end according to elephant::lisp-compare<=."
start end))
(let ((sc (get-con index))
--- /project/elephant/cvsroot/elephant/src/elephant/serializer2.lisp 2007/04/22 03:35:09 1.40
+++ /project/elephant/cvsroot/elephant/src/elephant/serializer2.lisp 2007/04/23 02:41:11 1.41
@@ -201,7 +201,7 @@
(serialize-string frob bs))
(persistent
(unless (valid-persistent-reference-p frob sc)
- (raise-cross-store-condition frob sc))
+ (signal-cross-reference-error frob sc))
(buffer-write-byte +persistent+ bs)
(buffer-write-int32 (oid frob) bs)
;; This circumlocution is necessitated by
1
0
Update of /project/elephant/cvsroot/elephant/src/elephant
In directory clnet:/tmp/cvs-serv18051/src/elephant
Modified Files:
classindex.lisp collections.lisp controller.lisp
metaclasses.lisp
Log Message:
:from-end option for map-index and simple test; better error handling and argument checking
--- /project/elephant/cvsroot/elephant/src/elephant/classindex.lisp 2007/04/12 02:47:32 1.36
+++ /project/elephant/cvsroot/elephant/src/elephant/classindex.lisp 2007/04/23 02:26:53 1.37
@@ -394,11 +394,11 @@
(declare (dynamic-extent map-fn))
(map-btree #'map-fn class-idx))))
-(defun map-class-index (fn class index &rest args &key start end value)
- "This function maps over a subset of class instances in the
- order defined by the index. Specify the class and index by
- quoted name. The index may be a slot index or a derived
- index.
+(defun map-class-index (fn class index &rest args &key start end value from-end)
+ "map-class-index maps a function of two variables, taking key
+ and instance, over a subset of class instances in the order
+ defined by the index. Specify the class and index by quoted
+ name. The index may be a slot index or a derived index.
To map only a subset of key-value pairs, specify the range
using the :start and :end keywords; all elements greater than
@@ -410,17 +410,20 @@
element or last element, respectively.
To map a single value, iff it exists, use the :value keyword.
- This is the only way to travers all nil values."
+ This is the only way to travers all nil values.
+
+ To map from :end to :start in descending order, set :from-end
+ to true. If :value is used, :from-end is ignored"
(declare (dynamic-extent args)
(ignorable args))
(let* ((index (if (symbolp index)
(find-inverted-index class index)
index)))
(flet ((wrapper (key value pkey)
- (declare (ignore key pkey))
- (funcall fn value)))
+ (declare (ignore pkey))
+ (funcall fn key value)))
(declare (dynamic-extent wrapper))
- (map-index #'wrapper index :start start :end end :value value))))
+ (map-index #'wrapper index :start start :end end :value value :from-end from-end))))
;; =================
--- /project/elephant/cvsroot/elephant/src/elephant/collections.lisp 2007/04/19 05:24:37 1.22
+++ /project/elephant/cvsroot/elephant/src/elephant/collections.lisp 2007/04/23 02:26:53 1.23
@@ -382,7 +382,7 @@
(funcall fn k v)
(return nil)))))))))
-(defgeneric map-index (fn index &rest args &key start end value)
+(defgeneric map-index (fn index &rest args &key start end value from-end)
(:documentation "Map-index is like map-btree but for secondary indices, it
takes a function of three arguments: key, value and primary
key. As with map-btree the keyword arguments start and end
@@ -393,47 +393,75 @@
use the value keyword which will override any values of start
and end."))
-(defmethod map-index (fn (index btree-index) &rest args &key start end (value nil value-set-p))
+(defun pprev-hack (cur)
+ "Get the first duplicate instance of the prior value off the current cursor"
+ (let ((e? (cursor-pprev-nodup cur)))
+ (when e?
+ (let ((e? (cursor-pprev-nodup cur)))
+ (if e?
+ (cursor-pnext cur)
+ (cursor-pfirst cur))))))
+
+(defun cursor-last-range-hack (cur)
+ "Get the first duplicate instance of the last value of the cursor's index"
+ (let ((e? (cursor-plast cur)))
+ (when e?
+ (let ((e? (cursor-pprev-nodup cur)))
+ (if e?
+ (cursor-pnext cur)
+ (cursor-pfirst cur))))))
+
+
+(defmethod map-index (fn (index btree-index) &rest args &key start end (value nil value-set-p) from-end)
(declare (dynamic-extent args)
(ignorable args))
+ (unless (lisp-compare<= start end)
+ (error "map-index called with start = ~A and end = ~A. Start must be less than or equal to end according to elephant::lisp-compare<=."
+ start end))
(let ((sc (get-con index))
(end (or value end)))
(ensure-transaction (:store-controller sc)
(with-btree-cursor (cur index)
- (labels ((next-range ()
- (multiple-value-bind (exists? skey val pkey) (cursor-pnext-nodup cur)
- (if (and exists?
- (or (null end)
- (lisp-compare<= skey end)))
- (progn
- (funcall fn skey val pkey)
- (next-in-range skey))
- (return-from map-index nil))))
- (next-in-range (key)
- (multiple-value-bind (exists? skey val pkey) (cursor-pnext-dup cur)
- (if exists?
+ (labels ((continue-p (key) ;; Do we got to the next value?
+ (or (if from-end (null start) (null end))
+ (if from-end
+ (or (not (lisp-compare<= key start))
+ (lisp-compare-equal key start))
+ (lisp-compare<= key end))))
+ (value-increment () ;; Step to the next key value
+ (if from-end
+ (pprev-hack cur)
+ (cursor-pnext-nodup cur)))
+ (next-value () ;; Handle the next key value
+ (multiple-value-bind (exists? skey val pkey)
+ (value-increment)
+ (if (and exists? (continue-p skey))
(progn
(funcall fn skey val pkey)
- (next-in-range key))
- (progn
- (cursor-pset-range cur key)
- (next-range))))))
- (declare (dynamic-extent next-range next-in-range))
+ (map-duplicates skey))
+ (return-from map-index nil))))
+ (map-duplicates (key) ;; Map all duplicates for key value
+ (loop as (exists? skey val pkey) = (multiple-value-list (cursor-pnext-dup cur))
+ while exists? do (funcall fn skey val pkey))
+ (cursor-pset-range cur key)
+ (next-value)))
+ (declare (dynamic-extent next-value next-value-increment continue-p map-duplicates))
(multiple-value-bind (exists? skey val pkey)
(cond (value-set-p
(cursor-pset cur value))
- ((null start)
+ ((and (not from-end) (null start))
(cursor-pfirst cur))
- (t (cursor-pset-range cur start)))
- (if (and exists?
- (or (null end)
- (lisp-compare<= skey end)))
+ ((and from-end (null end))
+ (cursor-last-range-hack cur))
+ (t (if from-end
+ (cursor-pset-range cur end)
+ (cursor-pset-range cur start))))
+ (if (and exists? (continue-p skey))
(progn
(funcall fn skey val pkey)
- (next-in-range skey))
+ (map-duplicates skey))
nil)))))))
-
;; ===============================
;; Some generic utility functions
;; ===============================
--- /project/elephant/cvsroot/elephant/src/elephant/controller.lisp 2007/04/22 03:35:09 1.48
+++ /project/elephant/cvsroot/elephant/src/elephant/controller.lisp 2007/04/23 02:26:53 1.49
@@ -64,7 +64,7 @@
(defun signal-controller-lost-error (object)
(cerror "Open a new instance and continue?"
'controller-lost-error
- :format-string "Store controller for specification ~A for object ~A cannot be found."
+ :format-control "Store controller for specification ~A for object ~A cannot be found."
:format-arguments (list object (dbcn-spc-pst object))
:object object
:spec (dbcn-spc-pst object)))
--- /project/elephant/cvsroot/elephant/src/elephant/metaclasses.lisp 2007/04/12 02:47:32 1.16
+++ /project/elephant/cvsroot/elephant/src/elephant/metaclasses.lisp 2007/04/23 02:26:53 1.17
@@ -32,6 +32,10 @@
(:documentation "Abstract superclass for all persistent classes (common
to both user-defined classes and Elephant-defined objects such as collections.)"))
+(defmethod print-object ((obj persistent) stream)
+ "This is useful for debugging and being clear about what is persistent and what is not"
+ (format stream "#<~A oid:~A>" (type-of obj) (oid obj)))
+
(defclass persistent-metaclass (standard-class)
((%persistent-slots :accessor %persistent-slots)
(%indexed-slots :accessor %indexed-slots)
1
0
Update of /project/elephant/cvsroot/elephant/tests
In directory clnet:/tmp/cvs-serv18051/tests
Modified Files:
testcollections.lisp
Log Message:
:from-end option for map-index and simple test; better error handling and argument checking
--- /project/elephant/cvsroot/elephant/tests/testcollections.lisp 2007/04/06 02:51:50 1.20
+++ /project/elephant/cvsroot/elephant/tests/testcollections.lisp 2007/04/23 02:26:54 1.21
@@ -325,6 +325,19 @@
10945 ;; sum 990 to 1000 inclusive
))
+(deftest map-index-from-end
+ (let ((sum 0))
+ (flet ((collector (key value pkey)
+ (incf sum (slot1 value))))
+ (map-index #'collector index1 :start nil :end 10 :from-end t)
+ (map-index #'collector index1 :start 990 :end nil :from-end t)
+ (map-index #'collector index1 :start 400 :end 410 :from-end t))
+ sum)
+ #.(+ 49 ;; sum 4-10 inclusive (1-3 removed by here)
+ 4455 ;; sum 690-700 inclusive
+ 10945 ;; sum 990 to 1000 inclusive
+ ))
+
(deftest rem-kv
(with-transaction (:store-controller *store-controller*)
(let ((ibt (make-indexed-btree *store-controller*)))
1
0