[elephant-devel] Sqlite-3 backend, threads and transactions

Robert L. Read read at robertlread.net
Wed Apr 19 22:32:34 UTC 2006


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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/elephant-devel/attachments/20060419/87854118/attachment.html>
-------------- next part --------------
;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;
;;; transactions.lisp -- Top level transaction support for elephant
;;; 
;;; Initial version 8/26/2004 by Ben Lee
;;; <blee at common-lisp.net>
;;; 
;;; part of
;;;
;;; Elephant: an object-oriented database for Common Lisp
;;;
;;; Copyright (c) 2004 by Andrew Blumberg and Ben Lee
;;; <ablumberg at common-lisp.net> <blee at common-lisp.net>
;;;
;;; 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 () , at 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*)))


More information about the elephant-devel mailing list