Oops - I forgot about that hack. In order to make serialization thread safe I need to use locks which are non-standard. I'll hack something for SBCL in minute or two.
If you want to manually controll transaction you can use the following protocol: (start-ele-transaction) (transaction-commit) (transaction-abort) inside of your own logic. with-transaction is a convenience macro with a specific control policy. We can leave that policy and let more complex programs make it all explicit (and suffer the consequences). Perhaps a 'condition on abort' on a non-local exit (that isn't a thrown condition) from with-transaction would help catch any annoying bugs caused by silent aborts. Ian Vladimir Sedach wrote: >> For the record, the current measure of a successful body within >> (with-transaction ()) is an ordinary exit. _ANY_ non-local exit such as >> throw, error, etc as well as goto labels, or (return-from <function>) >> all result in aborts. More technically the test is written as: >> >> (with-transaction () >> <txn-body>) >> >> => >> >> (unwind-protect >> (prog1 >> <txn-body> >> (setf success t) >> (db-transaction-commit ...)) >> (unless success >> (db-transaction-abort ...))) >> >> Should this policy be changed? Should all conditions and throws result >> in aborts but other non-local exits in success? > > First of all, unless I am missing something, shouldn't it be (progn > <txn-body> (db-transaction-commit ...) [and then] (setf success t))? > > I think that the policy of aborting the transaction on all non-local > exits as it is now is a good idea. Maybe <txn-body> will funcall some > lambda passed to it that does weird things with the control flow which > could lead to hard-to-find bugs. I also have a feeling this may lead > to such bugs with code that tries to fake continuations in some > instances, but I can't think of any examples. However, then there > should be a protocol to let programmers deal with transactions in > hairy code themselves (hey, transactions are a part of the business > logic or whatever... :)). Here is what I propose: > > (defun close-transaction () ;; this gets exported > (db-transaction-commit :transaction *txn* > :txn-nosync *txn-nosync* > :txn-sync *txn-sync*) > (setq *success* t)) > > now (with-transaction <body>) becomes: > > (let ((*success* nil) (*txn ... ) > (declare (special *success*) (special *txn... ) > (unwind-protect > (progn > <body> > (unless *success* (close-transaction))) ;; this makes sure we > don't commit twice > (unless *success* (abort-transaction... )) > > So when you want to do something to leave control from <body> without > reaching the end, you can call (elephant:close-transaction) or > whatever (maybe backend-close-transaction is a better name?) to > explicitly close that transaction. This also handles the problem that > somebody may want to raise an error or something but still want the > transaction to go through. > > I would implement the above myself, but I can't get Elephant from the > CVS circa right now to work. First thing is that in serializer.lisp, > in functions get-circularity-hash and release-circularity-hash, there > is the (#+allegro mp::with-process-lock (*circularity-lock*) > (pop/push...)), which SBCL doesn't like, so you have to do #+allegro > (mp::with-process lock... (pop/push...)) #-allegro (pop/push...). Then > in sleepycat.lisp, (def-function ("db_compact" ... should have > :returning :pointer-void (or maybe it is better for def-function > lambda-list to default &key returning to &key (returning > :pointer-void)?). After that everything seems to compile but nothing > seems to work. I'm not quite sure why, and I'm too tired to find out > right now. > > Vladimir > _______________________________________________ > 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