summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-09-09 12:47:58 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-09-09 13:13:00 -0400
commit57f499eae5470dcebc10975e8d02ecedea3d624f (patch)
tree02ed2b4f01324bfb803bd7f2c6e6086408473cc7
parent8f7681946a62b5f835f267b68d02bf4c8aa7a0e2 (diff)
downloadoslo-db-57f499eae5470dcebc10975e8d02ecedea3d624f.tar.gz
Add a check for SQLite transactional state
When we intercept SQLite transactions for BEGIN, check a marker that we place there to indicate BEGIN has already been called, which we then remove on commit or rollback. This is to resolve the issue of the fact that we currently use the StaticPool implementation with SQLite, which shares a single SQLite connection for all requests; any API method which makes use of multiple sessions at once (not a good idea, but this is prevalent throughout nova, neutron) will therefore share the same SQLite connection with multiple SQLAlchemy Connection wrappers that are not aware of the existing state. While this practice should be corrected, for now the marker, which is local to the SQLite connection as stored by the pool, will track when BEGIN is safe to call, or has already been called. Change-Id: I70d44104412bd99d8c7713eb6cd9ff0f80c5da34 Closes-Bug: #1367354
-rw-r--r--oslo/db/sqlalchemy/session.py13
1 files changed, 11 insertions, 2 deletions
diff --git a/oslo/db/sqlalchemy/session.py b/oslo/db/sqlalchemy/session.py
index 9ab09db..192ad1d 100644
--- a/oslo/db/sqlalchemy/session.py
+++ b/oslo/db/sqlalchemy/session.py
@@ -504,8 +504,17 @@ def _init_events(engine, sqlite_synchronous=True, sqlite_fk=False, **kw):
@sqlalchemy.event.listens_for(engine, "begin")
def _sqlite_emit_begin(conn):
- # emit our own BEGIN
- conn.execute("BEGIN")
+ # emit our own BEGIN, checking for existing
+ # transactional state
+ if 'in_transaction' not in conn.info:
+ conn.execute("BEGIN")
+ conn.info['in_transaction'] = True
+
+ @sqlalchemy.event.listens_for(engine, "rollback")
+ @sqlalchemy.event.listens_for(engine, "commit")
+ def _sqlite_end_transaction(conn):
+ # remove transactional marker
+ conn.info.pop('in_transaction', None)
def _test_connection(engine, max_retries, retry_interval):