diff options
| author | Jon Dufresne <jon.dufresne@gmail.com> | 2019-02-14 07:04:55 -0800 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2019-02-14 10:04:55 -0500 |
| commit | 76990cbbda5d93fda560c8a5ab019860f7efaab7 (patch) | |
| tree | 7e299a0eb50001d19d11120b9acb286744779afc /django/db | |
| parent | 21f9d437374ee078ee46e23b64efa3d52ca6f49a (diff) | |
Fixed #30171 -- Fixed DatabaseError in servers tests.
Made DatabaseWrapper thread sharing logic reentrant. Used a reference
counting like scheme to allow nested uses.
The error appeared after 8c775391b78b2a4a2b57c5e89ed4888f36aada4b.
Diffstat (limited to 'django/db')
| -rw-r--r-- | django/db/backends/base/base.py | 38 | ||||
| -rw-r--r-- | django/db/backends/postgresql/base.py | 1 |
2 files changed, 24 insertions, 15 deletions
diff --git a/django/db/backends/base/base.py b/django/db/backends/base/base.py index f97d171c96..9fa03cc0ee 100644 --- a/django/db/backends/base/base.py +++ b/django/db/backends/base/base.py @@ -1,4 +1,5 @@ import copy +import threading import time import warnings from collections import deque @@ -43,8 +44,7 @@ class BaseDatabaseWrapper: queries_limit = 9000 - def __init__(self, settings_dict, alias=DEFAULT_DB_ALIAS, - allow_thread_sharing=False): + def __init__(self, settings_dict, alias=DEFAULT_DB_ALIAS): # Connection related attributes. # The underlying database connection. self.connection = None @@ -80,7 +80,8 @@ class BaseDatabaseWrapper: self.errors_occurred = False # Thread-safety related attributes. - self.allow_thread_sharing = allow_thread_sharing + self._thread_sharing_lock = threading.Lock() + self._thread_sharing_count = 0 self._thread_ident = _thread.get_ident() # A list of no-argument functions to run when the transaction commits. @@ -515,12 +516,27 @@ class BaseDatabaseWrapper: # ##### Thread safety handling ##### + @property + def allow_thread_sharing(self): + with self._thread_sharing_lock: + return self._thread_sharing_count > 0 + + def inc_thread_sharing(self): + with self._thread_sharing_lock: + self._thread_sharing_count += 1 + + def dec_thread_sharing(self): + with self._thread_sharing_lock: + if self._thread_sharing_count <= 0: + raise RuntimeError('Cannot decrement the thread sharing count below zero.') + self._thread_sharing_count -= 1 + def validate_thread_sharing(self): """ Validate that the connection isn't accessed by another thread than the one which originally created it, unless the connection was explicitly - authorized to be shared between threads (via the `allow_thread_sharing` - property). Raise an exception if the validation fails. + authorized to be shared between threads (via the `inc_thread_sharing()` + method). Raise an exception if the validation fails. """ if not (self.allow_thread_sharing or self._thread_ident == _thread.get_ident()): raise DatabaseError( @@ -589,11 +605,7 @@ class BaseDatabaseWrapper: potential child threads while (or after) the test database is destroyed. Refs #10868, #17786, #16969. """ - return self.__class__( - {**self.settings_dict, 'NAME': None}, - alias=NO_DB_ALIAS, - allow_thread_sharing=False, - ) + return self.__class__({**self.settings_dict, 'NAME': None}, alias=NO_DB_ALIAS) def schema_editor(self, *args, **kwargs): """ @@ -635,7 +647,7 @@ class BaseDatabaseWrapper: finally: self.execute_wrappers.pop() - def copy(self, alias=None, allow_thread_sharing=None): + def copy(self, alias=None): """ Return a copy of this connection. @@ -644,6 +656,4 @@ class BaseDatabaseWrapper: settings_dict = copy.deepcopy(self.settings_dict) if alias is None: alias = self.alias - if allow_thread_sharing is None: - allow_thread_sharing = self.allow_thread_sharing - return type(self)(settings_dict, alias, allow_thread_sharing) + return type(self)(settings_dict, alias) diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 4be5a193bb..b3a3202c90 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -277,7 +277,6 @@ class DatabaseWrapper(BaseDatabaseWrapper): return self.__class__( {**self.settings_dict, 'NAME': connection.settings_dict['NAME']}, alias=self.alias, - allow_thread_sharing=False, ) return nodb_connection |
