[elephant-devel] Querying Advice

Robert L. Read read at robertlread.net
Tue Nov 14 20:20:28 UTC 2006


On Tue, 2006-11-14 at 14:50 -0500, Daniel Salama wrote:

> Ian et al,
> 
> Based on my comment to Robert and that of Pierre, could you, or  
> anyone, please clarify this for me (and maybe others):
> 
> If making a class persistent means that there is no need to add it to  
> root or to any persistent collection, when I look at Robert's sample  
> code, I see (excerpts):
> 
> (defclass User ()
>    ((username :type 'string :initform "" :initarg :uname :accessor  
> username-of)
>     (password :type 'string :initform "" :initarg :pword :accessor  
> password-of)
>     (email :type 'string :initform "" :initarg :email :accessor email- 
> of)
>     (fullname :type 'string :initform "" :initarg :fullname :accessor  
> fullname-of)
>     (balance :type 'integer :initform 0 :initarg :balance :accessor  
> balance-of)))
> 
> (defun random-users (n)
>    (dotimes (x n)
>      (let ((u (make-instance
>                'User
>                :uname (format nil "user~A" x)
>                :pword (random-password)
>                :email (format nil "user~A at .nowheresville.org" x)
>                :fullname (format nil "~A~A ~A~A" (random-password) x  
> (random-password) x)
>                :balance (random 100))))
>        (add-to-root x u))))
> 
> There is an explicit add-to-root in random-users. I suppose the  
> reason for this is because User class does not inherit from  
> persistent-metaclass and in order to be able to "search for" or  
> retrieve that object (could this also be the reason for the  
> additional storage overhead, as you pointed out yesterday?). Right?  

You must either do something like add-to-root, or inherit from
persistent-class.  In that,
you are correct.  Once an object is persisted by either mechanism, it
won't be "garbage collected"
from the store; you can kill you lisp image and recreated it and then
retrieve the object.
Garbage collection within memory is a separate issue, and less
important---you can always
get back to the object.

I feel that I just muddied things by using "add-to-root" here ---
creating a persistent 
class is almost always better for a serious application.  

I think Ian should answer the rest of this email.

> So, if my understanding is correct, defining User with defpclass  
> instead would mean that you don't have to add-to-root because it will  
> be automatically persisted. However, after the function exits, there  
> will be no reference to that persistent object and will therefore be  
> eventually garbage collected (whether or not the persistent space  
> will be reclaimed is a different story, as you mentioned in your  
> email). Is that right? If so, how could I avoid for the User objects  
> to be garbage collected in this case, since there really is no other  
> reference to these objects after creating them? Or, if the objects  
> are NOT garbage collected, how could I manually "delete" any of them?
> 
> Now, if I (or Robert) had defined the User class as:
> 
> (defpclass User ()
>    ((username :type 'string :initform "" :initarg :uname :accessor  
> username-of :index t)
>     (password :type 'string :initform "" :initarg :pword :accessor  
> password-of)
>     (email :type 'string :initform "" :initarg :email :accessor email- 
> of)
>     (fullname :type 'string :initform "" :initarg :fullname :accessor  
> fullname-of)
>     (balance :type 'integer :initform 0 :initarg :balance :accessor  
> balance-of)))
> 
> where (notice how it's defined with defpclass) the username slot is  
> indexed, the system would automatically store a reference to the  
> object in the slot index, and there would be no need to use the add- 
> to-root in random-users. Correct? If that's the case, how would I  
> then go about removing this user object from persistence? Would it be  
> by setting the indexed slot value to NIL?
> 
> On another note, if I want to create a collection of users, I don't  
> have to store these users in a collection. Simply making them inherit  
> from persistent-metaclass and indexing them would do so automatically  
> (just like the example above). Right? How about this, then:
> 
> (asdf:operate 'asdf:load-op :elephant-tests)
> 
> (in-package :elephant-tests)
> 
> (setf *default-spec* *testbdb-spec*)
> 
> (open-store *default-spec*)
> 
> (defpclass state ()
>    ((abbr :type 'string :initform "" :initarg :abbr :accessor abbr- 
> of :index t)
>     (name :type 'string :initform "" :initarg :name :accessor name-of)))
> 
> (defpclass zip-code ()
>    ((zip :type 'string :initform "" :initarg :zip :accessor zip- 
> of :index t)
>     (city :type 'string :initform "" :initarg :city :accessor city-of)
>     (county :type 'string :initform "" :initarg :county :accessor  
> county-of)
>     (state :initform nil :initarg :state :accessor state-of)))
> 
> (defmethod print-object ((obj state) stream)
>    (format stream "State (abbr, name) = (~A, ~A)" (abbr-of obj) (name- 
> of obj)))
> 
> (defmethod print-object ((obj zip-code) stream)
>    (format stream "Zip (zip, city, county, state) = (~A, ~A, ~A, ~A)"
>            (zip-of obj) (city-of obj) (county-of obj) (state-of obj)))
> 
> (let* ((s1 (make-instance 'state :abbr "FL" :name "Florida"))
>        (s2 (make-instance 'state :abbr "NY" :name "New York"))
>        (z1 (make-instance 'zip-code :zip "33015" :city  
> "Miami" :county "Dade" :state s1))
>        (z2 (make-instance 'zip-code :zip "13605" :city  
> "Adams" :county "Jefferson" :state s2))
>        (z2 (make-instance 'zip-code :zip "33160" :city "Sunny Isles  
> Beach" :county "Dade" :state s1)))
>    (print s1)
>    (print s2)
>    (print z1)
>    (print z2)
>    (print z3))
> 
> Here, I'm creating a couple of state objects and a couple of zip-code  
> objects. Since a zip-code can only belong to one state, they have a  
> reference back to the state in order to "quickly" determine the state  
> they belong to.
> 
> A couple of questions/comments here:
> 
> 1) If I wanted to ask a state to give me all the zip-code(s) within  
> it, would I create a slot in the state class to hold a collection of  
> zip-code references? Or would I simply create a state-class method like:
> 
> (defmethod get-zip-codes ((obj state))
>    (get-instances-by-value 'zip-code 'state obj))
> 
> This does not work because the state slot in zip-code is not indexed.  
> Also, from the code above, I don't know how to get a reference to the  
> btree in order to create a cursor so that I can linearly traverse the  
> zip-code(s) to return only those zip-code(s) which belong to that state.
> 
> Of course, I would probably want to index the state slot of zip-code  
> because there are tens of thousands of zip codes and I wouldn't want  
> to linearly traverse them, but I just wanted to illustrate the  
> problem to get some additional feedback (the overhead of maintaining  
> a secondary index on state wouldn't matter too much to me because  
> changes to this class/objects are very rare but access is much more  
> frequent)
> 
> 2) Maybe this is a totally different issue and mainly caused by my  
> lisp ignorance:
> 
> If I have:
> 
> (defparameter *s1* (get-instances-by-value 'state 'abbr "FL"))
> (defparameter *s2* (get-instances-by-value 'state 'abbr "NY"))
> (defparameter *z1* (get-instances-by-value 'zip-code 'zip "33015"))
> (defparameter *z2* (get-instances-by-value 'zip-code 'zip "13605"))
> (defparameter *z3* (get-instances-by-value 'zip-code 'zip "33160"))
> 
> and I want to remove the association of zip code 33160 from the "FL"  
> state object, I would think all I have to do is:
> 
> (setf (state-of *z3*) nil)
> 
> However, when I do so, I get this error message:
> 
> There is no applicable method for the generic function
>    #<STANDARD-GENERIC-FUNCTION (SETF STATE-OF) (1)>
> when called with arguments
>    (NIL
>     (Zip (zip, city, county, state) = (33160, Sunny Isles Beach,  
> Dade, State (abbr, name) = (FL, Florida)))).
>     [Condition of type SIMPLE-ERROR]
> 
> Restarts:
>    0: [ABORT-REQUEST] Abort handling SLIME request.
>    1: [ABORT] Exit debugger, returning to top level.
> 
> Backtrace:
>    0: ((SB-PCL::FAST-METHOD NO-APPLICABLE-METHOD (T)) #<unavailable  
> argument> #<unavailable argument> #<STANDARD-GENERIC-FUNCTION (SETF  
> STATE-OF) (1)> (NIL (Zip (zip, city, county, state) = (33160, Sunny  
> Isles Beach, Dade, State (abbr, name) = (FL, Florida)))))
>    1: ((SB-PCL::FAST-METHOD NO-APPLICABLE-METHOD (T)) #<unavailable  
> argument> #<unavailable argument> #<STANDARD-GENERIC-FUNCTION (SETF  
> STATE-OF) (1)> (NIL (Zip (zip, city, county, state) = (33160, Sunny  
> Isles Beach, Dade, State (abbr, name) = (FL, Florida)))))
>    2: (SB-INT:EVAL-IN-LEXENV (SETF (STATE-OF *Z3*) NIL) #<NULL-LEXENV>)
>    3: (SWANK::EVAL-REGION "(setf (state-of *z3*) nil)" T)
> 
> 3) So, going back to the previous questions in the email, if I wanted  
> to permanently remove zip code "33015", how would I go about it?
> 
> Thanks again and thanks for the patience.
> 
> - Daniel
> 
> On Nov 14, 2006, at 9:04 AM, Ian Eslick wrote:
> 
> > Persistent classes in the current model aren't easy to fully delete -
> > you can only make the unreachable by having no reference to them
> > reachable from the controller or class roots.  You can drop an object
> > from the index and there is a way to delete the object from the main
> > system BTree - but until 4.4 you couldn't reclaim that space  
> > (unless it
> > happened to be reused opportunistically).  In 4.4 you can compact the
> > DB, but elephant does not take advantage of this yet.
> >
> > Ideally there would be an automated way to 'migrate' which is a
> > stop-and-copy model of GC - everything reachable from the  
> > controller and
> > class roots gets copied, anything that isn't reachable stays in the  
> > old
> > DB.  This compacts and cleans the DB.  I hope that we'll clean up the
> > model of space reclamation and provide something akin to GC in the not
> > too distant future.  It's not a high priority in large part because
> > on-disk space has little implication on in-memory space and disk is ~
> > free.  (Although I do suffer from too many backup copies of my 6GB  
> > DB -
> > fortunately I just upgraded my computer and doubled my hard drive  
> > space
> > so I'm OK for a awhile longer!)
> >
> > Ian
> >
> > Pierre THIERRY wrote:
> >> Scribit Daniel Salama dies 13/11/2006 hora 21:00:
> >>
> >>> So, if I make my class persistent, it's persistent... period! I  
> >>> don't
> >>> need to add it to a collection or to the root.
> >>>
> >>
> >> Well, I did not know that before that discussion. I think it's not
> >> clearly indicated in the docs...
> >>
> >> And then I wonder: if I use persistent classes, how do I remove an
> >> object from the store?
> >>
> >> Curiously,
> >> Nowhere man
> >>
> >> --------------------------------------------------------------------- 
> >> ---
> >>
> >> _______________________________________________
> >> elephant-devel site list
> >> elephant-devel at common-lisp.net
> >> http://common-lisp.net/mailman/listinfo/elephant-devel
> > _______________________________________________
> > elephant-devel site list
> > elephant-devel at common-lisp.net
> > http://common-lisp.net/mailman/listinfo/elephant-devel
> 
> _______________________________________________
> elephant-devel site list
> elephant-devel at common-lisp.net
> http://common-lisp.net/mailman/listinfo/elephant-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/elephant-devel/attachments/20061114/89bfcf0a/attachment.html>


More information about the elephant-devel mailing list