Ticket #1442: django.threading.2.patch

File django.threading.2.patch, 10.6 KB (added by eugene@…, 10 years ago)

patch for trunk (includes all database backends)

  • C:/Projects/Django/django/core/db/backends/ado_mssql.py

     
    4444    return res
    4545Database.convertVariantToPython = variantToPython
    4646
    47 class DatabaseWrapper:
     47try:
     48    # only exists in python 2.4+
     49    from threading import local
     50except ImportError:
     51    # import copy of _thread_local.py from python 2.4
     52    from django.utils._threading_local import local
     53
     54class DatabaseWrapper(local):
    4855    def __init__(self):
    4956        self.connection = None
    5057        self.queries = []
  • C:/Projects/Django/django/core/db/backends/mysql.py

     
    4646            return self.__dict__[attr]
    4747        else:
    4848            return getattr(self.cursor, attr)
     49           
     50try:
     51    # only exists in python 2.4+
     52    from threading import local
     53except ImportError:
     54    # import copy of _thread_local.py from python 2.4
     55    from django.utils._threading_local import local
    4956
    50 class DatabaseWrapper:
     57class DatabaseWrapper(local):
    5158    def __init__(self):
    5259        self.connection = None
    5360        self.queries = []
     61       
     62    def _valid_connection(self):
     63        if self.connection is not None:
     64            try:
     65                self.connection.ping()
     66                return True
     67            except DatabaseError:
     68                self.connection.close()
     69                self.connection = None
     70        return False
    5471
    5572    def cursor(self):
    5673        from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG
    57         if self.connection is None:
     74        if not self._valid_connection():
    5875            kwargs = {
    5976                'user': DATABASE_USER,
    6077                'db': DATABASE_NAME,
  • C:/Projects/Django/django/core/db/backends/postgresql.py

     
    99
    1010DatabaseError = Database.DatabaseError
    1111
    12 class DatabaseWrapper:
     12try:
     13    # only exists in python 2.4+
     14    from threading import local
     15except ImportError:
     16    # import copy of _thread_local.py from python 2.4
     17    from django.utils._threading_local import local
     18
     19class DatabaseWrapper(local):
    1320    def __init__(self):
    1421        self.connection = None
    1522        self.queries = []
  • C:/Projects/Django/django/core/db/backends/sqlite3.py

     
    2424            return s
    2525    return [utf8(r) for r in row]
    2626
    27 class DatabaseWrapper:
     27try:
     28    # only exists in python 2.4+
     29    from threading import local
     30except ImportError:
     31    # import copy of _thread_local.py from python 2.4
     32    from django.utils._threading_local import local
     33
     34class DatabaseWrapper(local):
    2835    def __init__(self):
    2936        self.connection = None
    3037        self.queries = []
  • C:/Projects/Django/django/utils/_threading_local.py

     
     1"""Thread-local objects
     2
     3(Note that this module provides a Python version of thread
     4 threading.local class.  Depending on the version of Python you're
     5 using, there may be a faster one available.  You should always import
     6 the local class from threading.)
     7
     8Thread-local objects support the management of thread-local data.
     9If you have data that you want to be local to a thread, simply create
     10a thread-local object and use its attributes:
     11
     12  >>> mydata = local()
     13  >>> mydata.number = 42
     14  >>> mydata.number
     15  42
     16
     17You can also access the local-object's dictionary:
     18
     19  >>> mydata.__dict__
     20  {'number': 42}
     21  >>> mydata.__dict__.setdefault('widgets', [])
     22  []
     23  >>> mydata.widgets
     24  []
     25
     26What's important about thread-local objects is that their data are
     27local to a thread. If we access the data in a different thread:
     28
     29  >>> log = []
     30  >>> def f():
     31  ...     items = mydata.__dict__.items()
     32  ...     items.sort()
     33  ...     log.append(items)
     34  ...     mydata.number = 11
     35  ...     log.append(mydata.number)
     36
     37  >>> import threading
     38  >>> thread = threading.Thread(target=f)
     39  >>> thread.start()
     40  >>> thread.join()
     41  >>> log
     42  [[], 11]
     43
     44we get different data.  Furthermore, changes made in the other thread
     45don't affect data seen in this thread:
     46
     47  >>> mydata.number
     48  42
     49
     50Of course, values you get from a local object, including a __dict__
     51attribute, are for whatever thread was current at the time the
     52attribute was read.  For that reason, you generally don't want to save
     53these values across threads, as they apply only to the thread they
     54came from.
     55
     56You can create custom local objects by subclassing the local class:
     57
     58  >>> class MyLocal(local):
     59  ...     number = 2
     60  ...     initialized = False
     61  ...     def __init__(self, **kw):
     62  ...         if self.initialized:
     63  ...             raise SystemError('__init__ called too many times')
     64  ...         self.initialized = True
     65  ...         self.__dict__.update(kw)
     66  ...     def squared(self):
     67  ...         return self.number ** 2
     68
     69This can be useful to support default values, methods and
     70initialization.  Note that if you define an __init__ method, it will be
     71called each time the local object is used in a separate thread.  This
     72is necessary to initialize each thread's dictionary.
     73
     74Now if we create a local object:
     75
     76  >>> mydata = MyLocal(color='red')
     77
     78Now we have a default number:
     79
     80  >>> mydata.number
     81  2
     82
     83an initial color:
     84
     85  >>> mydata.color
     86  'red'
     87  >>> del mydata.color
     88
     89And a method that operates on the data:
     90
     91  >>> mydata.squared()
     92  4
     93
     94As before, we can access the data in a separate thread:
     95
     96  >>> log = []
     97  >>> thread = threading.Thread(target=f)
     98  >>> thread.start()
     99  >>> thread.join()
     100  >>> log
     101  [[('color', 'red'), ('initialized', True)], 11]
     102
     103without affecting this thread's data:
     104
     105  >>> mydata.number
     106  2
     107  >>> mydata.color
     108  Traceback (most recent call last):
     109  ...
     110  AttributeError: 'MyLocal' object has no attribute 'color'
     111
     112Note that subclasses can define slots, but they are not thread
     113local. They are shared across threads:
     114
     115  >>> class MyLocal(local):
     116  ...     __slots__ = 'number'
     117
     118  >>> mydata = MyLocal()
     119  >>> mydata.number = 42
     120  >>> mydata.color = 'red'
     121
     122So, the separate thread:
     123
     124  >>> thread = threading.Thread(target=f)
     125  >>> thread.start()
     126  >>> thread.join()
     127
     128affects what we see:
     129
     130  >>> mydata.number
     131  11
     132
     133>>> del mydata
     134"""
     135
     136# Threading import is at end
     137
     138class _localbase(object):
     139    __slots__ = '_local__key', '_local__args', '_local__lock'
     140
     141    def __new__(cls, *args, **kw):
     142        self = object.__new__(cls)
     143        key = '_local__key', 'thread.local.' + str(id(self))
     144        object.__setattr__(self, '_local__key', key)
     145        object.__setattr__(self, '_local__args', (args, kw))
     146        object.__setattr__(self, '_local__lock', RLock())
     147
     148        if args or kw and (cls.__init__ is object.__init__):
     149            raise TypeError("Initialization arguments are not supported")
     150
     151        # We need to create the thread dict in anticipation of
     152        # __init__ being called, to make sire we don't cal it
     153        # again ourselves.
     154        dict = object.__getattribute__(self, '__dict__')
     155        currentThread().__dict__[key] = dict
     156
     157        return self
     158
     159def _patch(self):
     160    key = object.__getattribute__(self, '_local__key')
     161    d = currentThread().__dict__.get(key)
     162    if d is None:
     163        d = {}
     164        currentThread().__dict__[key] = d
     165        object.__setattr__(self, '__dict__', d)
     166
     167        # we have a new instance dict, so call out __init__ if we have
     168        # one
     169        cls = type(self)
     170        if cls.__init__ is not object.__init__:
     171            args, kw = object.__getattribute__(self, '_local__args')
     172            cls.__init__(self, *args, **kw)
     173    else:
     174        object.__setattr__(self, '__dict__', d)
     175
     176class local(_localbase):
     177
     178    def __getattribute__(self, name):
     179        lock = object.__getattribute__(self, '_local__lock')
     180        lock.acquire()
     181        try:
     182            _patch(self)
     183            return object.__getattribute__(self, name)
     184        finally:
     185            lock.release()
     186
     187    def __setattr__(self, name, value):
     188        lock = object.__getattribute__(self, '_local__lock')
     189        lock.acquire()
     190        try:
     191            _patch(self)
     192            return object.__setattr__(self, name, value)
     193        finally:
     194            lock.release()
     195
     196    def __delattr__(self, name):
     197        lock = object.__getattribute__(self, '_local__lock')
     198        lock.acquire()
     199        try:
     200            _patch(self)
     201            return object.__delattr__(self, name)
     202        finally:
     203            lock.release()
     204
     205
     206    def __del__():
     207        threading_enumerate = enumerate
     208        __getattribute__ = object.__getattribute__
     209
     210        def __del__(self):
     211            key = __getattribute__(self, '_local__key')
     212
     213            try:
     214                threads = list(threading_enumerate())
     215            except:
     216                # if enumerate fails, as it seems to do during
     217                # shutdown, we'll skip cleanup under the assumption
     218                # that there is nothing to clean up
     219                return
     220
     221            for thread in threads:
     222                try:
     223                    __dict__ = thread.__dict__
     224                except AttributeError:
     225                    # Thread is dying, rest in peace
     226                    continue
     227
     228                if key in __dict__:
     229                    try:
     230                        del __dict__[key]
     231                    except KeyError:
     232                        pass # didn't have anything in this thread
     233
     234        return __del__
     235    __del__ = __del__()
     236
     237from threading import currentThread, enumerate, RLock
Back to Top