On Thu, 2006-04-20 at 01:06 +0300, Ignas Mikalajunas wrote:
And indeed it is independent, but calls to ele:start-transaction, ele:commit-transaction and ele:abort-transaction are throwing an error for me and their code seems to be BDB specific. I would like to use with-transacton, yet it aborts the transaction on "any non-local exit", while i want to rollback only when some error occurs. TBNL redirect code does (throw 'tbnl:tbnl-handler-done), aborting transaction on each redirect. As in web applications (save-data-to-database) (redirect-to-avoid-double-post) is a very common pattern, i was getting my data reverted every time. So i am doing manual commits/rollbacks, depending on whether the request processing code raised an error or not.


Are you using the latest cvs version, or the latest released version from a tar file?
The cvs version has reworked a lot of this to make it more clearly independent.
If you check out the latest cvs version (instructions are on the Elephant project home page),
you will find in the src directory transactions.lisp, which provides a small API.  This would
be in spirit much, much better than calling anything on clsql directly.  The whole point of
Elephant, and particularly the last year of work, is to protect the user from details at the
implementation level.

Of course, I understand making it work overrides design philosophy; I hate to tell you to extensively
rewrite something, but I really must insist that directly accessing either CLSQL or BDB is not a
reasonable long term approach.  It should be better to use the latest transaction interface
(mostly reorganized by Ian Eslick, I think) that is independent of the back-end.  I've attached
the file from the latest version for you to look at.

I apologize that our latest version has been "just about ready" for so long; I hope we haven't wasted
your time by not releasing it faster.

I have not done that much work with the transaction handling, but am willing to debug any
reproducible problem that you find.

You have already posted a very nice, small, testcase for SBCL.  If we could figure out
how to make that testcase work (perhaps by changing Elephant internals when SQLite3 is in use),
would that allow you to go back to using the "pure" Elephant API?

If so, I'll work on that.

If not, I'll work on whatever the problem is, but I don't think I should work on any solution that
goes around the Elephant API (or is not using the latest version from CVS), even though I
appreciate you trying so hard to get it to work.
;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;
;;; transactions.lisp -- Top level transaction support for elephant
;;; 
;;; Initial version 8/26/2004 by Ben Lee
;;; <[EMAIL PROTECTED]>
;;; 
;;; part of
;;;
;;; Elephant: an object-oriented database for Common Lisp
;;;
;;; Copyright (c) 2004 by Andrew Blumberg and Ben Lee
;;; <[EMAIL PROTECTED]> <[EMAIL PROTECTED]>
;;;
;;; Elephant users are granted the rights to distribute and use this software
;;; as governed by the terms of the Lisp Lesser GNU Public License
;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
;;;

(in-package "ELEPHANT")

(defgeneric execute-transaction (store-controller txn-fn &rest rest &key 
&allow-other-keys)
  (:documentation 
   "This is an interface to the backend's transaction function.  The
    body should be executed in a dynamic environment that protects against
    non-local exist, provides ACID properties for DB operations within the
    body and properly bind any relevant parameters."))

;; Good defaults for bdb elephant
(defmacro with-transaction ((&key (store-controller '*store-controller*)
                                  transaction 
                                  environment 
                                  (parent '*current-transaction*)
                                  degree-2 dirty-read txn-nosync
                                  txn-nowait txn-sync
                                  (retries 100))
                             &body body)
  "Execute a body with a transaction in place.  On success,
   the transaction is committed.  Otherwise, the transaction is
   aborted.  If the body deadlocks, the body is re-executed in
   a new transaction, retrying a fixed number of iterations.
   *auto-commit* is false for the body of the transaction."
  `(funcall #'execute-transaction ,store-controller 
            (lambda () ,@body)
            :transaction ,transaction
            :environment ,environment
            :parent ,parent
            :retries ,retries
            :degree-2 ,degree-2
            :dirty-read ,dirty-read
            :txn-nosync ,txn-nosync
            :txn-nowait ,txn-nowait
            :txn-sync ,txn-sync))

;;
;; An interface to manage transactions explicitely
;;

;; Controller methods to implement

(defgeneric controller-start-transaction (store-controller &key 
&allow-other-keys)
  (:documentation "Start an elephant transaction"))

(defgeneric controller-commit-transaction (store-controller &key 
&allow-other-keys)
  (:documentation "Commit an elephant transaction"))

(defgeneric controller-abort-transaction (store-controller &key 
&allow-other-keys)
  (:documentation "Abort an elephant transaction"))


;; User Interface

(defun start-ele-transaction (&key (store-controller *store-controller*)
                              (parent *current-transaction*)
                              degree-2
                              dirty-read
                              txn-nosync
                              txn-nowait
                              txn-sync)
  "Start a transaction.  May be nested but not interleaved."
  (vector-push-extend *current-transaction* *transaction-stack*)
  (setq *current-transaction* 
        (controller-start-transaction store-controller 
                                      :parent parent
                                      :degree-2 degree-2
                                      :dirty-read dirty-read
                                      :txn-nosync txn-nosync
                                      :txn-nowait txn-nowait
                                      :txn-sync txn-sync)))

(defun commit-transaction (&key (store-controller *store-controller*) 
txn-nosync txn-sync &allow-other-keys)
  "Commit the current transaction."
  (controller-commit-transaction store-controller 
                                 :transaction *current-transaction*
                                 :txn-nosync txn-nosync 
                                 :txn-sync txn-sync)
  (setq *current-transaction* (vector-pop *transaction-stack*)))

(defun abort-transaction (&key (store-controller *store-controller*) 
&allow-other-keys)
  "Abort the current transaction."
  (controller-abort-transaction store-controller :transaction 
*current-transaction*)
  (setq *current-transaction* (vector-pop *transaction-stack*)))
_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel

Reply via email to