Statistics
| Branch: | Tag: | Revision:

root / snf-quotaholder-app / quotaholder_django / quotaholder_app / managers.py @ e5a2e942

History | View | Annotate | Download (4.4 kB)

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

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

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

47 5d996aea Giorgos Korfiatis
        Example:
48 5d996aea Giorgos Korfiatis
            networks = Network.objects.select_for_update().filter(public=True)
49 5d996aea Giorgos Korfiatis

50 5d996aea Giorgos Korfiatis
    """
51 5d996aea Giorgos Korfiatis
52 5d996aea Giorgos Korfiatis
    def __init__(self, *args, **kwargs):
53 5d996aea Giorgos Korfiatis
        super(ForUpdateManager, self).__init__(*args, **kwargs)
54 5d996aea Giorgos Korfiatis
        self._select_for_update = False
55 5d996aea Giorgos Korfiatis
56 5d996aea Giorgos Korfiatis
    def filter(self, *args, **kwargs):
57 5d996aea Giorgos Korfiatis
        query = self.get_query_set().filter(*args, **kwargs)
58 5d996aea Giorgos Korfiatis
        if self._select_for_update:
59 5d996aea Giorgos Korfiatis
            self._select_for_update = False
60 5d996aea Giorgos Korfiatis
            return for_update(query)
61 5d996aea Giorgos Korfiatis
        else:
62 5d996aea Giorgos Korfiatis
            return query
63 5d996aea Giorgos Korfiatis
64 5d996aea Giorgos Korfiatis
    def get(self, *args, **kwargs):
65 5d996aea Giorgos Korfiatis
        if not self._select_for_update:
66 5d996aea Giorgos Korfiatis
            return self.get_query_set().get(*args, **kwargs)
67 5d996aea Giorgos Korfiatis
68 5d996aea Giorgos Korfiatis
        query = self.filter(*args, **kwargs)
69 5d996aea Giorgos Korfiatis
        query = list(query)
70 5d996aea Giorgos Korfiatis
        num = len(query)
71 5d996aea Giorgos Korfiatis
        if num == 1:
72 5d996aea Giorgos Korfiatis
            return query[0]
73 5d996aea Giorgos Korfiatis
        if not num:
74 5d996aea Giorgos Korfiatis
            raise self.model.DoesNotExist(
75 5d996aea Giorgos Korfiatis
                    "%s matching query does not exist. "
76 5d996aea Giorgos Korfiatis
                    "Lookup parameters were %s" %
77 5d996aea Giorgos Korfiatis
                    (self.model._meta.object_name, kwargs))
78 5d996aea Giorgos Korfiatis
        raise self.model.MultipleObjectsReturned(
79 5d996aea Giorgos Korfiatis
            "get() returned more than one %s -- it returned %s! "
80 5d996aea Giorgos Korfiatis
            "Lookup parameters were %s" %
81 5d996aea Giorgos Korfiatis
            (self.model._meta.object_name, num, kwargs))
82 5d996aea Giorgos Korfiatis
83 5d996aea Giorgos Korfiatis
    def select_for_update(self, *args, **kwargs):
84 5d996aea Giorgos Korfiatis
        self._select_for_update = True
85 5d996aea Giorgos Korfiatis
        return self
86 5d996aea Giorgos Korfiatis
87 5d996aea Giorgos Korfiatis
88 5d996aea Giorgos Korfiatis
def for_update(query):
89 5d996aea Giorgos Korfiatis
    """ Rewrite query using SELECT .. FOR UPDATE.
90 5d996aea Giorgos Korfiatis

91 5d996aea Giorgos Korfiatis
    """
92 5d996aea Giorgos Korfiatis
    if 'sqlite' in connections[query.db].settings_dict['ENGINE'].lower():
93 5d996aea Giorgos Korfiatis
        # SQLite  does not support FOR UPDATE
94 5d996aea Giorgos Korfiatis
        return query
95 5d996aea Giorgos Korfiatis
    sql, params = query.query.get_compiler(query.db).as_sql()
96 5d996aea Giorgos Korfiatis
    return query.model._default_manager.raw(sql.rstrip() + ' FOR UPDATE',
97 5d996aea Giorgos Korfiatis
                                            params)
98 5d996aea Giorgos Korfiatis
99 5d996aea Giorgos Korfiatis
100 5d996aea Giorgos Korfiatis
class ProtectedDeleteManager(ForUpdateManager):
101 5d996aea Giorgos Korfiatis
    """ Manager for protecting Backend deletion.
102 5d996aea Giorgos Korfiatis

103 5d996aea Giorgos Korfiatis
        Call Backend delete() method in order to prevent deletion
104 5d996aea Giorgos Korfiatis
        of Backends that host non-deleted VirtualMachines.
105 5d996aea Giorgos Korfiatis

106 5d996aea Giorgos Korfiatis
    """
107 5d996aea Giorgos Korfiatis
108 5d996aea Giorgos Korfiatis
    def get_query_set(self):
109 5d996aea Giorgos Korfiatis
        return BackendQuerySet(self.model, using=self._db)
110 5d996aea Giorgos Korfiatis
111 5d996aea Giorgos Korfiatis
112 5d996aea Giorgos Korfiatis
class BackendQuerySet(QuerySet):
113 5d996aea Giorgos Korfiatis
    def delete(self):
114 5d996aea Giorgos Korfiatis
        for backend in self._clone():
115 5d996aea Giorgos Korfiatis
            backend.delete()