Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / managers.py @ 7deaaa5f

History | View | Annotate | Download (4.4 kB)

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

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

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

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

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

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

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

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