Update of /project/elephant/cvsroot/elephant/src/elephant In directory clnet:/tmp/cvs-serv26146/src/elephant
Modified Files: classes.lisp classindex.lisp metaclasses.lisp Log Message: Fixed indexing bugs and SQL backend secondary index abstraction
--- /project/elephant/cvsroot/elephant/src/elephant/classes.lisp 2006/02/25 17:04:56 1.6 +++ /project/elephant/cvsroot/elephant/src/elephant/classes.lisp 2006/02/25 20:53:57 1.7 @@ -20,7 +20,6 @@
(defvar *debug-si* nil)
- (defmethod initialize-instance :before ((instance persistent) &rest initargs &key from-oid @@ -68,10 +67,35 @@ (when (not (slot-boundp instance '%indexed-slots)) (update-indexed-record instance (indexed-slot-names-from-defs instance)))))
+(defmethod reinitialize-instance :around ((instance persistent-metaclass) &rest initargs &key &allow-other-keys) + (declare (ignore initargs)) + (prog1 + (call-next-method) + (when (class-finalized-p instance) + (update-persistent-slots instance (persistent-slot-names instance)) + (update-indexed-record instance (indexed-slot-names-from-defs instance)) + (if (removed-indexing? instance) + (progn + (let ((class-idx (get-value (class-name instance) (controller-class-root *store-controller*)))) + (when class-idx + (wipe-class-indexing instance class-idx))) + (setf (%index-cache instance) nil)) + (set-db-synch instance :class)) + #+allegro + (loop with persistent-slots = (persistent-slots instance) + for slot-def in (class-direct-slots instance) + when (member (slot-definition-name slot-def) persistent-slots) + do (initialize-accessors slot-def instance)) + (make-instances-obsolete instance)))) + ;; ================================================ ;; PERSISTENT OBJECT MAINTENANCE ;; ================================================
+;; +;; CLASS INSTANCE INITIALIZATION +;; + (defmethod shared-initialize :around ((instance persistent-object) slot-names &rest initargs &key from-oid &allow-other-keys) "Initializes the persistent slots via initargs or forms. This seems to be necessary because it is typical for @@ -90,45 +114,51 @@ (transient-slot-names class) (remove-if #'persistent-slot-p slot-names))) (persistent-slot-inits - (if (eq slot-names t) persistent-slot-names + (if (eq slot-names t) + persistent-slot-names (remove-if-not #'persistent-slot-p slot-names)))) (inhibit-indexing oid) (unwind-protect - ;; initialize the persistent slots - (flet ((initialize-from-initarg (slot-def) - (loop for initarg in initargs - with slot-initargs = (slot-definition-initargs slot-def) - when (member initarg slot-initargs :test #'eq) - do - (setf (slot-value-using-class class instance slot-def) - (getf initargs initarg)) - (return t)))) - (with-transaction (:store-controller (get-con instance)) - (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) - do - (let ((initfun (slot-definition-initfunction slot-def))) - (when initfun - (setf (slot-value-using-class class instance slot-def) - (funcall initfun)))))) -;; (format t "transient-slot-inits ~A~%" transient-slot-inits) -;; (format t "indices boundp ~A~%" (slot-boundp instance 'indices)) -;; (format t "indices-caches boundp ~A~%" (slot-boundp instance 'indices-cache)) - ;; let the implementation initialize the transient slots - (apply #'call-next-method instance transient-slot-inits initargs)) + (progn + ;; initialize the persistent slots ourselves + (initialize-persistent-slots class instance persistent-slot-inits initargs) + ;; let the implementation initialize the transient slots + (apply #'call-next-method instance transient-slot-inits initargs)) (uninhibit-indexing oid)) - ;; Inhibit indexing altogether if the object already was defined (ie being created - ;; from an oid) as it should be indexed already. This hack avoids a deadlock - ;; situation where we write the class or index page that we are currently reading - ;; via a cursor without going through the cursor abstraction. There has to be a - ;; better way to do this. - (when (and (indexed class) (not from-oid)) - (let ((class-index (find-class-index class))) - (when class-index - (setf (get-value oid class-index) instance)))) - )))) + ;; Inhibit indexing altogether if the object already was defined (ie being created + ;; from an oid) as it should be indexed already. This hack avoids a deadlock + ;; situation where we write the class or index page that we are currently reading + ;; via a cursor without going through the cursor abstraction. There has to be a + ;; better way to do this. + (when (and (indexed class) (not from-oid)) + (let ((class-index (find-class-index class))) + (when class-index + (setf (get-value oid class-index) instance)))) + )))) + +(defun initialize-persistent-slots (class instance persistent-slot-inits initargs) + (flet ((initialize-from-initarg (slot-def) + (loop for initarg in initargs + with slot-initargs = (slot-definition-initargs slot-def) + when (member initarg slot-initargs :test #'eq) + do + (setf (slot-value-using-class class instance slot-def) + (getf initargs initarg)) + (return t)))) + (with-transaction (:store-controller (get-con instance)) + (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) + do + (let ((initfun (slot-definition-initfunction slot-def))) + (when initfun + (setf (slot-value-using-class class instance slot-def) + (funcall initfun)))))))) + +;; +;; CLASS REDEFINITION PROTOCOL +;;
(defmethod update-instance-for-redefined-class :around ((instance persistent-object) added-slots discarded-slots property-list &rest initargs &key &allow-other-keys) ;; NOTE: probably should delete discarded slots, but we'll worry about that later @@ -144,6 +174,10 @@ (apply #'shared-initialize instance new-persistent-slots initargs)) ))
+;; +;; CLASS CHANGE PROTOCOL +;; + (defmethod update-instance-for-different-class :around ((previous persistent) (current persistent) &rest initargs &key) (let* ((old-class (class-of previous)) (new-class (class-of current)) @@ -174,6 +208,10 @@ (call-next-method)))
+;; +;; SLOT ACCESS PROTOCOLS +;; + (defmethod slot-value-using-class :around ((class persistent-metaclass) (instance persistent-object) (slot-def persistent-slot-definition)) "Get the slot value from the database." (declare (optimize (speed 3))) @@ -256,21 +294,6 @@ (loop for writer in writers do (make-persistent-writer writer slot-definition class class-name))))
-#+allegro -(defmethod reinitialize-instance :around ((instance persistent-metaclass) &rest initargs &key &allow-other-keys) - (declare (ignore initargs)) - (prog1 - (call-next-method) - (when (class-finalized-p instance) - (update-persistent-slots instance (persistent-slot-names instance)) - (update-indexed-record instance (indexed-slot-names-from-defs instance)) - (set-db-synch instance :class) - (loop with persistent-slots = (persistent-slots instance) - for slot-def in (class-direct-slots instance) - when (member (slot-definition-name slot-def) persistent-slots) - do (initialize-accessors slot-def instance)) - (make-instances-obsolete instance)))) - ;; ;; CMU / SBCL ;; @@ -318,15 +341,3 @@ (make-persistent-slot-boundp name))) slot-def)
-#+(or cmu sbcl openmcl) -(defmethod reinitialize-instance :around ((instance persistent-metaclass) &rest initargs &key &allow-other-keys) - (declare (ignore initargs)) - (prog1 - (call-next-method) - (when (class-finalized-p instance) - (update-persistent-slots instance (persistent-slot-names instance)) - (update-indexed-record instance (indexed-slot-names-from-defs instance)) - (set-db-synch instance :class) -;; (initialize-internal-slot-functions - (make-instances-obsolete instance)))) - --- /project/elephant/cvsroot/elephant/src/elephant/classindex.lisp 2006/02/22 20:18:51 1.4 +++ /project/elephant/cvsroot/elephant/src/elephant/classindex.lisp 2006/02/25 20:53:57 1.5 @@ -175,12 +175,14 @@ ;; =============================
(defmethod enable-class-indexing ((class persistent-metaclass) indexed-slot-names &key (sc *store-controller*)) + (assert (not (= 0 (length indexed-slot-names)))) (let ((croot (controller-class-root sc))) (multiple-value-bind (btree found) (get-value (class-name class) croot) (declare (ignore btree)) (when found (error "Class is already enabled for indexing! Run disable class indexing to clean up."))) ;; Put class instance index into the class root & cache it in the class object + (update-indexed-record class indexed-slot-names) (with-transaction (:store-controller sc) (let ((class-idx (build-indexed-btree sc))) (setf (get-value (class-name class) croot) class-idx) @@ -200,31 +202,40 @@ (disable-class-indexing class :sc sc))))
(defmethod disable-class-indexing ((class persistent-metaclass) &key (sc *store-controller*) (errorp nil)) + "Disable any class indices from the database, even if the current class object is not + officially indexed. This ensures there is no persistent trace of a class index. Storage + is reclaimed also" (let ((class-idx (find-class-index class :sc sc :errorp errorp))) - (unless class-idx (return-from disable-class-indexing nil)) - ;; Remove all instance key/value data from the class index (& secondary indices) - (with-transaction (:store-controller sc) - (with-btree-cursor (cur class-idx) - (when (cursor-first cur) - (loop while (cursor-delete cur))))) - ;; Get the names of all indices & remove them - (let ((names nil)) - (map-indices (lambda (name secondary-index) - (declare (ignore secondary-index)) - (push name names)) - class-idx) - (dolist (name names) - (if (member name (class-slots class)) - (remove-class-slot-index class name) - (with-transaction (:store-controller sc) - (remove-index class-idx name))))) - ;; Drop the class instance index from the class root - (with-transaction (:store-controller sc) - (remove-kv (class-name class) (controller-class-root sc))) - (setf (%index-cache class) nil) - ;; Clear out the current class - (update-indexed-record class nil) - )) + (if class-idx + (progn + (wipe-class-indexing class class-idx :sc sc) + (update-indexed-record class nil)) + (when errorp + (error "No class index exists in persistent store ~A" sc) + (return-from disable-class-indexing nil))))) + +(defmethod wipe-class-indexing ((class persistent-metaclass) class-idx &key (sc *store-controller*)) + ;; Clear out the current class record + (with-transaction (:store-controller sc) + (with-btree-cursor (cur class-idx) + (when (cursor-first cur) + (loop while (cursor-delete cur))))) + ;; Get the names of all indices & remove them + (let ((names nil)) + (map-indices (lambda (name secondary-index) + (declare (ignore secondary-index)) + (push name names)) + class-idx) + (dolist (name names) + (if (member name (class-slots class)) + (remove-class-slot-index class name) + (with-transaction (:store-controller sc) + (remove-index class-idx name))))) + ;; Drop the class instance index from the class root + (with-transaction (:store-controller sc) + (remove-kv (class-name class) (controller-class-root sc))) + (setf (%index-cache class) nil) + )
(defmethod add-class-slot-index ((class symbol) slot-name &key (sc *store-controller*)) (add-class-slot-index (find-class class) slot-name :sc sc)) --- /project/elephant/cvsroot/elephant/src/elephant/metaclasses.lisp 2006/02/22 21:03:47 1.4 +++ /project/elephant/cvsroot/elephant/src/elephant/metaclasses.lisp 2006/02/25 20:53:57 1.5 @@ -116,11 +116,14 @@
(defmethod indexed-record ((class standard-class)) nil) + (defmethod indexed-record ((class persistent-metaclass)) - (car (%indexed-slots class))) + (when (slot-boundp class '%indexed-slots) + (car (%indexed-slots class))))
(defmethod old-indexed-record ((class persistent-metaclass)) - (cdr (%indexed-slots class))) + (when (slot-boundp class '%indexed-slots) + (cdr (%indexed-slots class))))
(defmethod update-indexed-record ((class persistent-metaclass) new-slot-list) (let ((oldrec (if (slot-boundp class '%indexed-slots) @@ -132,6 +135,10 @@ :derived (when oldrec (indexing-record-derived oldrec))) (if oldrec oldrec nil)))))
+(defmethod removed-indexing? ((class persistent-metaclass)) + (and (not (indexed class)) + (previously-indexed class))) + (defun indexed-slot-names-from-defs (class) (let ((slot-definitions (class-slots class))) (loop for slot-definition in slot-definitions @@ -188,6 +195,14 @@ (or (indexing-record-slots (indexed-record class)) (indexing-record-derived (indexed-record class)))))
+(defmethod previously-indexed ((class persistent-metaclass)) + (and (slot-boundp class '%indexed-slots) + (not (null (%indexed-slots class))) + (let ((old (old-indexed-record class))) + (when (not (null old)) + (or (indexing-record-slots old) + (indexing-record-derived old)))))) + (defmethod indexed ((slot standard-slot-definition)) nil) (defmethod indexed ((class standard-class)) nil)