[Zope-DB] Zope database connectivity
Maciej Wisniowski
maciej.wisniowski at coig.katowice.pl
Thu Sep 28 14:38:43 EDT 2006
>If one is careful, one can find a reliable solution...
>
Hopefully I think I did this today...
I've found that psycopg pool implementation has nice
class:
class PersistentConnectionPool(AbstractConnectionPool):
"""A pool that assigns persistent connections to different threads.
Note that this connection pool generates by itself the required keys
using the current thread id. This means that untill a thread put away
a connection it will always get the same connection object by successive
.getconn() calls. This also means that a thread can't use more than one
single connection from the pool.
"""
I used this, and finally I have DCOracle2 with connection pool, without
volatile attributes (I didn't changed implementation of stored
procedures yet),
with ability to reconnect after things like DB restart and with REAL
ability to
open/close connections from ZMI.
I did one important change. Instead of having pool of connections I have
pool
of Resource Managers (or Transaction Managers - I'm not sure which name
is correct). These are descendants of Shared.DC.ZRDB.TM.TM and are usually
defined in db.py ad DA(Shared.DC.ZRDB.TM.TM). I'll call them RM.
Every RM in my pool is already connected to database - it has self.db.
With this implementation the typical request is:
0. pool of RM is created - usually it is during first call to 'getconn'
function
that pops connection from the pool.
1. ZSQLMethod (or other DA) calls database connection object
which is descendant of Shared.DC.ZRDB.Connection.Connection
2. Descendant of Shared.DC.ZRDB.Connection.Connection
in it's __call__ function gets free RM from the pool and
returns it to ZSQLMethod.
RM when taken from pool is marked as 'used' in the pool
and is assigned a key that is thread id. Every subsequent call
to 'getconn' checks if there already is 'used' RM under specific
key (thread id), and if so, returns this. During request we always
have same thread id so... it just works :)
3. ZSQLMethod executes 'query' on RM. RM registers itself
in Transaction
Steps 1-3 are repeated for each ZSQLMethod used during request.
Thanks to PersistentConnectionPool ZSQLs always get
same RM. As you probably noticed, RM taken from the pool
at the begining was not returned to the pool yet - it is still marked
as 'used' so no other thread is able to get it.
4. Request finishes so all registered RMs are commited (or aborted)
and their _finish method is called. A bit ugly thing happens here:
5. In _finish method RM puts itself :-/ back to the pool.
It is not possible (at last I have no idea how) to release RM in
different place because I don't know when request is finished.
But this implementation seems to work correcly.
One more thing I'm wondering about is getting RMs from
the pool (free or even used) because it is always done with code
like:
_connections_lock.acquire()
try:
....
finally:
_connections_lock.release()
may it be slow with high load? I mean that every time you need
the connection this code is used.
--
Maciej Wisniowski
More information about the Zope-DB
mailing list