<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
<HTML>
<HEAD>
  <META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
  <META NAME="GENERATOR" CONTENT="GtkHTML/3.3.2">
</HEAD>
<BODY>
On Tue, 2006-11-14 at 14:50 -0500, Daniel Salama wrote:
<BLOCKQUOTE TYPE=CITE>
<PRE>
<FONT COLOR="#000000">Ian et al,</FONT>

<FONT COLOR="#000000">Based on my comment to Robert and that of Pierre, could you, or  </FONT>
<FONT COLOR="#000000">anyone, please clarify this for me (and maybe others):</FONT>

<FONT COLOR="#000000">If making a class persistent means that there is no need to add it to  </FONT>
<FONT COLOR="#000000">root or to any persistent collection, when I look at Robert's sample  </FONT>
<FONT COLOR="#000000">code, I see (excerpts):</FONT>

<FONT COLOR="#000000">(defclass User ()</FONT>
<FONT COLOR="#000000">   ((username :type 'string :initform "" :initarg :uname :accessor  </FONT>
<FONT COLOR="#000000">username-of)</FONT>
<FONT COLOR="#000000">    (password :type 'string :initform "" :initarg :pword :accessor  </FONT>
<FONT COLOR="#000000">password-of)</FONT>
<FONT COLOR="#000000">    (email :type 'string :initform "" :initarg :email :accessor email- </FONT>
<FONT COLOR="#000000">of)</FONT>
<FONT COLOR="#000000">    (fullname :type 'string :initform "" :initarg :fullname :accessor  </FONT>
<FONT COLOR="#000000">fullname-of)</FONT>
<FONT COLOR="#000000">    (balance :type 'integer :initform 0 :initarg :balance :accessor  </FONT>
<FONT COLOR="#000000">balance-of)))</FONT>

<FONT COLOR="#000000">(defun random-users (n)</FONT>
<FONT COLOR="#000000">   (dotimes (x n)</FONT>
<FONT COLOR="#000000">     (let ((u (make-instance</FONT>
<FONT COLOR="#000000">               'User</FONT>
<FONT COLOR="#000000">               :uname (format nil "user~A" x)</FONT>
<FONT COLOR="#000000">               :pword (random-password)</FONT>
<FONT COLOR="#000000">               :email (format nil "user~A@.nowheresville.org" x)</FONT>
<FONT COLOR="#000000">               :fullname (format nil "~A~A ~A~A" (random-password) x  </FONT>
<FONT COLOR="#000000">(random-password) x)</FONT>
<FONT COLOR="#000000">               :balance (random 100))))</FONT>
<FONT COLOR="#000000">       (add-to-root x u))))</FONT>

<FONT COLOR="#000000">There is an explicit add-to-root in random-users. I suppose the  </FONT>
<FONT COLOR="#000000">reason for this is because User class does not inherit from  </FONT>
<FONT COLOR="#000000">persistent-metaclass and in order to be able to "search for" or  </FONT>
<FONT COLOR="#000000">retrieve that object (could this also be the reason for the  </FONT>
<FONT COLOR="#000000">additional storage overhead, as you pointed out yesterday?). Right? </FONT> 
</PRE>
</BLOCKQUOTE>
You must either do something like add-to-root, or inherit from persistent-class.  In that,<BR>
you are correct.  Once an object is persisted by either mechanism, it won't be "garbage collected"<BR>
from the store; you can kill you lisp image and recreated it and then retrieve the object.<BR>
Garbage collection within memory is a separate issue, and less important---you can always<BR>
get back to the object.<BR>
<BR>
I feel that I just muddied things by using "add-to-root" here --- creating a persistent <BR>
class is almost always better for a serious application.  <BR>
<BR>
I think Ian should answer the rest of this email.
<BLOCKQUOTE TYPE=CITE>
<PRE>
<FONT COLOR="#000000">So, if my understanding is correct, defining User with defpclass  </FONT>
<FONT COLOR="#000000">instead would mean that you don't have to add-to-root because it will  </FONT>
<FONT COLOR="#000000">be automatically persisted. However, after the function exits, there  </FONT>
<FONT COLOR="#000000">will be no reference to that persistent object and will therefore be  </FONT>
<FONT COLOR="#000000">eventually garbage collected (whether or not the persistent space  </FONT>
<FONT COLOR="#000000">will be reclaimed is a different story, as you mentioned in your  </FONT>
<FONT COLOR="#000000">email). Is that right? If so, how could I avoid for the User objects  </FONT>
<FONT COLOR="#000000">to be garbage collected in this case, since there really is no other  </FONT>
<FONT COLOR="#000000">reference to these objects after creating them? Or, if the objects  </FONT>
<FONT COLOR="#000000">are NOT garbage collected, how could I manually "delete" any of them?</FONT>

<FONT COLOR="#000000">Now, if I (or Robert) had defined the User class as:</FONT>

<FONT COLOR="#000000">(defpclass User ()</FONT>
<FONT COLOR="#000000">   ((username :type 'string :initform "" :initarg :uname :accessor  </FONT>
<FONT COLOR="#000000">username-of :index t)</FONT>
<FONT COLOR="#000000">    (password :type 'string :initform "" :initarg :pword :accessor  </FONT>
<FONT COLOR="#000000">password-of)</FONT>
<FONT COLOR="#000000">    (email :type 'string :initform "" :initarg :email :accessor email- </FONT>
<FONT COLOR="#000000">of)</FONT>
<FONT COLOR="#000000">    (fullname :type 'string :initform "" :initarg :fullname :accessor  </FONT>
<FONT COLOR="#000000">fullname-of)</FONT>
<FONT COLOR="#000000">    (balance :type 'integer :initform 0 :initarg :balance :accessor  </FONT>
<FONT COLOR="#000000">balance-of)))</FONT>

<FONT COLOR="#000000">where (notice how it's defined with defpclass) the username slot is  </FONT>
<FONT COLOR="#000000">indexed, the system would automatically store a reference to the  </FONT>
<FONT COLOR="#000000">object in the slot index, and there would be no need to use the add- </FONT>
<FONT COLOR="#000000">to-root in random-users. Correct? If that's the case, how would I  </FONT>
<FONT COLOR="#000000">then go about removing this user object from persistence? Would it be  </FONT>
<FONT COLOR="#000000">by setting the indexed slot value to NIL?</FONT>

<FONT COLOR="#000000">On another note, if I want to create a collection of users, I don't  </FONT>
<FONT COLOR="#000000">have to store these users in a collection. Simply making them inherit  </FONT>
<FONT COLOR="#000000">from persistent-metaclass and indexing them would do so automatically  </FONT>
<FONT COLOR="#000000">(just like the example above). Right? How about this, then:</FONT>

<FONT COLOR="#000000">(asdf:operate 'asdf:load-op :elephant-tests)</FONT>

<FONT COLOR="#000000">(in-package :elephant-tests)</FONT>

<FONT COLOR="#000000">(setf *default-spec* *testbdb-spec*)</FONT>

<FONT COLOR="#000000">(open-store *default-spec*)</FONT>

<FONT COLOR="#000000">(defpclass state ()</FONT>
<FONT COLOR="#000000">   ((abbr :type 'string :initform "" :initarg :abbr :accessor abbr- </FONT>
<FONT COLOR="#000000">of :index t)</FONT>
<FONT COLOR="#000000">    (name :type 'string :initform "" :initarg :name :accessor name-of)))</FONT>

<FONT COLOR="#000000">(defpclass zip-code ()</FONT>
<FONT COLOR="#000000">   ((zip :type 'string :initform "" :initarg :zip :accessor zip- </FONT>
<FONT COLOR="#000000">of :index t)</FONT>
<FONT COLOR="#000000">    (city :type 'string :initform "" :initarg :city :accessor city-of)</FONT>
<FONT COLOR="#000000">    (county :type 'string :initform "" :initarg :county :accessor  </FONT>
<FONT COLOR="#000000">county-of)</FONT>
<FONT COLOR="#000000">    (state :initform nil :initarg :state :accessor state-of)))</FONT>

<FONT COLOR="#000000">(defmethod print-object ((obj state) stream)</FONT>
<FONT COLOR="#000000">   (format stream "State (abbr, name) = (~A, ~A)" (abbr-of obj) (name- </FONT>
<FONT COLOR="#000000">of obj)))</FONT>

<FONT COLOR="#000000">(defmethod print-object ((obj zip-code) stream)</FONT>
<FONT COLOR="#000000">   (format stream "Zip (zip, city, county, state) = (~A, ~A, ~A, ~A)"</FONT>
<FONT COLOR="#000000">           (zip-of obj) (city-of obj) (county-of obj) (state-of obj)))</FONT>

<FONT COLOR="#000000">(let* ((s1 (make-instance 'state :abbr "FL" :name "Florida"))</FONT>
<FONT COLOR="#000000">       (s2 (make-instance 'state :abbr "NY" :name "New York"))</FONT>
<FONT COLOR="#000000">       (z1 (make-instance 'zip-code :zip "33015" :city  </FONT>
<FONT COLOR="#000000">"Miami" :county "Dade" :state s1))</FONT>
<FONT COLOR="#000000">       (z2 (make-instance 'zip-code :zip "13605" :city  </FONT>
<FONT COLOR="#000000">"Adams" :county "Jefferson" :state s2))</FONT>
<FONT COLOR="#000000">       (z2 (make-instance 'zip-code :zip "33160" :city "Sunny Isles  </FONT>
<FONT COLOR="#000000">Beach" :county "Dade" :state s1)))</FONT>
<FONT COLOR="#000000">   (print s1)</FONT>
<FONT COLOR="#000000">   (print s2)</FONT>
<FONT COLOR="#000000">   (print z1)</FONT>
<FONT COLOR="#000000">   (print z2)</FONT>
<FONT COLOR="#000000">   (print z3))</FONT>

<FONT COLOR="#000000">Here, I'm creating a couple of state objects and a couple of zip-code  </FONT>
<FONT COLOR="#000000">objects. Since a zip-code can only belong to one state, they have a  </FONT>
<FONT COLOR="#000000">reference back to the state in order to "quickly" determine the state  </FONT>
<FONT COLOR="#000000">they belong to.</FONT>

<FONT COLOR="#000000">A couple of questions/comments here:</FONT>

<FONT COLOR="#000000">1) If I wanted to ask a state to give me all the zip-code(s) within  </FONT>
<FONT COLOR="#000000">it, would I create a slot in the state class to hold a collection of  </FONT>
<FONT COLOR="#000000">zip-code references? Or would I simply create a state-class method like:</FONT>

<FONT COLOR="#000000">(defmethod get-zip-codes ((obj state))</FONT>
<FONT COLOR="#000000">   (get-instances-by-value 'zip-code 'state obj))</FONT>

<FONT COLOR="#000000">This does not work because the state slot in zip-code is not indexed.  </FONT>
<FONT COLOR="#000000">Also, from the code above, I don't know how to get a reference to the  </FONT>
<FONT COLOR="#000000">btree in order to create a cursor so that I can linearly traverse the  </FONT>
<FONT COLOR="#000000">zip-code(s) to return only those zip-code(s) which belong to that state.</FONT>

<FONT COLOR="#000000">Of course, I would probably want to index the state slot of zip-code  </FONT>
<FONT COLOR="#000000">because there are tens of thousands of zip codes and I wouldn't want  </FONT>
<FONT COLOR="#000000">to linearly traverse them, but I just wanted to illustrate the  </FONT>
<FONT COLOR="#000000">problem to get some additional feedback (the overhead of maintaining  </FONT>
<FONT COLOR="#000000">a secondary index on state wouldn't matter too much to me because  </FONT>
<FONT COLOR="#000000">changes to this class/objects are very rare but access is much more  </FONT>
<FONT COLOR="#000000">frequent)</FONT>

<FONT COLOR="#000000">2) Maybe this is a totally different issue and mainly caused by my  </FONT>
<FONT COLOR="#000000">lisp ignorance:</FONT>

<FONT COLOR="#000000">If I have:</FONT>

<FONT COLOR="#000000">(defparameter *s1* (get-instances-by-value 'state 'abbr "FL"))</FONT>
<FONT COLOR="#000000">(defparameter *s2* (get-instances-by-value 'state 'abbr "NY"))</FONT>
<FONT COLOR="#000000">(defparameter *z1* (get-instances-by-value 'zip-code 'zip "33015"))</FONT>
<FONT COLOR="#000000">(defparameter *z2* (get-instances-by-value 'zip-code 'zip "13605"))</FONT>
<FONT COLOR="#000000">(defparameter *z3* (get-instances-by-value 'zip-code 'zip "33160"))</FONT>

<FONT COLOR="#000000">and I want to remove the association of zip code 33160 from the "FL"  </FONT>
<FONT COLOR="#000000">state object, I would think all I have to do is:</FONT>

<FONT COLOR="#000000">(setf (state-of *z3*) nil)</FONT>

<FONT COLOR="#000000">However, when I do so, I get this error message:</FONT>

<FONT COLOR="#000000">There is no applicable method for the generic function</FONT>
<FONT COLOR="#000000">   #<STANDARD-GENERIC-FUNCTION (SETF STATE-OF) (1)></FONT>
<FONT COLOR="#000000">when called with arguments</FONT>
<FONT COLOR="#000000">   (NIL</FONT>
<FONT COLOR="#000000">    (Zip (zip, city, county, state) = (33160, Sunny Isles Beach,  </FONT>
<FONT COLOR="#000000">Dade, State (abbr, name) = (FL, Florida)))).</FONT>
<FONT COLOR="#000000">    [Condition of type SIMPLE-ERROR]</FONT>

<FONT COLOR="#000000">Restarts:</FONT>
<FONT COLOR="#000000">   0: [ABORT-REQUEST] Abort handling SLIME request.</FONT>
<FONT COLOR="#000000">   1: [ABORT] Exit debugger, returning to top level.</FONT>

<FONT COLOR="#000000">Backtrace:</FONT>
<FONT COLOR="#000000">   0: ((SB-PCL::FAST-METHOD NO-APPLICABLE-METHOD (T)) #<unavailable  </FONT>
<FONT COLOR="#000000">argument> #<unavailable argument> #<STANDARD-GENERIC-FUNCTION (SETF  </FONT>
<FONT COLOR="#000000">STATE-OF) (1)> (NIL (Zip (zip, city, county, state) = (33160, Sunny  </FONT>
<FONT COLOR="#000000">Isles Beach, Dade, State (abbr, name) = (FL, Florida)))))</FONT>
<FONT COLOR="#000000">   1: ((SB-PCL::FAST-METHOD NO-APPLICABLE-METHOD (T)) #<unavailable  </FONT>
<FONT COLOR="#000000">argument> #<unavailable argument> #<STANDARD-GENERIC-FUNCTION (SETF  </FONT>
<FONT COLOR="#000000">STATE-OF) (1)> (NIL (Zip (zip, city, county, state) = (33160, Sunny  </FONT>
<FONT COLOR="#000000">Isles Beach, Dade, State (abbr, name) = (FL, Florida)))))</FONT>
<FONT COLOR="#000000">   2: (SB-INT:EVAL-IN-LEXENV (SETF (STATE-OF *Z3*) NIL) #<NULL-LEXENV>)</FONT>
<FONT COLOR="#000000">   3: (SWANK::EVAL-REGION "(setf (state-of *z3*) nil)" T)</FONT>

<FONT COLOR="#000000">3) So, going back to the previous questions in the email, if I wanted  </FONT>
<FONT COLOR="#000000">to permanently remove zip code "33015", how would I go about it?</FONT>

<FONT COLOR="#000000">Thanks again and thanks for the patience.</FONT>

<FONT COLOR="#000000">- Daniel</FONT>

<FONT COLOR="#000000">On Nov 14, 2006, at 9:04 AM, Ian Eslick wrote:</FONT>

<FONT COLOR="#000000">> Persistent classes in the current model aren't easy to fully delete -</FONT>
<FONT COLOR="#000000">> you can only make the unreachable by having no reference to them</FONT>
<FONT COLOR="#000000">> reachable from the controller or class roots.  You can drop an object</FONT>
<FONT COLOR="#000000">> from the index and there is a way to delete the object from the main</FONT>
<FONT COLOR="#000000">> system BTree - but until 4.4 you couldn't reclaim that space  </FONT>
<FONT COLOR="#000000">> (unless it</FONT>
<FONT COLOR="#000000">> happened to be reused opportunistically).  In 4.4 you can compact the</FONT>
<FONT COLOR="#000000">> DB, but elephant does not take advantage of this yet.</FONT>
<FONT COLOR="#000000">></FONT>
<FONT COLOR="#000000">> Ideally there would be an automated way to 'migrate' which is a</FONT>
<FONT COLOR="#000000">> stop-and-copy model of GC - everything reachable from the  </FONT>
<FONT COLOR="#000000">> controller and</FONT>
<FONT COLOR="#000000">> class roots gets copied, anything that isn't reachable stays in the  </FONT>
<FONT COLOR="#000000">> old</FONT>
<FONT COLOR="#000000">> DB.  This compacts and cleans the DB.  I hope that we'll clean up the</FONT>
<FONT COLOR="#000000">> model of space reclamation and provide something akin to GC in the not</FONT>
<FONT COLOR="#000000">> too distant future.  It's not a high priority in large part because</FONT>
<FONT COLOR="#000000">> on-disk space has little implication on in-memory space and disk is ~</FONT>
<FONT COLOR="#000000">> free.  (Although I do suffer from too many backup copies of my 6GB  </FONT>
<FONT COLOR="#000000">> DB -</FONT>
<FONT COLOR="#000000">> fortunately I just upgraded my computer and doubled my hard drive  </FONT>
<FONT COLOR="#000000">> space</FONT>
<FONT COLOR="#000000">> so I'm OK for a awhile longer!)</FONT>
<FONT COLOR="#000000">></FONT>
<FONT COLOR="#000000">> Ian</FONT>
<FONT COLOR="#000000">></FONT>
<FONT COLOR="#000000">> Pierre THIERRY wrote:</FONT>
<FONT COLOR="#000000">>> Scribit Daniel Salama dies 13/11/2006 hora 21:00:</FONT>
<FONT COLOR="#000000">>></FONT>
<FONT COLOR="#000000">>>> So, if I make my class persistent, it's persistent... period! I  </FONT>
<FONT COLOR="#000000">>>> don't</FONT>
<FONT COLOR="#000000">>>> need to add it to a collection or to the root.</FONT>
<FONT COLOR="#000000">>>></FONT>
<FONT COLOR="#000000">>></FONT>
<FONT COLOR="#000000">>> Well, I did not know that before that discussion. I think it's not</FONT>
<FONT COLOR="#000000">>> clearly indicated in the docs...</FONT>
<FONT COLOR="#000000">>></FONT>
<FONT COLOR="#000000">>> And then I wonder: if I use persistent classes, how do I remove an</FONT>
<FONT COLOR="#000000">>> object from the store?</FONT>
<FONT COLOR="#000000">>></FONT>
<FONT COLOR="#000000">>> Curiously,</FONT>
<FONT COLOR="#000000">>> Nowhere man</FONT>
<FONT COLOR="#000000">>></FONT>
<FONT COLOR="#000000">>> --------------------------------------------------------------------- </FONT>
<FONT COLOR="#000000">>> ---</FONT>
<FONT COLOR="#000000">>></FONT>
<FONT COLOR="#000000">>> _______________________________________________</FONT>
<FONT COLOR="#000000">>> elephant-devel site list</FONT>
<FONT COLOR="#000000">>> <A HREF="mailto:elephant-devel@common-lisp.net">elephant-devel@common-lisp.net</A></FONT>
<FONT COLOR="#000000">>> <A HREF="http://common-lisp.net/mailman/listinfo/elephant-devel">http://common-lisp.net/mailman/listinfo/elephant-devel</A></FONT>
<FONT COLOR="#000000">> _______________________________________________</FONT>
<FONT COLOR="#000000">> elephant-devel site list</FONT>
<FONT COLOR="#000000">> <A HREF="mailto:elephant-devel@common-lisp.net">elephant-devel@common-lisp.net</A></FONT>
<FONT COLOR="#000000">> <A HREF="http://common-lisp.net/mailman/listinfo/elephant-devel">http://common-lisp.net/mailman/listinfo/elephant-devel</A></FONT>

<FONT COLOR="#000000">_______________________________________________</FONT>
<FONT COLOR="#000000">elephant-devel site list</FONT>
<FONT COLOR="#000000"><A HREF="mailto:elephant-devel@common-lisp.net">elephant-devel@common-lisp.net</A></FONT>
<FONT COLOR="#000000"><A HREF="http://common-lisp.net/mailman/listinfo/elephant-devel">http://common-lisp.net/mailman/listinfo/elephant-devel</A></FONT>
</PRE>
</BLOCKQUOTE>
</BODY>
</HTML>