Zope transactions and connections was: Re: CT: Stumped was RE: [Zope] Asynchronous dtml?

Dieter Maurer dieter@handshake.de
Thu, 14 Jun 2001 21:29:07 +0200 (CEST)


albert boulanger writes:
 > Here is another example use for something like this. The Plumtree
 > Portal Server, to build the content of a mypage, will use multiple
 > threads to collect the content for the table cells of the mypage from
 > what they term gadget servers. It is important to collect this content
 > in parallel otherwise the time to build can be really bad especially
 > if multiple sources time out which can occur more often than one would
 > expect. If one were to build mypages for CMF for example and rely on
 > external content provision (say stock quotes, etc) for any of the
 > sources, one would need something like this.
Your use case should be okay:

    Threads become only problematic, if they access a
    database (including the ZODB) (or global data,
    but that is not Zope specific).

If they do access a database, they need to play well with
the transaction and persistence machinery of Zope:

    Zope associates a transaction with each thread.
    If you create a new thread, you will get a new transaction.
    The transaction is accessed with "get_transaction()".

    Zope registers objects with the transaction. These
    objects are examined when the transaction is commited
    or aborted in order to make potential changes persistent
    or discard them, respectively.

    ZODB objects are registered when they are changed,
    many other objects, e.g. DatabaseConnections, when
    they are accessed.

    Thus, if you change or access transaction aware objects, you may
    get a pending state, unless you call "get_transaction().commit()"
    or "get_transaction().abort()" at the end of your thread.


    Zope associates a ZODB connection with each HTTP request.
    This is done during traversal of the root object:
    ZODB.ZApplication.ZApplicationWrapper.__bobo_traverse__
    (db.open(version)).
    This connection is used to load objects on demand from
    the ZODB.
    It is propagated from an object to its persistent children
    during loading of the object.

    Thus, if you pass a Zope object to a new thread, the
    new thread uses the original thread's connection
    when it accesses (children) of the object or modifies the
    object itself.

    Apparently, the connection does not protect itself against
    concurrent use by different threads.
    This is quite understandable as such protection would
    cause a significant performance penalty.
    It is quite likely, that you get non-deterministic
    difficult to explain and analyse problems when you
    access the connection from different threads.
    I expect that even read access is dangerous.

    You can create a new connection in your thread
    and then access an object identified by an absolute
    URL "url" through

	import Zope
	root= Zope.app()
	object= root.unrestrictedTraverse(url)

    Note, however, that ZODB connections are pooled with
    a limited pool size (7 or 3 (for a version)). If
    you try to create more connections your thread blocks
    until there is an available connection.
    This may hit ZServer, too, when all available connections
    are used. Thus, your site may freeze, if you are not careful.


Dieter