dmiller wrote:
> On Feb 12, 2006, at 4:48 PM, Michael Bayer wrote:
>> Well, I was pursuing this differently.  While I am moving in the
>> same direction where UnitOfWork is not really dealt with
>> publically, I have the Session's main purpose as managing the
>> "scope" of a set of unit of works, such as thread-local, per-
>> application, or custom.
>
> May I respectfully disagree...I don't think the session should be
> managing scope. The session is the object that should be managed in a
> given "scope". If you really want to make the session manage the
> scope, then it should be a singleton (which is basically what the
> original objectstore was--a module, not a class). Otherwise we're
> talking about nested scopes, which gets very complicated to
> understand (and hard to debug). I don't think that is as useful as
> keeping it simple with a single UnitOfWork per session by default
> (well, not quite since the begin/commit thing will create additional
> "units of work").

fine with me....I knew pretty well when I did the original implementation,
which was just a single thread-local storage for a bunch of UnitOfWorks,
that the scoping issue was going to come up since that design was
intentionally simplistic....it wasnt occurring to me how else it might
want to be used so i didnt pursue.  The way i did it right now has the
disadvantage that theres a lot of thread-local lookups in a row for no
clear reason.   Also, that you tried to get your app to specify window IDs
and at the end of the day it was unworkable in practice makes a lot of
sense to me, so back to being simple is great.

Using inheritance as the primary means to extend the Session slightly
raises my gang-of-four sense (i.e.
http://www.c2.com/cgi/wiki?CompositionInsteadOfInheritance )  but its not
that big a deal to me, since I dont think people are going to need this
very much at all...plus Python encourages inheritance of standard objects
all over the place.

>> and have foo()'s transaction pulled upwards to the outermost
>> transaction.  you need a begin/commit counter to do that.
>
> Hmm. Is there a test for that? I don't think my patch is causing it
> to fail.

no theres no test for that as of yet....but its a pattern Ive used in lots
of other places.  it just means session.begin()/commit() will need a
counter inside of it to keep track of the outermost begin()/commit() pair.
 for a similar idea see the docs for threading.RLock
(http://www.python.org/doc/2.3.4/lib/rlock-objects.html) where they call
it a "recursion counter".    Previously, I had it so that new unitofwork
objects just get compounded on top of each other so that you could have
"nested transactions", but it became clear that wasnt the usual use
case....but its easy enough to make both behaviors available via an option
on the session.

so to sum up:

a thread-local ScopedRegistry gets placed at the module level in
objectstore, and stores a bunch of Session objects, one for each thread. 
Each Session contains one UnitOfWork and delgates operations to it.  
UnitOfWork is constructed with no awareness of the Session, and contains
just a commit method.  UnitOfWork can also take an IdentityMap as an
argument which allows related UnitOfWork objects to be constructed.

Session implements begin/commit and maintains a stack of UnitOfWork
objects for this purpose.  It may work in "recursion counter" mode or
possibly "nested transaction" mode.

Session also gets it own register_new()/register_clean() methods which
take incoming objects and calls bind_to with them, before delgating onto
the UOW, thus binding those instances to this Session.

objectstore implements get_session() which returns the current
thread-local Session object, or given an object instance returns the
Session that was bound to this object, if any, or just the thread-local
session otherwise.  the outside world is given get_session() as the
primary method of getting a unit of work context, and nobody really deals
with the UnitOfWork class directly.

objectstore/mapper also provide ways to specify a different Session for
the scope of a particular operation, by placing the new Session in the
ScopedRegistry for this thread, then popping it off after the operation is
complete.  mapper provides the "using()" method, objectstore provides
push_session/pop_session.  Objects that are created or loaded within such
a block get "bound to" that Session, so that subsequent operations
involving those instances will call up that Session object.  an object can
also be explitly created as bound to a Session anywhere by specifying the
keyword argument "_sa_session" to its constructor.  If the Session to
which an object is bound falls out of scope, it gets garbage collected and
operations upon those objects will raise an exception.

calling operations like session.clear() will cause Session to remove its
internal UnitOfWork instance and replace with a new one.  objects that
were bound to this session remain bound to it.

so let me know if this works for you...hopefully I can get this change in
tonight or tomorrow.

I am going to try really hard, once this change is in place, to put out a
release, just so that the trunk can handle more changes coming down
without throwing off everyone already using the library in projects, since
people are starting to grumble about that.   I was hoping to release
already but this will have to be fixed up first.

- mike




-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=103432&bid=230486&dat=121642
_______________________________________________
Sqlalchemy-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users

Reply via email to