diff options
Diffstat (limited to 'paste/webkit/FakeWebware/MiscUtils/DBPool.py')
| -rw-r--r-- | paste/webkit/FakeWebware/MiscUtils/DBPool.py | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/paste/webkit/FakeWebware/MiscUtils/DBPool.py b/paste/webkit/FakeWebware/MiscUtils/DBPool.py new file mode 100644 index 0000000..522f268 --- /dev/null +++ b/paste/webkit/FakeWebware/MiscUtils/DBPool.py @@ -0,0 +1,128 @@ +""" +DBPool.py + +Implements a pool of cached connections to a database. This should result in +a speedup for persistent apps. The pool of connections is threadsafe +regardless of whether the DB API module question in general has a +threadsafety of 1 or 2. + +For more information on the DB API, see: + http://www.python.org/topics/database/DatabaseAPI-2.0.html + +The idea behind DBPool is that it's completely seamless, so once you have +established your connection, use it just as you would any other DB-API +compliant module. For example: + + dbPool = DBPool(MySQLdb, 5, host=xxx, user=xxx, ...) + db = dbPool.getConnection() + +Now use "db" exactly as if it were a MySQLdb connection. It's really +just a proxy class. + +db.close() will return the connection to the pool, not actually +close it. This is so your existing code works nicely. + + +FUTURE + +* If in the presence of WebKit, register ourselves as a Can. + + +CREDIT + +* Contributed by Dan Green +* thread safety bug found by Tom Schwaller +* Fixes by Geoff Talvola (thread safety in _threadsafe_getConnection()). +* Clean up by Chuck Esterbrook. +* Fix unthreadsafe functions which were leaking, Jay Love +* Eli Green's webware-discuss comments were lifted for additional docs. +""" + + +import threading + + +class DBPoolError(Exception): pass +class UnsupportedError(DBPoolError): pass + + +class PooledConnection: + """ A wrapper for database connections to help with DBPool. You don't normally deal with this class directly, but use DBPool to get new connections. """ + + def __init__(self, pool, con): + self._con = con + self._pool = pool + + def close(self): + if self._con is not None: + self._pool.returnConnection(self) + self._con = None + + def __getattr__(self, name): + return getattr(self._con, name) + + def __del__(self): + self.close() + + +class DBPool: + + def __init__(self, dbModule, maxConnections, *args, **kwargs): + if dbModule.threadsafety==0: + raise UnsupportedError, "Database module does not support any level of threading." + elif dbModule.threadsafety==1: + from Queue import Queue + self._queue = Queue(maxConnections) + self.addConnection = self._unthreadsafe_addConnection + self.getConnection = self._unthreadsafe_getConnection + self.returnConnection = self._unthreadsafe_returnConnection + elif dbModule.threadsafety>=2: + self._lock = threading.Lock() + self._nextCon = 0 + self._connections = [] + self.addConnection = self._threadsafe_addConnection + self.getConnection = self._threadsafe_getConnection + self.returnConnection = self._threadsafe_returnConnection + + # @@ 2000-12-04 ce: Should we really make all the connections now? + # Couldn't we do this on demand? + for i in range(maxConnections): + con = apply(dbModule.connect, args, kwargs) + self.addConnection(con) + + + # threadsafe/unthreadsafe refers to the database _module_, not THIS class.. + # this class is definitely threadsafe (um. that is, I hope so - Dan) + + def _threadsafe_addConnection(self, con): + self._connections.append(con) + + + def _threadsafe_getConnection(self): + self._lock.acquire() + try: + con = PooledConnection(self, self._connections[self._nextCon]) + self._nextCon = self._nextCon + 1 + if self._nextCon >= len(self._connections): + self._nextCon = 0 + return con + finally: + self._lock.release() + + def _threadsafe_returnConnection(self, con): + return + + # These functions are used with DB modules that have connection level threadsafety, like PostgreSQL. + # + def _unthreadsafe_addConnection(self, con): + self._queue.put(con) + + def _unthreadsafe_getConnection(self): + return PooledConnection(self, self._queue.get()) + + def _unthreadsafe_returnConnection(self, conpool): + """ + This should never be called explicitly outside of this module. + """ + self.addConnection(conpool._con) + |
