summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/pool.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-01-12 17:34:20 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2014-01-12 17:34:20 -0500
commitc91fd822bc9816827d0aab4699e304ab49ed8280 (patch)
tree291326b1bf9b1b489b9dac24632e668610d4504f /lib/sqlalchemy/pool.py
parent86c3855c9bafb52cb71df7e958196d27ca4dc578 (diff)
downloadsqlalchemy-c91fd822bc9816827d0aab4699e304ab49ed8280.tar.gz
- add new event PoolEvents.invalidate(). allows interception of invalidation
events including auto-invalidation, which is useful both for tests here as well as detecting failure conditions within the "reset" or "close" cases. - rename the argument for PoolEvents.reset() to dbapi_connection and connection_record to be consistent with everything else. - add new documentation sections on invalidation, including auto-invalidation and the invalidation process within the pool. - add _ConnectionFairy and _ConnectionRecord to the pool documentation. Establish docs for common _ConnectionFairy/_ConnectionRecord methods and accessors and have PoolEvents docs refer to _ConnectionRecord, since it is passed to all events. Rename a few _ConnectionFairy methods that are actually private to pool such as _checkout(), _checkin() and _checkout_existing(); there should not be any external code calling these
Diffstat (limited to 'lib/sqlalchemy/pool.py')
-rw-r--r--lib/sqlalchemy/pool.py135
1 files changed, 118 insertions, 17 deletions
diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py
index 3adfb320b..0f0a2ac10 100644
--- a/lib/sqlalchemy/pool.py
+++ b/lib/sqlalchemy/pool.py
@@ -216,7 +216,7 @@ class Pool(log.Identified):
"""
- return _ConnectionFairy.checkout(self)
+ return _ConnectionFairy._checkout(self)
def _create_connection(self):
"""Called by subclasses to create a new ConnectionRecord."""
@@ -268,7 +268,7 @@ class Pool(log.Identified):
"""
if not self._use_threadlocal:
- return _ConnectionFairy.checkout(self)
+ return _ConnectionFairy._checkout(self)
try:
rec = self._threadconns.current()
@@ -276,9 +276,9 @@ class Pool(log.Identified):
pass
else:
if rec is not None:
- return rec.checkout_existing()
+ return rec._checkout_existing()
- return _ConnectionFairy.checkout(self, self._threadconns)
+ return _ConnectionFairy._checkout(self, self._threadconns)
def _return_conn(self, record):
"""Given a _ConnectionRecord, return it to the :class:`.Pool`.
@@ -309,6 +309,34 @@ class Pool(log.Identified):
class _ConnectionRecord(object):
+ """Internal object which maintains an individual DBAPI connection
+ referenced by a :class:`.Pool`.
+
+ The :class:`._ConnectionRecord` object always exists for any particular
+ DBAPI connection whether or not that DBAPI connection has been
+ "checked out". This is in contrast to the :class:`._ConnectionFairy`
+ which is only a public facade to the DBAPI connection while it is checked
+ out.
+
+ A :class:`._ConnectionRecord` may exist for a span longer than that
+ of a single DBAPI connection. For example, if the
+ :meth:`._ConnectionRecord.invalidate`
+ method is called, the DBAPI connection associated with this
+ :class:`._ConnectionRecord`
+ will be discarded, but the :class:`._ConnectionRecord` may be used again,
+ in which case a new DBAPI connection is produced when the :class:`.Pool`
+ next uses this record.
+
+ The :class:`._ConnectionRecord` is delivered along with connection
+ pool events, including :meth:`.PoolEvents.connect` and
+ :meth:`.PoolEvents.checkout`, however :class:`._ConnectionRecord` still
+ remains an internal object whose API and internals may change.
+
+ .. seealso::
+
+ :class:`._ConnectionFairy`
+
+ """
def __init__(self, pool):
self.__pool = pool
@@ -320,8 +348,23 @@ class _ConnectionRecord(object):
exec_once(self.connection, self)
pool.dispatch.connect(self.connection, self)
+ connection = None
+ """A reference to the actual DBAPI connection being tracked.
+
+ May be ``None`` if this :class:`._ConnectionRecord` has been marked
+ as invalidated; a new DBAPI connection may replace it if the owning
+ pool calls upon this :class:`._ConnectionRecord` to reconnect.
+
+ """
+
@util.memoized_property
def info(self):
+ """The ``.info`` dictionary associated with the DBAPI connection.
+
+ This dictionary is shared among the :attr:`._ConnectionFairy.info`
+ and :attr:`.Connection.info` accessors.
+
+ """
return {}
@classmethod
@@ -360,9 +403,22 @@ class _ConnectionRecord(object):
def close(self):
if self.connection is not None:
- self.__pool._close_connection(self.connection)
+ self.__close()
def invalidate(self, e=None):
+ """Invalidate the DBAPI connection held by this :class:`._ConnectionRecord`.
+
+ This method is called for all connection invalidations, including
+ when the :meth:`._ConnectionFairy.invalidate` or :meth:`.Connection.invalidate`
+ methods are called, as well as when any so-called "automatic invalidation"
+ condition occurs.
+
+ .. seealso::
+
+ :ref:`pool_connection_invalidation`
+
+ """
+ self.__pool.dispatch.invalidate(self.connection, self, e)
if e is not None:
self.__pool.logger.info(
"Invalidate connection %r (reason: %s:%s)",
@@ -453,15 +509,41 @@ _refs = set()
class _ConnectionFairy(object):
- """Proxies a DB-API connection and provides return-on-dereference
- support."""
+ """Proxies a DBAPI connection and provides return-on-dereference
+ support.
+
+ This is an internal object used by the :class:`.Pool` implementation
+ to provide context management to a DBAPI connection delivered by
+ that :class:`.Pool`.
+
+ The name "fairy" is inspired by the fact that the :class:`._ConnectionFairy`
+ object's lifespan is transitory, as it lasts only for the length of a
+ specific DBAPI connection being checked out from the pool, and additionally
+ that as a transparent proxy, it is mostly invisible.
+
+ .. seealso::
+
+ :class:`._ConnectionRecord`
+
+ """
def __init__(self, dbapi_connection, connection_record):
self.connection = dbapi_connection
self._connection_record = connection_record
+ connection = None
+ """A reference to the actual DBAPI connection being tracked."""
+
+ _connection_record = None
+ """A reference to the :class:`._ConnectionRecord` object associated
+ with the DBAPI connection.
+
+ This is currently an internal accessor which is subject to change.
+
+ """
+
@classmethod
- def checkout(cls, pool, threadconns=None, fairy=None):
+ def _checkout(cls, pool, threadconns=None, fairy=None):
if not fairy:
fairy = _ConnectionRecord.checkout(pool)
@@ -498,16 +580,16 @@ class _ConnectionFairy(object):
fairy.invalidate()
raise exc.InvalidRequestError("This connection is closed")
- def checkout_existing(self):
- return _ConnectionFairy.checkout(self._pool, fairy=self)
+ def _checkout_existing(self):
+ return _ConnectionFairy._checkout(self._pool, fairy=self)
- def checkin(self):
+ def _checkin(self):
_finalize_fairy(self.connection, self._connection_record,
self._pool, None, self._echo, fairy=self)
self.connection = None
self._connection_record = None
- _close = checkin
+ _close = _checkin
@property
def _logger(self):
@@ -515,6 +597,9 @@ class _ConnectionFairy(object):
@property
def is_valid(self):
+ """Return True if this :class:`._ConnectionFairy` still refers
+ to an active DBAPI connection."""
+
return self.connection is not None
@util.memoized_property
@@ -525,7 +610,9 @@ class _ConnectionFairy(object):
The data here will follow along with the DBAPI connection including
after it is returned to the connection pool and used again
- in subsequent instances of :class:`.ConnectionFairy`.
+ in subsequent instances of :class:`._ConnectionFairy`. It is shared
+ with the :attr:`._ConnectionRecord.info` and :attr:`.Connection.info`
+ accessors.
"""
return self._connection_record.info
@@ -533,8 +620,16 @@ class _ConnectionFairy(object):
def invalidate(self, e=None):
"""Mark this connection as invalidated.
- The connection will be immediately closed. The containing
- ConnectionRecord will create a new connection when next used.
+ This method can be called directly, and is also called as a result
+ of the :meth:`.Connection.invalidate` method. When invoked,
+ the DBAPI connection is immediately closed and discarded from
+ further use by the pool. The invalidation mechanism proceeds
+ via the :meth:`._ConnectionRecord.invalidate` internal method.
+
+ .. seealso::
+
+ :ref:`pool_connection_invalidation`
+
"""
if self.connection is None:
@@ -542,9 +637,15 @@ class _ConnectionFairy(object):
if self._connection_record:
self._connection_record.invalidate(e=e)
self.connection = None
- self.checkin()
+ self._checkin()
def cursor(self, *args, **kwargs):
+ """Return a new DBAPI cursor for the underlying connection.
+
+ This method is a proxy for the ``connection.cursor()`` DBAPI
+ method.
+
+ """
return self.connection.cursor(*args, **kwargs)
def __getattr__(self, key):
@@ -576,7 +677,7 @@ class _ConnectionFairy(object):
def close(self):
self._counter -= 1
if self._counter == 0:
- self.checkin()
+ self._checkin()