[elephant-devel] Berkeley DB 4.4.20 Patch

Vladimir Sedach vsedach at gmail.com
Tue Sep 5 02:30:33 UTC 2006


> 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



More information about the elephant-devel mailing list