Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (4.3 kB)

1 dbecf586 Christos Stavrakakis
# Copyright 2012, 2013 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 dbecf586 Christos Stavrakakis
    """Model manager implementing SELECT .. FOR UPDATE statement
37 864bed43 Christos Stavrakakis

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

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

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

50 864bed43 Christos Stavrakakis
    """
51 864bed43 Christos Stavrakakis
52 1c11bace Christos Stavrakakis
    def select_for_update(self, *args, **kwargs):
53 1c11bace Christos Stavrakakis
        return ForUpdateQuerySet(self.model, using=self.db)
54 1c11bace Christos Stavrakakis
55 1c11bace Christos Stavrakakis
56 1c11bace Christos Stavrakakis
class ForUpdateQuerySet(QuerySet):
57 dbecf586 Christos Stavrakakis
    """QuerySet implmenting SELECT .. FOR UPDATE statement
58 1c11bace Christos Stavrakakis

59 1c11bace Christos Stavrakakis
    This QuerySet overrides filter and get methods in order to implement
60 1c11bace Christos Stavrakakis
    select_for_update() statement, by appending 'FOR UPDATE' to the end
61 1c11bace Christos Stavrakakis
    for the SQL query.
62 1c11bace Christos Stavrakakis

63 1c11bace Christos Stavrakakis
    """
64 864bed43 Christos Stavrakakis
65 864bed43 Christos Stavrakakis
    def filter(self, *args, **kwargs):
66 1c11bace Christos Stavrakakis
        query = super(ForUpdateQuerySet, self).filter(*args, **kwargs)
67 1c11bace Christos Stavrakakis
        return for_update(query)
68 864bed43 Christos Stavrakakis
69 864bed43 Christos Stavrakakis
    def get(self, *args, **kwargs):
70 864bed43 Christos Stavrakakis
        query = self.filter(*args, **kwargs)
71 864bed43 Christos Stavrakakis
        query = list(query)
72 864bed43 Christos Stavrakakis
        num = len(query)
73 864bed43 Christos Stavrakakis
        if num == 1:
74 864bed43 Christos Stavrakakis
            return query[0]
75 864bed43 Christos Stavrakakis
        if not num:
76 68b952f9 Christos Stavrakakis
            raise self.model.DoesNotExist("%s matching query does not exist. "
77 68b952f9 Christos Stavrakakis
                                          "Lookup parameters were %s" %
78 68b952f9 Christos Stavrakakis
                                          (self.model._meta.object_name,
79 68b952f9 Christos Stavrakakis
                                           kwargs))
80 864bed43 Christos Stavrakakis
        raise self.model.MultipleObjectsReturned(
81 864bed43 Christos Stavrakakis
            "get() returned more than one %s -- it returned %s! "
82 864bed43 Christos Stavrakakis
            "Lookup parameters were %s" %
83 864bed43 Christos Stavrakakis
            (self.model._meta.object_name, num, kwargs))
84 864bed43 Christos Stavrakakis
85 864bed43 Christos Stavrakakis
86 864bed43 Christos Stavrakakis
def for_update(query):
87 dbecf586 Christos Stavrakakis
    """Rewrite query using SELECT .. FOR UPDATE."""
88 864bed43 Christos Stavrakakis
    if 'sqlite' in connections[query.db].settings_dict['ENGINE'].lower():
89 864bed43 Christos Stavrakakis
        # SQLite  does not support FOR UPDATE
90 864bed43 Christos Stavrakakis
        return query
91 864bed43 Christos Stavrakakis
    sql, params = query.query.get_compiler(query.db).as_sql()
92 864bed43 Christos Stavrakakis
    return query.model._default_manager.raw(sql.rstrip() + ' FOR UPDATE',
93 864bed43 Christos Stavrakakis
                                            params)
94 864bed43 Christos Stavrakakis
95 864bed43 Christos Stavrakakis
96 adc46059 Christos Stavrakakis
class ProtectedDeleteManager(ForUpdateManager):
97 dbecf586 Christos Stavrakakis
    """Manager for protecting Backend deletion.
98 864bed43 Christos Stavrakakis

99 dbecf586 Christos Stavrakakis
    Call Backend delete() method in order to prevent deletion
100 dbecf586 Christos Stavrakakis
    of Backends that host non-deleted VirtualMachines.
101 864bed43 Christos Stavrakakis

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