Ticket #13105: django-1.1.1-thread-safe.patch

File django-1.1.1-thread-safe.patch, 4.3 KB (added by toplex, 12 years ago)

thread safe get_or_create patch

  • db/models/fields/related.py

    diff -urN django/db/models/fields/related.py django_new/db/models/fields/related.py
    old new  
    1010from django.utils.functional import curry
    1111from django.core import exceptions
    1212from django import forms
     13from threading import Lock
    1314
    1415try:
    1516    set
     
    408409        def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
    409410                join_table=None, source_col_name=None, target_col_name=None):
    410411            super(ManyRelatedManager, self).__init__()
     412            self._lock = model.objects._lock # using the model's manager lock
    411413            self.core_filters = core_filters
    412414            self.model = model
    413415            self.symmetrical = symmetrical
     
    488490                        raise TypeError, "'%s' instance expected" % self.model._meta.object_name
    489491                    else:
    490492                        new_ids.add(obj)
    491                 # Add the newly created or already existing objects to the join table.
    492                 # First find out which items are already added, to avoid adding them twice
    493                 cursor = connection.cursor()
    494                 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
    495                     (target_col_name, self.join_table, source_col_name,
    496                     target_col_name, ",".join(['%s'] * len(new_ids))),
    497                     [self._pk_val] + list(new_ids))
    498                 existing_ids = set([row[0] for row in cursor.fetchall()])
    499 
    500                 # Add the ones that aren't there already
    501                 for obj_id in (new_ids - existing_ids):
    502                     cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
    503                         (self.join_table, source_col_name, target_col_name),
    504                         [self._pk_val, obj_id])
    505                 transaction.commit_unless_managed()
     493
     494                self._lock.acquire()
     495                try:
     496                    # Add the newly created or already existing objects to the join table.
     497                    # First find out which items are already added, to avoid adding them twice
     498                    cursor = connection.cursor()
     499                    cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
     500                        (target_col_name, self.join_table, source_col_name,
     501                        target_col_name, ",".join(['%s'] * len(new_ids))),
     502                        [self._pk_val] + list(new_ids))
     503                    existing_ids = set([row[0] for row in cursor.fetchall()])
     504
     505                    # Add the ones that aren't there already
     506                    for obj_id in (new_ids - existing_ids):
     507                        cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
     508                            (self.join_table, source_col_name, target_col_name),
     509                            [self._pk_val, obj_id])
     510                    transaction.commit_unless_managed()
     511                finally: self._lock.release()
    506512
    507513        def _remove_items(self, source_col_name, target_col_name, *objs):
    508514            # source_col_name: the PK colname in join_table for the source object
  • db/models/manager.py

    diff -urN django/db/models/manager.py django_new/db/models/manager.py
    old new  
    33from django.db.models.query import QuerySet, EmptyQuerySet, insert_query
    44from django.db.models import signals
    55from django.db.models.fields import FieldDoesNotExist
     6from threading import Lock
    67
    78def ensure_default_manager(sender, **kwargs):
    89    """
     
    4748
    4849    def __init__(self):
    4950        super(Manager, self).__init__()
     51        self._lock = Lock()
    5052        self._set_creation_counter()
    5153        self.model = None
    5254        self._inherited = False
     
    120122        return self.get_query_set().get(*args, **kwargs)
    121123
    122124    def get_or_create(self, **kwargs):
    123         return self.get_query_set().get_or_create(**kwargs)
     125        self._lock.acquire()
     126        try: result = self.get_query_set().get_or_create(**kwargs)
     127        finally: self._lock.release()
     128        return result
    124129
    125130    def create(self, **kwargs):
    126131        return self.get_query_set().create(**kwargs)
Back to Top