[ZODB-Dev] Re: session problems

Florent Guillaume fg at nuxeo.com
Mon Jan 9 10:26:16 EST 2006


FWIW: this code was checked in just in time for Zope 2.9.0.
A cleaner version is included in 2.9.1 and trunk:

     def _getMountedConnection(self, anyjar):
         # This creates the DB if it doesn't exist yet and adds it
         # to the multidatabase
         self._getDB()
         # Return a new or existing connection linked to the multidatabase set
         return anyjar.get_connection(self._getDBName())

along with a unit test.
But the code that's in 2.9.0 is just as effective.

Florent


Florent Guillaume wrote:
> Ok I've dug deeper and now understand the problem. The root cause is  in 
> the multi-databases support.
> 
> The problem is that the Zope startup only closes the main connection  it 
> had on the root database. The first connection to the  TemporaryStorage, 
> created and opened during Zope startup, is never  closed, so still is a 
> synchronizer in its original transaction, but  is nevertheless reused in 
> other transactins, without a proper  synchronizer set up.
> 
> When a MountedObject needs to be traversed, it tries to find an  
> existing connection for the new database by doing:
>     conn = anyjar.get_connection(db_name)
> where anyjar is the "parent" connection. If there's a linked  connection 
> for that database, it's returned, otherwise if the multi- database 
> already has seen the wanted database, it opens a connection  from it, 
> then adds it to the "linked" connections attribute  (conn.connections) 
> and shares this attribute between the two  connections.
> 
> I that fails, because the connection has never been linked to the new  
> database (which is the case during startup code), then the  
> MountedObject code does:
>     conn = self._getDB().open()
> Here _getDB() correctly returns a newly instanciated database, which  
> has been linked to the other ones in the multi-databases setup  (shared 
> "databases" dictionnary attribute, ultimately coming from  
> Zope2.Startup.datatypes.DBTab.databases).
> 
> Then open() returns a new opened connection for that database. *BUT*  
> this new connection is not "linked" to the others (using  their 
> .connections attribute). This code from get_connections is needed:
>             self.connections.update(new_con.connections)
>             new_con.connections = self.connections
> which would be written, in the context of code executing in  
> MountedObject (in _getMountedConnection):
>         except KeyError:
>             conn = self._getDB().open()
>             anyjar.connections.update(conn.connections)
>             conn.connections = anyjar.connections
>         return conn
> But of course really this code doesn't belong to MountedObject. This  is 
> just the simplest way I could find, if others want to test it.
> 
> 
> The ".connections" sharing is really funky, apparently all the  
> connections opened in the context of the same multi-databases support  
> are intended to be present in it. Why is this access not indirected  
> through the multi-databases support in DB itself? Also I don't  
> understand why open()'s "delegate" attribute is not stored as a  
> connection attribute, and close() should reuse it instead of obeying  a 
> "primary" attribute. Anyway, I guess historical code, etc.
> 
> I'll let specialistst of the multi-databases decide what to do :)
> 
> Florent
> 


-- 
Florent Guillaume, Nuxeo (Paris, France)   CTO, Director of R&D
+33 1 40 33 71 59   http://nuxeo.com   fg at nuxeo.com


More information about the ZODB-Dev mailing list