You must either do something like add-to-root, or inherit from persistent-class. In that,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 "[EMAIL PROTECTED]" 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 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@common-lisp.net >> http://common-lisp.net/mailman/listinfo/elephant-devel > _______________________________________________ > elephant-devel site list > elephant-devel@common-lisp.net > http://common-lisp.net/mailman/listinfo/elephant-devel _______________________________________________ elephant-devel site list elephant-devel@common-lisp.net http://common-lisp.net/mailman/listinfo/elephant-devel
_______________________________________________ elephant-devel site list elephant-devel@common-lisp.net http://common-lisp.net/mailman/listinfo/elephant-devel