Revision c7e03d20

b/snf-astakos-app/astakos/im/functions.py
290 290

  
291 291
def get_project_for_update(project_id):
292 292
    try:
293
        return Project.objects.get_for_update(id=project_id)
293
        return Project.objects.select_for_update().get(id=project_id)
294 294
    except Project.DoesNotExist:
295 295
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % project_id
296 296
        raise ProjectNotFound(m)
......
302 302

  
303 303

  
304 304
def get_project_lock():
305
    ProjectLock.objects.get_for_update(pk=1)
305
    ProjectLock.objects.select_for_update().get(pk=1)
306 306

  
307 307

  
308 308
def get_application(application_id):
......
965 965

  
966 966

  
967 967
def qh_add_pending_app(user, project=None, force=False):
968
    user = AstakosUser.forupdate.get_for_update(id=user.id)
968
    user = AstakosUser.objects.select_for_update().get(id=user.id)
969 969
    diff = get_pending_app_diff(user, project)
970 970
    return register_pending_apps(user, diff, force)
971 971

  
......
982 982

  
983 983
def qh_release_pending_app(user, locked=False):
984 984
    if not locked:
985
        user = AstakosUser.forupdate.get_for_update(id=user.id)
985
        user = AstakosUser.objects.select_for_update().get(id=user.id)
986 986
    register_pending_apps(user, -1)
b/snf-astakos-app/astakos/im/management/commands/resource-modify.py
109 109

  
110 110
    def get_resource(self, resource_name):
111 111
        try:
112
            return Resource.objects.get_for_update(name=resource_name)
112
            return Resource.objects.select_for_update().get(name=resource_name)
113 113
        except Resource.DoesNotExist:
114 114
            raise CommandError("Resource %s does not exist."
115 115
                               % resource_name)
b/snf-astakos-app/astakos/im/models.py
62 62
from astakos.im import auth_providers as auth
63 63

  
64 64
import astakos.im.messages as astakos_messages
65
from snf_django.lib.db.managers import ForUpdateManager
66 65
from synnefo.lib.ordereddict import OrderedDict
67 66

  
68 67
from snf_django.lib.db.fields import intDecimalField
......
237 236
    uplimit = intDecimalField(default=0)
238 237
    allow_in_projects = models.BooleanField(default=True)
239 238

  
240
    objects = ForUpdateManager()
241

  
242 239
    def __str__(self):
243 240
        return self.name
244 241

  
......
455 452
                                          default=False, db_index=True)
456 453

  
457 454
    objects = AstakosUserManager()
458
    forupdate = ForUpdateManager()
459 455

  
460 456
    def __init__(self, *args, **kwargs):
461 457
        super(AstakosUser, self).__init__(*args, **kwargs)
......
1261 1257
    setting = models.CharField(max_length=255)
1262 1258
    value = models.IntegerField()
1263 1259

  
1264
    objects = ForUpdateManager()
1265

  
1266 1260
    class Meta:
1267 1261
        unique_together = ("user", "setting")
1268 1262

  
......
1272 1266

  
1273 1267
class Chain(models.Model):
1274 1268
    chain = models.AutoField(primary_key=True)
1275
    objects = ForUpdateManager()
1276 1269

  
1277 1270
    def __str__(self):
1278 1271
        return "%s" % (self.chain,)
......
1283 1276
    return c
1284 1277

  
1285 1278

  
1286
class ProjectApplicationManager(ForUpdateManager):
1279
class ProjectApplicationManager(models.Manager):
1287 1280

  
1288 1281
    def pending_per_project(self, projects):
1289 1282
        apps = self.filter(state=self.model.PENDING,
......
1527 1520
    return dict((v, k) for k, v in d.iteritems())
1528 1521

  
1529 1522

  
1530
class ProjectManager(ForUpdateManager):
1523
class ProjectManager(models.Manager):
1531 1524

  
1532 1525
    def all_with_pending(self, flt=None):
1533 1526
        flt = Q() if flt is None else flt
......
1802 1795

  
1803 1796

  
1804 1797
class ProjectLock(models.Model):
1805
    objects = ForUpdateManager()
1798
    pass
1806 1799

  
1807 1800

  
1808
class ProjectMembershipManager(ForUpdateManager):
1801
class ProjectMembershipManager(models.Manager):
1809 1802

  
1810 1803
    def any_accepted(self):
1811 1804
        q = self.model.Q_ACCEPTED_STATES
b/snf-astakos-app/astakos/im/quotas.py
255 255

  
256 256
def get_users_for_update(user_ids):
257 257
    uids = sorted(user_ids)
258
    objs = AstakosUser.forupdate
258
    objs = AstakosUser.objects
259 259
    return list(objs.filter(id__in=uids).order_by('id').select_for_update())
260 260

  
261 261

  
......
313 313

  
314 314

  
315 315
def qh_add_resource_limit(resource, diff):
316
    objs = AstakosUser.forupdate.filter(Q(email_verified=True) &
317
                                        ~Q(policy=resource))
316
    objs = AstakosUser.objects.filter(Q(email_verified=True) &
317
                                      ~Q(policy=resource))
318 318
    users = objs.order_by('id').select_for_update()
319 319
    uuids = [u.uuid for u in users]
320 320
    qh.add_resource_limit(holders=uuids, sources=[SYSTEM],
......
322 322

  
323 323

  
324 324
def qh_sync_new_resource(resource, limit):
325
    users = AstakosUser.forupdate.filter(
325
    users = AstakosUser.objects.filter(
326 326
        email_verified=True).order_by('id').select_for_update()
327 327

  
328 328
    resource_name = resource.name
b/snf-astakos-app/astakos/im/register.py
59 59
        raise RegisterException(m)
60 60

  
61 61
    try:
62
        r = Resource.objects.get_for_update(name=name)
62
        r = Resource.objects.select_for_update().get(name=name)
63 63
        exists = True
64 64
        if r.service_type != service_type:
65 65
            m = ("There already exists a resource named %s with service "
b/snf-astakos-app/astakos/quotaholder_app/models.py
35 35

  
36 36
from django.db.models import (Model, BigIntegerField, CharField, DateTimeField,
37 37
                              ForeignKey, AutoField)
38
from snf_django.lib.db.managers import ForUpdateManager
39 38

  
40 39

  
41 40
class Holding(Model):
......
48 47
    usage_min = intDecimalField(default=0)
49 48
    usage_max = intDecimalField(default=0)
50 49

  
51
    objects = ForUpdateManager()
52

  
53 50
    class Meta:
54 51
        unique_together = (('holder', 'source', 'resource'),)
55 52

  
......
61 58
    clientkey = CharField(max_length=4096, null=False)
62 59
    issue_datetime = DateTimeField()
63 60

  
64
    objects = ForUpdateManager()
65

  
66 61

  
67 62
class Provision(Model):
68 63

  
......
75 70

  
76 71
    quantity = intDecimalField()
77 72

  
78
    objects = ForUpdateManager()
79

  
80 73
    def todict(self):
81 74
        return {'holder':   self.holder,
82 75
                'source':   self.source,
......
102 95
    usage_max = intDecimalField()
103 96
    delta_quantity = intDecimalField()
104 97
    reason = CharField(max_length=4096)
105

  
106
    objects = ForUpdateManager()
/dev/null
1
# Copyright 2012, 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
#
7
#   1. Redistributions of source code must retain the above copyright
8
#      notice, this list of conditions and the following disclaimer.
9
#
10
#  2. Redistributions in binary form must reproduce the above copyright
11
#     notice, this list of conditions and the following disclaimer in the
12
#     documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
# SUCH DAMAGE.
25
#
26
# The views and conclusions contained in the software and documentation are
27
# those of the authors and should not be interpreted as representing official
28
# policies, either expressed or implied, of GRNET S.A.
29

  
30
from django.db import connections
31
from django.db.models import Manager
32
from django.db.models.query import QuerySet, EmptyQuerySet
33
from django.db.models.sql.datastructures import EmptyResultSet
34

  
35

  
36
class ForUpdateManager(Manager):
37
    """ Model manager implementing SELECT .. FOR UPDATE statement
38

  
39
        This manager implements select_for_update() method in order to use
40
        row-level locking in the database and guarantee exclusive access, since
41
        this method is only implemented in Django>=1.4.
42

  
43
        Non-blocking reads are not implemented, and each query including a row
44
        that is locked by another transaction will block until the lock is
45
        released. Also care must be taken in order to avoid deadlocks or retry
46
        transactions that abort due to deadlocks.
47

  
48
        Example:
49
            networks = Network.objects.filter(public=True).select_for_update()
50

  
51
    """
52

  
53
    def get_query_set(self):
54
        return ForUpdateQuerySet(self.model, using=self._db)
55

  
56
    def get_for_update(self, *args, **kwargs):
57
        query = for_update(self.filter(*args, **kwargs))
58
        query = list(query)
59
        num = len(query)
60
        if num == 1:
61
            return query[0]
62
        if not num:
63
            raise self.model.DoesNotExist(
64
                "%s matching query does not exist. "
65
                "Lookup parameters were %s" %
66
                (self.model._meta.object_name, kwargs))
67
        raise self.model.MultipleObjectsReturned(
68
            "get() returned more than one %s -- it returned %s! "
69
            "Lookup parameters were %s" %
70
            (self.model._meta.object_name, num, kwargs))
71

  
72

  
73
class ForUpdateQuerySet(QuerySet):
74

  
75
    def select_for_update(self):
76
        return for_update(self)
77

  
78

  
79
def for_update(query):
80
    """ Rewrite query using SELECT .. FOR UPDATE.
81

  
82
    """
83
    if 'sqlite' in connections[query.db].settings_dict['ENGINE'].lower():
84
        # SQLite  does not support FOR UPDATE
85
        return query
86
    try:
87
        sql, params = query.query.get_compiler(query.db).as_sql()
88
    except EmptyResultSet:
89
        return EmptyQuerySet()
90
    return query.model._default_manager.raw(sql.rstrip() + ' FOR UPDATE',
91
                                            params)

Also available in: Unified diff