dibbler/sqlalchemy/engine/threadlocal.py

139 lines
4.1 KiB
Python
Raw Normal View History

2017-04-15 18:27:12 +02:00
# engine/threadlocal.py
# Copyright (C) 2005-2017 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
2010-05-07 19:33:49 +02:00
"""Provides a thread-local transactional wrapper around the root Engine class.
2017-04-15 18:27:12 +02:00
The ``threadlocal`` module is invoked when using the
``strategy="threadlocal"`` flag with :func:`~sqlalchemy.engine.create_engine`.
This module is semi-private and is invoked automatically when the threadlocal
engine strategy is used.
2010-05-07 19:33:49 +02:00
"""
2017-04-15 18:27:12 +02:00
from .. import util
from . import base
2010-05-07 19:33:49 +02:00
import weakref
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
class TLConnection(base.Connection):
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
def __init__(self, *arg, **kw):
super(TLConnection, self).__init__(*arg, **kw)
self.__opencount = 0
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
def _increment_connect(self):
self.__opencount += 1
return self
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
def close(self):
if self.__opencount == 1:
base.Connection.close(self)
self.__opencount -= 1
def _force_close(self):
self.__opencount = 0
base.Connection.close(self)
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
class TLEngine(base.Engine):
2017-04-15 18:27:12 +02:00
"""An Engine that includes support for thread-local managed
transactions.
2010-05-07 19:33:49 +02:00
2017-04-15 18:27:12 +02:00
"""
_tl_connection_cls = TLConnection
2010-05-07 19:33:49 +02:00
def __init__(self, *args, **kwargs):
super(TLEngine, self).__init__(*args, **kwargs)
self._connections = util.threading.local()
def contextual_connect(self, **kw):
if not hasattr(self._connections, 'conn'):
connection = None
else:
connection = self._connections.conn()
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
if connection is None or connection.closed:
# guards against pool-level reapers, if desired.
# or not connection.connection.is_valid:
2017-04-15 18:27:12 +02:00
connection = self._tl_connection_cls(
self,
self._wrap_pool_connect(
self.pool.connect, connection),
**kw)
self._connections.conn = weakref.ref(connection)
2010-05-07 19:33:49 +02:00
return connection._increment_connect()
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
def begin_twophase(self, xid=None):
if not hasattr(self._connections, 'trans'):
self._connections.trans = []
2017-04-15 18:27:12 +02:00
self._connections.trans.append(
self.contextual_connect().begin_twophase(xid=xid))
return self
2010-05-07 19:33:49 +02:00
def begin_nested(self):
if not hasattr(self._connections, 'trans'):
self._connections.trans = []
2017-04-15 18:27:12 +02:00
self._connections.trans.append(
self.contextual_connect().begin_nested())
return self
2010-05-07 19:33:49 +02:00
def begin(self):
if not hasattr(self._connections, 'trans'):
self._connections.trans = []
self._connections.trans.append(self.contextual_connect().begin())
2017-04-15 18:27:12 +02:00
return self
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
if type is None:
self.commit()
else:
self.rollback()
2010-05-07 19:33:49 +02:00
def prepare(self):
2017-04-15 18:27:12 +02:00
if not hasattr(self._connections, 'trans') or \
not self._connections.trans:
return
2010-05-07 19:33:49 +02:00
self._connections.trans[-1].prepare()
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
def commit(self):
2017-04-15 18:27:12 +02:00
if not hasattr(self._connections, 'trans') or \
not self._connections.trans:
return
2010-05-07 19:33:49 +02:00
trans = self._connections.trans.pop(-1)
trans.commit()
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
def rollback(self):
2017-04-15 18:27:12 +02:00
if not hasattr(self._connections, 'trans') or \
not self._connections.trans:
return
2010-05-07 19:33:49 +02:00
trans = self._connections.trans.pop(-1)
trans.rollback()
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
def dispose(self):
self._connections = util.threading.local()
super(TLEngine, self).dispose()
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
@property
def closed(self):
return not hasattr(self._connections, 'conn') or \
2017-04-15 18:27:12 +02:00
self._connections.conn() is None or \
self._connections.conn().closed
2010-05-07 19:33:49 +02:00
def close(self):
if not self.closed:
self.contextual_connect().close()
connection = self._connections.conn()
connection._force_close()
del self._connections.conn
self._connections.trans = []
2017-04-15 18:27:12 +02:00
2010-05-07 19:33:49 +02:00
def __repr__(self):
2017-04-15 18:27:12 +02:00
return 'TLEngine(%r)' % self.url