From: Mike Bayer Date: Tue, 14 Sep 2010 21:37:27 +0000 (-0400) Subject: - merge tip, 0.6.4 + 0.6.5 X-Git-Tag: rel_0_7b1~253^2~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=60b82d6e13246a3d88e7288e863a5231b7572c6a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - merge tip, 0.6.4 + 0.6.5 --- 60b82d6e13246a3d88e7288e863a5231b7572c6a diff --cc doc/build/core/event.rst index ec36ee5990,0000000000..ec36ee5990 mode 100644,000000..100644 --- a/doc/build/core/event.rst +++ b/doc/build/core/event.rst diff --cc doc/build/core/interfaces.rst index 0000000000,71dd8c1220..c6254491a0 mode 000000,100644..100644 --- a/doc/build/core/interfaces.rst +++ b/doc/build/core/interfaces.rst @@@ -1,0 -1,30 +1,30 @@@ -.. _interfaces_core_toplevel: ++. _interfaces_core_toplevel: + + Core Event Interfaces + ====================== + + .. module:: sqlalchemy.interfaces + + This section describes the various categories of events which can be intercepted + in SQLAlchemy core, including execution and connection pool events. + + For ORM event documentation, see :ref:`interfaces_orm_toplevel`. + + A new version of this API with a significantly more flexible and consistent + interface will be available in version 0.7. + + Execution, Connection and Cursor Events + --------------------------------------- + + .. autoclass:: ConnectionProxy + :members: + :undoc-members: + + Connection Pool Events + ---------------------- + + .. autoclass:: PoolListener + :members: + :undoc-members: + + diff --cc doc/build/core/pooling.rst index 0000000000,edb6a334e3..692a33f009 mode 000000,100644..100644 --- a/doc/build/core/pooling.rst +++ b/doc/build/core/pooling.rst @@@ -1,0 -1,226 +1,226 @@@ + .. _pooling_toplevel: + + Connection Pooling + ================== + + .. module:: sqlalchemy.pool + + The establishment of a + database connection is typically a somewhat expensive operation, and + applications need a way to get at database connections repeatedly + with minimal overhead. Particularly for + server-side web applications, a connection pool is the standard way to + maintain a "pool" of active database connections in memory which are + reused across requests. + + SQLAlchemy includes several connection pool implementations + which integrate with the :class:`.Engine`. They can also be used + directly for applications that want to add pooling to an otherwise + plain DBAPI approach. + + Connection Pool Configuration + ----------------------------- + + The :class:`~sqlalchemy.engine.Engine` returned by the + :func:`~sqlalchemy.create_engine` function in most cases has a :class:`QueuePool` + integrated, pre-configured with reasonable pooling defaults. If + you're reading this section to simply enable pooling- congratulations! + You're already done. + + The most common :class:`QueuePool` tuning parameters can be passed + directly to :func:`~sqlalchemy.create_engine` as keyword arguments: + ``pool_size``, ``max_overflow``, ``pool_recycle`` and + ``pool_timeout``. For example:: + + engine = create_engine('postgresql://me@localhost/mydb', + pool_size=20, max_overflow=0) + + In the case of SQLite, a :class:`SingletonThreadPool` is provided instead, + to provide compatibility with SQLite's restricted threading model, as well + as to provide a reasonable default behavior to SQLite "memory" databases, + which maintain their entire dataset within the scope of a single connection. + + All SQLAlchemy pool implementations have in common + that none of them "pre create" connections - all implementations wait + until first use before creating a connection. At that point, if + no additional concurrent checkout requests for more connections + are made, no additional connections are created. This is why it's perfectly + fine for :func:`.create_engine` to default to using a :class:`.QueuePool` + of size five without regard to whether or not the application really needs five connections + queued up - the pool would only grow to that size if the application + actually used five connections concurrently, in which case the usage of a + small pool is an entirely appropriate default behavior. + + Switching Pool Implementations + ------------------------------ + + The usual way to use a different kind of pool with :func:`.create_engine` + is to use the ``poolclass`` argument. This argument accepts a class + imported from the ``sqlalchemy.pool`` module, and handles the details + of building the pool for you. Common options include specifying + :class:`.QueuePool` with SQLite:: + + from sqlalchemy.pool import QueuePool + engine = create_engine('sqlite:///file.db', poolclass=QueuePool) + + Disabling pooling using :class:`.NullPool`:: + + from sqlalchemy.pool import NullPool + engine = create_engine( + 'postgresql+psycopg2://scott:tiger@localhost/test', + poolclass=NullPool) + + Using a Custom Connection Function + ---------------------------------- + + All :class:`.Pool` classes accept an argument ``creator`` which is + a callable that creates a new connection. :func:`.create_engine` + accepts this function to pass onto the pool via an argument of + the same name:: + + import sqlalchemy.pool as pool + import psycopg2 + + def getconn(): + c = psycopg2.connect(username='ed', host='127.0.0.1', dbname='test') + # do things with 'c' to set up + return c + + engine = create_engine('postgresql+psycopg2://', creator=getconn) + + For most "initialize on connection" routines, it's more convenient + to use a :class:`.PoolListener`, so that the usual URL argument to + :func:`.create_engine` is still usable. ``creator`` is there as + a total last resort for when a DBAPI has some form of ``connect`` + that is not at all supported by SQLAlchemy. + + Constructing a Pool + ------------------------ + + To use a :class:`.Pool` by itself, the ``creator`` function is + the only argument that's required and is passed first, followed + by any additional options:: + + import sqlalchemy.pool as pool + import psycopg2 + + def getconn(): + c = psycopg2.connect(username='ed', host='127.0.0.1', dbname='test') + return c + + mypool = pool.QueuePool(getconn, max_overflow=10, pool_size=5) + + DBAPI connections can then be procured from the pool using the :meth:`.Pool.connect` + function. The return value of this method is a DBAPI connection that's contained + within a transparent proxy:: + + # get a connection + conn = mypool.connect() + + # use it + cursor = conn.cursor() + cursor.execute("select foo") + + The purpose of the transparent proxy is to intercept the ``close()`` call, + such that instead of the DBAPI connection being closed, its returned to the + pool:: + + # "close" the connection. Returns + # it to the pool. + conn.close() + + The proxy also returns its contained DBAPI connection to the pool + when it is garbage collected, + though it's not deterministic in Python that this occurs immediately (though + it is typical with cPython). + + A particular pre-created :class:`.Pool` can be shared with one or more + engines by passing it to the ``pool`` argument of :func:`.create_engine`:: + + e = create_engine('postgresql://', pool=mypool) + + Pool Event Listeners + -------------------- + + Connection pools support an event interface that allows hooks to execute + upon first connect, upon each new connection, and upon checkout and + checkin of connections. See :class:`.PoolListener` for details. + + Builtin Pool Implementations + ---------------------------- + + .. autoclass:: sqlalchemy.pool.Pool + + .. automethod:: __init__ + .. automethod:: connect + .. automethod:: dispose + .. automethod:: recreate + + .. autoclass:: sqlalchemy.pool.QueuePool + :show-inheritance: + + .. automethod:: __init__ + + .. autoclass:: SingletonThreadPool + :show-inheritance: + + .. automethod:: __init__ + + .. autoclass:: AssertionPool + :show-inheritance: + + .. autoclass:: NullPool - :show-inheritance: ++ :show-inheritance: + + .. autoclass:: StaticPool + :show-inheritance: + + + Pooling Plain DB-API Connections + -------------------------------- + + Any :pep:`249` DB-API module can be "proxied" through the connection + pool transparently. Usage of the DB-API is exactly as before, except + the ``connect()`` method will consult the pool. Below we illustrate + this with ``psycopg2``:: + + import sqlalchemy.pool as pool + import psycopg2 as psycopg + + psycopg = pool.manage(psycopg) + + # then connect normally + connection = psycopg.connect(database='test', username='scott', + password='tiger') + + This produces a :class:`_DBProxy` object which supports the same + ``connect()`` function as the original DB-API module. Upon + connection, a connection proxy object is returned, which delegates its + calls to a real DB-API connection object. This connection object is + stored persistently within a connection pool (an instance of + :class:`Pool`) that corresponds to the exact connection arguments sent + to the ``connect()`` function. + + The connection proxy supports all of the methods on the original + connection object, most of which are proxied via ``__getattr__()``. + The ``close()`` method will return the connection to the pool, and the + ``cursor()`` method will return a proxied cursor object. Both the + connection proxy and the cursor proxy will also return the underlying + connection to the pool after they have both been garbage collected, + which is detected via weakref callbacks (``__del__`` is not used). + + Additionally, when connections are returned to the pool, a + ``rollback()`` is issued on the connection unconditionally. This is + to release any locks still held by the connection that may have + resulted from normal activity. + + By default, the ``connect()`` method will return the same connection + that is already checked out in the current thread. This allows a + particular connection to be used in a given thread without needing to + pass it around between functions. To disable this behavior, specify + ``use_threadlocal=False`` to the ``manage()`` function. + + .. autofunction:: sqlalchemy.pool.manage + + .. autofunction:: sqlalchemy.pool.clear_managers + diff --cc lib/sqlalchemy/orm/attributes.py index ddfdb8655a,b56de5f05d..7cc8d2161b --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@@ -512,10 -455,10 +519,10 @@@ class ScalarAttributeImpl(AttributeImpl self, state, dict_.get(self.key, NO_VALUE)) def set(self, state, dict_, value, initiator, passive=PASSIVE_OFF): - if initiator is self: + if initiator and initiator.parent_token is self.parent_token: return - if self.active_history: + if self.dispatch.active_history: old = self.get(state, dict_) else: old = dict_.get(self.key, NO_VALUE) @@@ -591,10 -534,10 +598,10 @@@ class MutableScalarAttributeImpl(Scalar state.mutable_dict.pop(self.key) def set(self, state, dict_, value, initiator, passive=PASSIVE_OFF): - if initiator is self: + if initiator and initiator.parent_token is self.parent_token: return - if self.extensions: + if self.dispatch.on_set: old = self.get(state, dict_) value = self.fire_replace_event(state, dict_, value, old, initiator) @@@ -653,14 -596,14 +660,14 @@@ class ScalarObjectAttributeImpl(ScalarA setter operation. """ - if initiator is self: + if initiator and initiator.parent_token is self.parent_token: return - if self.active_history: + if self.dispatch.active_history: - old = self.get(state, dict_) + old = self.get(state, dict_, passive=PASSIVE_ONLY_PERSISTENT) else: old = self.get(state, dict_, passive=PASSIVE_NO_FETCH) - + value = self.fire_replace_event(state, dict_, value, old, initiator) dict_[self.key] = value diff --cc lib/sqlalchemy/pool.py index 5d14c17898,c70a41069f..9ed5c80670 --- a/lib/sqlalchemy/pool.py +++ b/lib/sqlalchemy/pool.py @@@ -209,20 -131,15 +209,28 @@@ class Pool(log.Identified) for l in listeners: self.add_listener(l) + dispatch = event.dispatcher(PoolEvents) + + @util.deprecated(2.7, "Pool.add_listener is deprecated. Use event.listen()") + def add_listener(self, listener): + """Add a :class:`.PoolListener`-like object to this pool. + + ``listener`` may be an object that implements some or all of + PoolListener, or a dictionary of callables containing implementations + of some or all of the named methods in PoolListener. + + """ + interfaces.PoolListener._adapt_listener(self, listener) + def unique_connection(self): + """Produce a DBAPI connection that is not referenced by any + thread-local context. + + This method is different from :meth:`.Pool.connect` only if the + ``use_threadlocal`` flag has been set to ``True``. + + """ + return _ConnectionFairy(self).checkout() def create_connection(self):