summaryrefslogtreecommitdiff
path: root/oslo
diff options
context:
space:
mode:
Diffstat (limited to 'oslo')
-rw-r--r--oslo/db/api.py4
-rw-r--r--oslo/db/sqlalchemy/compat/__init__.py4
-rw-r--r--oslo/db/sqlalchemy/compat/engine_connect.py60
-rw-r--r--oslo/db/sqlalchemy/compat/utils.py1
-rw-r--r--oslo/db/sqlalchemy/models.py5
-rw-r--r--oslo/db/sqlalchemy/session.py21
-rw-r--r--oslo/db/sqlalchemy/test_base.py3
7 files changed, 85 insertions, 13 deletions
diff --git a/oslo/db/api.py b/oslo/db/api.py
index 5527e64..8b7bdeb 100644
--- a/oslo/db/api.py
+++ b/oslo/db/api.py
@@ -23,12 +23,12 @@ takes no arguments. The method can return any object that implements DB
API methods.
"""
-import functools
import logging
import threading
import time
from oslo.utils import importutils
+import six
from oslo.db._i18n import _LE
from oslo.db import exception
@@ -93,7 +93,7 @@ class wrap_db_retry(object):
self.max_retry_interval = max_retry_interval
def __call__(self, f):
- @functools.wraps(f)
+ @six.wraps(f)
def wrapper(*args, **kwargs):
next_interval = self.retry_interval
remaining = self.max_retries
diff --git a/oslo/db/sqlalchemy/compat/__init__.py b/oslo/db/sqlalchemy/compat/__init__.py
index 1510dd0..aaaf200 100644
--- a/oslo/db/sqlalchemy/compat/__init__.py
+++ b/oslo/db/sqlalchemy/compat/__init__.py
@@ -16,11 +16,13 @@ added at some point but for which oslo.db provides a compatible versions
for previous SQLAlchemy versions.
"""
+from oslo.db.sqlalchemy.compat import engine_connect as _e_conn
from oslo.db.sqlalchemy.compat import handle_error as _h_err
# trying to get: "from oslo.db.sqlalchemy import compat; compat.handle_error"
# flake8 won't let me import handle_error directly
+engine_connect = _e_conn.engine_connect
handle_error = _h_err.handle_error
ExceptionContextImpl = _h_err.ExceptionContextImpl
-__all__ = ['handle_error', 'ExceptionContextImpl']
+__all__ = ['engine_connect', 'handle_error', 'ExceptionContextImpl']
diff --git a/oslo/db/sqlalchemy/compat/engine_connect.py b/oslo/db/sqlalchemy/compat/engine_connect.py
new file mode 100644
index 0000000..d64d462
--- /dev/null
+++ b/oslo/db/sqlalchemy/compat/engine_connect.py
@@ -0,0 +1,60 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""Provide forwards compatibility for the engine_connect event.
+
+See the "engine_connect" event at
+http://docs.sqlalchemy.org/en/rel_0_9/core/events.html.
+
+
+"""
+
+from sqlalchemy.engine import Engine
+from sqlalchemy import event
+
+from oslo.db.sqlalchemy.compat import utils
+
+
+def engine_connect(engine, listener):
+ """Add an engine_connect listener for the given :class:`.Engine`.
+
+ This listener uses the SQLAlchemy
+ :meth:`sqlalchemy.event.ConnectionEvents.engine_connect`
+ event for 0.9.0 and above, and implements an interim listener
+ for 0.8 versions.
+
+ """
+ if utils.sqla_090:
+ event.listen(engine, "engine_connect", listener)
+ return
+
+ assert isinstance(engine, Engine), \
+ "engine argument must be an Engine instance, not a Connection"
+
+ if not getattr(engine._connection_cls,
+ '_oslo_engine_connect_wrapper', False):
+ engine._oslo_engine_connect_events = []
+
+ class Connection(engine._connection_cls):
+ _oslo_engine_connect_wrapper = True
+
+ def __init__(self, *arg, **kw):
+ super(Connection, self).__init__(*arg, **kw)
+
+ _oslo_engine_connect_events = getattr(
+ self.engine,
+ '_oslo_engine_connect_events',
+ False)
+ if _oslo_engine_connect_events:
+ for fn in _oslo_engine_connect_events:
+ fn(self, kw.get('_branch', False))
+ engine._connection_cls = Connection
+ engine._oslo_engine_connect_events.append(listener)
diff --git a/oslo/db/sqlalchemy/compat/utils.py b/oslo/db/sqlalchemy/compat/utils.py
index a1c6d83..7ba83c3 100644
--- a/oslo/db/sqlalchemy/compat/utils.py
+++ b/oslo/db/sqlalchemy/compat/utils.py
@@ -21,4 +21,5 @@ _SQLA_VERSION = tuple(
sqla_097 = _SQLA_VERSION >= (0, 9, 7)
sqla_094 = _SQLA_VERSION >= (0, 9, 4)
+sqla_090 = _SQLA_VERSION >= (0, 9, 0)
sqla_08 = _SQLA_VERSION >= (0, 8)
diff --git a/oslo/db/sqlalchemy/models.py b/oslo/db/sqlalchemy/models.py
index ae01bb3..818c1b4 100644
--- a/oslo/db/sqlalchemy/models.py
+++ b/oslo/db/sqlalchemy/models.py
@@ -97,7 +97,7 @@ class ModelBase(six.Iterator):
return six.iteritems(local)
-class ModelIterator(ModelBase):
+class ModelIterator(ModelBase, six.Iterator):
def __init__(self, model, columns):
self.model = model
@@ -111,9 +111,6 @@ class ModelIterator(ModelBase):
n = six.advance_iterator(self.i)
return n, getattr(self.model, n)
- def next(self):
- return self.__next__()
-
class TimestampMixin(object):
created_at = Column(DateTime, default=lambda: timeutils.utcnow())
diff --git a/oslo/db/sqlalchemy/session.py b/oslo/db/sqlalchemy/session.py
index 192ad1d..882a9ea 100644
--- a/oslo/db/sqlalchemy/session.py
+++ b/oslo/db/sqlalchemy/session.py
@@ -293,6 +293,7 @@ from sqlalchemy.sql.expression import select
from oslo.db._i18n import _LW
from oslo.db import exception
from oslo.db import options
+from oslo.db.sqlalchemy import compat
from oslo.db.sqlalchemy import exc_filters
from oslo.db.sqlalchemy import utils
@@ -311,12 +312,22 @@ def _thread_yield(dbapi_con, con_record):
time.sleep(0)
-def _begin_ping_listener(connection):
- """Ping the server at transaction begin.
+def _connect_ping_listener(connection, branch):
+ """Ping the server at connection startup.
Ping the server at transaction begin and transparently reconnect
if a disconnect exception occurs.
"""
+ if branch:
+ return
+
+ # turn off "close with result". This can also be accomplished
+ # by branching the connection, however just setting the flag is
+ # more performant and also doesn't get involved with some
+ # connection-invalidation awkardness that occurs (see
+ # https://bitbucket.org/zzzeek/sqlalchemy/issue/3215/)
+ save_should_close_with_result = connection.should_close_with_result
+ connection.should_close_with_result = False
try:
# run a SELECT 1. use a core select() so that
# any details like that needed by Oracle, DB2 etc. are handled.
@@ -329,6 +340,8 @@ def _begin_ping_listener(connection):
# new connections assuming they are good now.
# run the select again to re-validate the Connection.
connection.scalar(select([1]))
+ finally:
+ connection.should_close_with_result = save_should_close_with_result
def _setup_logging(connection_debug=0):
@@ -389,8 +402,8 @@ def create_engine(sql_connection, sqlite_fk=False, mysql_sql_mode=None,
# register alternate exception handler
exc_filters.register_engine(engine)
- # register on begin handler
- sqlalchemy.event.listen(engine, "begin", _begin_ping_listener)
+ # register engine connect handler
+ compat.engine_connect(engine, _connect_ping_listener)
# initial connect + test
_test_connection(engine, max_retries, retry_interval)
diff --git a/oslo/db/sqlalchemy/test_base.py b/oslo/db/sqlalchemy/test_base.py
index cb4e3d5..02a356a 100644
--- a/oslo/db/sqlalchemy/test_base.py
+++ b/oslo/db/sqlalchemy/test_base.py
@@ -14,7 +14,6 @@
# under the License.
import abc
-import functools
import os
import fixtures
@@ -82,7 +81,7 @@ def backend_specific(*dialects):
::dialects: list of dialects names under which the test will be launched.
"""
def wrap(f):
- @functools.wraps(f)
+ @six.wraps(f)
def ins_wrap(self):
if not set(dialects).issubset(ALLOWED_DIALECTS):
raise ValueError(