summaryrefslogtreecommitdiff
path: root/paste/webkit/FakeWebware/MiscUtils/DBPool.py
diff options
context:
space:
mode:
Diffstat (limited to 'paste/webkit/FakeWebware/MiscUtils/DBPool.py')
-rw-r--r--paste/webkit/FakeWebware/MiscUtils/DBPool.py128
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)
+