Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / db / managers.py @ 3165f027

History | View | Annotate | Download (4.3 kB)

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

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

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

47 864bed43 Christos Stavrakakis
        Example:
48 864bed43 Christos Stavrakakis
            networks = Network.objects.select_for_update().filter(public=True)
49 864bed43 Christos Stavrakakis

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

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

103 864bed43 Christos Stavrakakis
        Call Backend delete() method in order to prevent deletion
104 864bed43 Christos Stavrakakis
        of Backends that host non-deleted VirtualMachines.
105 864bed43 Christos Stavrakakis

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