[elephant-devel] postmodern / lispworks issues

Carlos Ungil ungil at mac.com
Sun Dec 8 06:31:49 UTC 2013


Hello,

I'd like to propose a few changes to the code available at http://www.common-lisp.net/project/elephant/darcs/elephant-1.0/ (I understand this is "the" repository, at least quicklisp seems to use it).
 
With the following changes, (do-backend-tests) runs without failures using postmodern in each combination of Lispworks/AllegroCL/SBCL and MacOSX/Windows (for some reason there is one check less in Lispworks, 582 instead of 583).

1) There is a bug that is not specific to Lispworks or Postmodern (it's the reason why CACHING-STYLE-REQUIRED fails). In src/elephant/classes.lisp

    79    (when (and (not cache-style) (has-cached-slot-specification direct-slots)
    80               (not (superclass-member-p 'cacheable-persistent-object
    81                                         (class-direct-superclasses class))))
    82      (error "Must specify the class caching style if you declare cached slots and don't~%inherit from a cached class.  Class option :cache-style must be one of~% :checkout, :txn or :none"))

the call to superclass-member-p is wrong, should be (superclass-member-p (find-class 'cacheable-persistent-object) direct-superclasses)

2) In ele-postmodern.asd there is a reference to (:file "pm-pset"), but I don't think the file was ever added to the repository. Removing the reference everything seems to work (of course adding the file would be better).

3) UPDATE-SLOT-INDEX-NIL-VALUE and SLOT-MAKUNBOUND-NIL-VALUE fail because nil values are not indexed. In src/db-postmodern/pm-btree.lisp, line 417

   416  (defmethod (setf internal-get-value) (value key (bt pm-btree))
   417    (when key
   418      (if (initialized-p bt)

the "when key" check should be removed, I think. I don't know if there might be any case where it's required, but at least the test suite runs without issues.

4) A conditional "#-lispworks" is missing in src/elephant/serializer2.lisp, line 455:
   452               ((= tag +utf8-string+)
   453                #+lispworks
   454                (coerce (deserialize-string :utf8 bs) 'base-string)
   455
   456                (deserialize-string :utf8 bs))

5) Replace the #+lispworks defmethods at the end of src/elephant/slots.lisp (lines 209-233) with the following:

#+lispworks
(defmethod slot-value-using-class ((class persistent-metaclass) (instance persistent-object) (slot symbol))
  (let ((slot-def (or (find slot (class-slots class) :key 'slot-definition-name)
 		      (find slot (class-slots class)))))
    (if (typep slot-def (or 'persistent-slot-definition 'cached-slot-definition))
	(slot-value-using-class class instance slot-def)
	(call-next-method))))

#+lispworks
(defmethod (setf slot-value-using-class) (new-value (class persistent-metaclass) (instance persistent-object) (slot symbol))
  (let ((slot-def (or (find slot (class-slots class) :key 'slot-definition-name)
 		      (find slot (class-slots class)))))
    (if (typep slot-def (or 'persistent-slot-definition 'cached-slot-definition))
	(setf (slot-value-using-class class instance slot-def) new-value)
	(call-next-method))))

#+lispworks
(defmethod slot-makunbound-using-class ((class persistent-metaclass) (instance persistent-object) (slot symbol))
  (let ((slot-def (or (find slot (class-slots class) :key 'slot-definition-name)
 		      (find slot (class-slots class)))))
    (if (typep slot-def (or 'persistent-slot-definition 'cached-slot-definition))
	(slot-makunbound-using-class class instance slot-def)
	(call-next-method))))

#+lispworks
(defmethod slot-boundp-using-class ((class persistent-metaclass) (instance persistent-object) (slot symbol))
  (let ((slot-def (or (find slot (class-slots class) :key 'slot-definition-name)
 		      (find slot (class-slots class)))))
    (if (typep slot-def (or 'persistent-slot-definition 'cached-slot-definition))
	(slot-boundp-using-class class instance slot-def)
	(call-next-method))))

6) The remaining modifications add support for cacheable-persistent-objects. This is more a work-around that a proper implementation and it might not by correct (but at least it passes the tests).

Adding the following method to src/elephant/cache.lisp ensures that cached slots are properly initialized in the database by recreating them after the instance has been created (it calls explicitly the slot-value-using-class and slot-makunbound-using-class methods).

#+lispworks 
(defmethod initialize-instance :after ((instance cacheable-persistent-object) &key from-oid (make-cached-instance nil make-cached-instance-p) &allow-other-keys)
  (dolist (slot (cached-slot-defs (class-of instance)))
    (if (slot-boundp instance (slot-definition-name slot))
	(setf (slot-value-using-class (class-of instance) instance slot)
	      (slot-value instance (slot-definition-name slot)))
      (slot-makunbound-using-class (class-of instance) instance slot)))
  instance)

In src/elephant/cached-slots.lisp, a couple of #+lispworks lines can fix the loss of sync for cached slots happening under some circumstances.

    83  (defmethod (setf caching-style) (style (class persistent-metaclass))
    84    (case style
    85      ((or :checkout :txn)
    86       (unless (cached-slot-defs class)
    87         (error "Cannot enable caching for classes with no cached slots"))
    88       (setf (%cache-style class) style))
    89      (:none
               #+lispworks (map-class (lambda (x) (when (checked-out-p x) (persistent-checkout-cancel x))) class)
    90       (setf (%cache-style class) style))
    91      (t (error "Unknown caching mode ~A" style))))

   155  (defmethod persistent-checkout-cancel ((object cacheable-persistent-object))
   156    (ensure-transaction ()
   157      (assert (pchecked-out-p object))
               #+lispworks (refresh-cached-slots object (cached-slot-names (class-of object)))
   158      (setf (pchecked-out-p object) nil)
   159      (setf (checked-out-p object) nil)))

Cheers,

Carlos


More information about the elephant-devel mailing list