diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-09-09 12:47:58 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-09-09 13:13:00 -0400 |
commit | 57f499eae5470dcebc10975e8d02ecedea3d624f (patch) | |
tree | 02ed2b4f01324bfb803bd7f2c6e6086408473cc7 | |
parent | 8f7681946a62b5f835f267b68d02bf4c8aa7a0e2 (diff) | |
download | oslo-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.py | 13 |
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): |