Hi Jim! Glad to here from you. I don't think I'm clearly sharing the problem I'm having. See my comments below. John Heintz Jim Fulton wrote:
"John D.Heintz" wrote:
Hi all,
I am about to embark on integrating ZODB with CORBA,
Woo hoo!
and am in the deep thinking phase of the endeavor. ;-)
What I want to do is _explicitly_ manage connections and transactions without being able to depend on what thread is running. I know that this is _not_ the way that Zope works,
That depends on your point of view. The Zope publisher (ORB) largely automates transaction management for application programmers, so they don't have to deal with identifying transaction boundaries. So, from an application point of voew, these details are hidden.
First issue I need to clarify: I am not integrating ZPublisher, just ZODB expose objects. I want to do this because we are using ZODB to persist complicated Python object (great database!) but are not publishing them to the web.
From a system point of view, Zope does manage per-thread transaction data. This is something a CORBA interface could provide as well.
CORBA provides two threading policies, and either could be used in a thread/Connection per request model. I am not intending on doing Connection per request, I would rather manage Connections as longer running activities so that I don't have to create servants more often than necessary.
IMPORTANT NOTE: The ZODB-provided transaction manager automatically manages per-thread transaction information.
Were you aware of this? This sounds like what you need.
Yes, I'm pretty aware of this. I have even studied the cPersistence.c code, specifically the changed() function that calls the global get_transaction() python function.
but if I want to use standard CORBA I think I have only two choices: 1) Explicitly associate Connections with Transactions in my CORBA layer. What I need to do is allow any thread to change a Persistent object from some Connection,
This would be nice. Basically, you want to open a ZODB database connection and begin a transaction at the beginning of the request. At the end of the request, you want to commit or abort the transaction, depending on whether an error occurred, and close the connection.
This is the Zope publisher model. I want to rather keep a persistent reference to objects in the Database (from a Connection) across CORBA Requests. This is the core reason that I am trying to manage Transactions/threads/Connections explicitly.
and make sure that the right transaction is called for "register".
If I understand your requirements, then the standard transaction machinery should do this for you.
Except that I'm not committing or aborting necessarily at the end of a CORBA Request. I plan on having users login to the server and get back a Session object that provides access to other objects in the system. That returned Session object will have a ZODB Connection and a Transaction cached. It also will expose through CORBA a commit() and abort() method that delegates to the ZODB Transaction. All this because I want to keep object from the ZODB Connection cache around for a while.
2) Build a complete wrapping adapter layer that does thread synchronization to the actual Persistent objects and proper thread for the transaction. - Lots of overhead and redundant coding - tricks with ExtensionClass might make this adaptation simpler to code, but still it won't be easy.
I'm not sure what this is, but I think it probably isn't necessary.
This layer would exist to ensure that, across CORBA Requests, the correct thread would be running. The correct thread is the one that was created in the CORBA Session object that open()ed the ZODB Connection.
Obviously number one is my preferred choice. In order to accomplish that, I see only two ways: 1) Modify ZODB to maintain a Connection to Transaction link, and modify cPersistence.c to use that link in the changed() function instead of relying on the standard get_transaction() thread index.
Is there a one-to-one relation between threads and connections (or, more precisely, is it the case that there is never more than one simultaneous connection per thread)? If so, then get_transaction() should do the right thing.
There would not be any predictable mapping from threads to connections for any two CORBA Requests if I don't throw away the connections after a commit() or abort().
2) Replace the get_transaction() in globals to return the appropriate Transaction regardless of thread.
It currently returns a different transaction depending on the thread.
In the CORBA exposure I would never call get_transaction(). I would use the reference to a transaction from the CORBA Session object that originally open()ed a database connection.
Again, my preference is number one. After going over the ZODB code, I _think_ that a Connection is always associated with one Transaction. If this assumption is true, then it should be safe to make the change I'm proposing. If not, then I need to understand why so that I can rethink how to solve my problem. ;-)
I hope that I've made my problems and ideas for solutions clear, if not please let me know.
I dunno. You'll probably be able to tell from my response. :)
Only the difference between thread/Connection/transaction per request versus exposing the same cached object across multiple CORBA requests.
Also, I think that I should be able to make the changes to ZODB myself within the next few week, but only if there is the _possibility_ of folding them back into the main Zope codebase.
I sincerely hope that no ZODB changes are necessary.
This is, in Python, the changes to Persistent that I feel would solve my problem. I think that in general this code would allow multiple thread to modify ZODB objects while still keeping the right transaction up to date. import ZODB from Persistence import Persistent class TestPersistent(Persistent): self __changed__(self): "Completely ignoring self->state from c code..." if self._p_jar: self._p_jar.transaction.register(self) and then in DB.py the open() method must add a transaction attribute to the connection before returning. I've got one more question. What happens if I: - make a connection to a database - navigate to some objects and store references to them - make some changes to these objects - call get_transaction().abort() - make some changes to the same objects (that I have references to) - call get_transaction().commit() Will everything do what I expect in this case? Thanks so much for you time, John Heintz
Thanks for any help, John D. Heintz
CORBA Threading description: CORBA defines the POA, which has two standard threading policies: ORB Controlled Model Single Threaded Model
The POA is basically a controller for requests to one or more distributed objects, with thread policy as one of its parameters.
The first threading policy means whatever the ORB gives you - single or multi, and you have to deal with all synchronizations.
The second I consider a mis-nomer because there can be many threads, but only one at a time will access objects for a given POA. (This is the model that I perceive being used by default for ZODB object from a specific Connection.)
No. Multiple threads can be accessing the same logical object. Each thread has it's own copy (and DB connection and transaction).
Jim
-- Jim Fulton mailto:jim@digicool.com Python Powered! Technical Director (888) 344-4332 http://www.python.org Digital Creations http://www.digicool.com http://www.zope.org
Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email address may not be added to any commercial mail list with out my permission. Violation of my privacy with advertising or SPAM will result in a suit for a MINIMUM of $500 damages/incident, $1500 for repeats.
-- John D. Heintz DataChannel, Inc. Senior Engineer 512-633-1198 jheintz@isogen.com