On Tue, Dec 21, 2010 at 4:19 AM, Leslie P. Polzer <[email protected]> wrote:
> We've discussed this in the context of the upcoming Postmodern store
> and think it's the right thing to do (provided we abstract it properly
> so it works with multiple stores).
>
> But we need to test and think a bit more about it. It'd be great if
> you could try this approach in parallel for CLSQL.
Okay, I took a shot at it. I quickly discovered the complication
posed by multiple stores. But I think I found a reasonably elegant
solution. It cheats just a tiny bit, by calling the internal accessor
CLSQL-SYS::CONNECTION-SPEC, but that's all. It seems to work, though
all I've done with it so far is run the demo.
The patch is below. Basically there's a new generic function
THREAD-PREPARE-STORE by which each store gets to do setup and teardown
for each thread. PROCESS-CONNECTION (not ACCEPT-CONNECTIONS, as I
originally thought) is made to call this.
I added an (OPEN-STORES) call in START-WEBLOCKS, and a (CLOSE-STORES)
call in STOP-WEBLOCKS. The former is necessary, because the stores
have to be opened before the server threads get created in order for
THREAD-PREPARE-STORE to do its thing. The latter isn't strictly
necessary, but I noticed that STOP-WEBLOCKS wasn't closing stores as
its doc string promises.
To convince yourself it's working, trace CLSQL:CONNECT and
CLSQL:DISCONNECT. (You probably know, but I didn't: if you're using
slime-repl, trace output from background threads appears in
*inferior-lisp*.)
-- Scott
diff -r 5659d7f4ca80 src/acceptor.lisp
--- a/src/acceptor.lisp Wed Dec 15 12:56:55 2010 +0100
+++ b/src/acceptor.lisp Wed Dec 22 12:04:33 2010 -0800
@@ -20,3 +20,7 @@
(let ((*print-readably* nil))
(call-next-method)))
+(defmethod process-connection :around ((acceptor weblocks-acceptor) socket)
+ (with-stores-thread-prepared
+ (call-next-method)))
+
diff -r 5659d7f4ca80 src/server.lisp
--- a/src/server.lisp Wed Dec 15 12:56:55 2010 +0100
+++ b/src/server.lisp Wed Dec 22 12:04:33 2010 -0800
@@ -56,6 +56,7 @@
(if debug
(enable-global-debugging)
(disable-global-debugging))
+ (open-stores)
(when (null *weblocks-server*)
(values
(start (setf *weblocks-server*
@@ -75,6 +76,7 @@
(reset-sessions)
(when *weblocks-server*
(stop *weblocks-server*))
+ (close-stores)
(setf *weblocks-server* nil)))
diff -r 5659d7f4ca80 src/store/clsql/clsql.lisp
--- a/src/store/clsql/clsql.lisp Wed Dec 15 12:56:55 2010 +0100
+++ b/src/store/clsql/clsql.lisp Wed Dec 22 12:04:33 2010 -0800
@@ -10,13 +10,18 @@
(export '(order-by-expression range-to-offset range-to-limit))
+(defmethod thread-prepare-store ((store database) thunk)
+ (with-database (*default-database* (clsql-sys::connection-spec store)
+ :database-type (database-type store)
+ :pool t :if-exists :new)
+ (funcall thunk)))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Initialization/finalization ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmethod open-store ((store-type (eql :clsql)) &rest args)
(setf *default-caching* nil)
- (setf *default-store* (apply #'make-instance 'fluid-database
- :connection-spec args)))
+ (setf *default-store* (apply #'connect args)))
(defmethod close-store ((store database))
(when (eq *default-store* store)
diff -r 5659d7f4ca80 src/store/clsql/weblocks-clsql.asd
--- a/src/store/clsql/weblocks-clsql.asd Wed Dec 15 12:56:55 2010 +0100
+++ b/src/store/clsql/weblocks-clsql.asd Wed Dec 22 12:04:33 2010 -0800
@@ -11,6 +11,6 @@
:author "Slava Akhmechet"
:licence "LLGPL"
:description "A weblocks backend for clsql."
- :depends-on (:closer-mop :metatilities :clsql :clsql-fluid :weblocks)
+ :depends-on (:closer-mop :metatilities :clsql :weblocks)
:components ((:file "clsql")))
diff -r 5659d7f4ca80 src/store/store-api.lisp
--- a/src/store/store-api.lisp Wed Dec 15 12:56:55 2010 +0100
+++ b/src/store/store-api.lisp Wed Dec 22 12:04:33 2010 -0800
@@ -1,7 +1,7 @@
(in-package :weblocks)
-(export '(open-store close-store clean-store *default-store*
+(export '(open-store close-store clean-store thread-prepare-store
*default-store*
begin-transaction commit-transaction rollback-transaction
dynamic-transaction use-dynamic-transaction-p
persist-object delete-persistent-object
@@ -26,6 +26,10 @@
should erase data, but not necessarily any schema information (like
tables, etc.)"))
+(defgeneric thread-prepare-store (store thunk)
+ (:documentation "Some stores need per-thread setup/teardown. This
function does
+ the setup, calls THUNK (a function of no arguments), and does the
teardown."))
+
(defvar *default-store* nil
"The default store to which objects are persisted. Bound while a
webapp is handling a request to the value of its
diff -r 5659d7f4ca80 src/store/store-utils.lisp
--- a/src/store/store-utils.lisp Wed Dec 15 12:56:55 2010 +0100
+++ b/src/store/store-utils.lisp Wed Dec 22 12:04:33 2010 -0800
@@ -158,3 +158,21 @@
(dolist (obj objects)
(apply #'persist-object store obj keys)))
+;;; Default method.
+(defmethod thread-prepare-store ((store t) thunk)
+ (funcall thunk))
+
+(defun thread-prepare-stores (thunk)
+ (labels ((rec (store-names)
+ (if store-names
+ (if (symbol-value (car store-names))
+ (thread-prepare-store (symbol-value (car store-names))
+ #'(lambda ()
+ (rec (cdr store-names))))
+ (rec (cdr store-names)))
+ (funcall thunk))))
+ (rec *store-names*)))
+
+(defmacro with-stores-thread-prepared (&body body)
+ `(thread-prepare-stores #'(lambda () . ,body)))
+
--
You received this message because you are subscribed to the Google Groups
"weblocks" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/weblocks?hl=en.