Statistics
| Branch: | Tag: | Revision:

root / snf-common / synnefo / lib / db / xctx.py @ 1c65202f

History | View | Annotate | Download (4 kB)

1 d55d4f34 Giorgos Korfiatis
# Copyright 2013 GRNET S.A. All rights reserved.
2 d55d4f34 Giorgos Korfiatis
#
3 d55d4f34 Giorgos Korfiatis
# Redistribution and use in source and binary forms, with or
4 d55d4f34 Giorgos Korfiatis
# without modification, are permitted provided that the following
5 d55d4f34 Giorgos Korfiatis
# conditions are met:
6 d55d4f34 Giorgos Korfiatis
#
7 d55d4f34 Giorgos Korfiatis
#   1. Redistributions of source code must retain the above
8 d55d4f34 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
9 d55d4f34 Giorgos Korfiatis
#      disclaimer.
10 d55d4f34 Giorgos Korfiatis
#
11 d55d4f34 Giorgos Korfiatis
#   2. Redistributions in binary form must reproduce the above
12 d55d4f34 Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
13 d55d4f34 Giorgos Korfiatis
#      disclaimer in the documentation and/or other materials
14 d55d4f34 Giorgos Korfiatis
#      provided with the distribution.
15 d55d4f34 Giorgos Korfiatis
#
16 d55d4f34 Giorgos Korfiatis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 d55d4f34 Giorgos Korfiatis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 d55d4f34 Giorgos Korfiatis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 d55d4f34 Giorgos Korfiatis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 d55d4f34 Giorgos Korfiatis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 d55d4f34 Giorgos Korfiatis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 d55d4f34 Giorgos Korfiatis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 d55d4f34 Giorgos Korfiatis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 d55d4f34 Giorgos Korfiatis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 d55d4f34 Giorgos Korfiatis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 d55d4f34 Giorgos Korfiatis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 d55d4f34 Giorgos Korfiatis
# POSSIBILITY OF SUCH DAMAGE.
28 d55d4f34 Giorgos Korfiatis
#
29 d55d4f34 Giorgos Korfiatis
# The views and conclusions contained in the software and
30 d55d4f34 Giorgos Korfiatis
# documentation are those of the authors and should not be
31 d55d4f34 Giorgos Korfiatis
# interpreted as representing official policies, either expressed
32 d55d4f34 Giorgos Korfiatis
# or implied, of GRNET S.A.
33 d55d4f34 Giorgos Korfiatis
34 d55d4f34 Giorgos Korfiatis
from django.db import transaction
35 d55d4f34 Giorgos Korfiatis
36 d55d4f34 Giorgos Korfiatis
# USAGE
37 d55d4f34 Giorgos Korfiatis
# =====
38 d55d4f34 Giorgos Korfiatis
# @transaction_context()
39 d55d4f34 Giorgos Korfiatis
# def a_view(args, ctx=None):
40 d55d4f34 Giorgos Korfiatis
#     ...
41 d55d4f34 Giorgos Korfiatis
#     if ctx:
42 d55d4f34 Giorgos Korfiatis
#         ctx.mark_rollback()
43 d55d4f34 Giorgos Korfiatis
#     ...
44 d55d4f34 Giorgos Korfiatis
#     return http response
45 d55d4f34 Giorgos Korfiatis
#
46 d55d4f34 Giorgos Korfiatis
# OR
47 d55d4f34 Giorgos Korfiatis
#
48 d55d4f34 Giorgos Korfiatis
# def a_view(args):
49 d55d4f34 Giorgos Korfiatis
#     with transaction_context() as ctx:
50 d55d4f34 Giorgos Korfiatis
#         ...
51 d55d4f34 Giorgos Korfiatis
#         ctx.mark_rollback()
52 d55d4f34 Giorgos Korfiatis
#         ...
53 d55d4f34 Giorgos Korfiatis
#         return http response
54 d55d4f34 Giorgos Korfiatis
55 d55d4f34 Giorgos Korfiatis
def transaction_context(**kwargs):
56 d55d4f34 Giorgos Korfiatis
    return TransactionHandler(ctx=TransactionContext, **kwargs)
57 d55d4f34 Giorgos Korfiatis
58 d55d4f34 Giorgos Korfiatis
59 d55d4f34 Giorgos Korfiatis
class TransactionContext(object):
60 d55d4f34 Giorgos Korfiatis
    def __init__(self, notify=True):
61 d55d4f34 Giorgos Korfiatis
        self._rollback = False
62 d55d4f34 Giorgos Korfiatis
63 d55d4f34 Giorgos Korfiatis
    def mark_rollback(self):
64 d55d4f34 Giorgos Korfiatis
        self._rollback = True
65 d55d4f34 Giorgos Korfiatis
66 d55d4f34 Giorgos Korfiatis
    def is_marked_rollback(self):
67 d55d4f34 Giorgos Korfiatis
        return self._rollback
68 d55d4f34 Giorgos Korfiatis
69 d55d4f34 Giorgos Korfiatis
    def postprocess(self):
70 d55d4f34 Giorgos Korfiatis
        pass
71 d55d4f34 Giorgos Korfiatis
72 d55d4f34 Giorgos Korfiatis
class TransactionHandler(object):
73 d55d4f34 Giorgos Korfiatis
74 d55d4f34 Giorgos Korfiatis
    def __init__(self, ctx=None, using=None, **kwargs):
75 d55d4f34 Giorgos Korfiatis
        self.db        = (using if using is not None
76 d55d4f34 Giorgos Korfiatis
                          else transaction.DEFAULT_DB_ALIAS)
77 d55d4f34 Giorgos Korfiatis
        self.ctx_class  = ctx
78 d55d4f34 Giorgos Korfiatis
        self.ctx_kwargs = kwargs
79 d55d4f34 Giorgos Korfiatis
80 d55d4f34 Giorgos Korfiatis
    def __call__(self, func):
81 d55d4f34 Giorgos Korfiatis
        def wrap(*args, **kwargs):
82 d55d4f34 Giorgos Korfiatis
            ctx = self.__enter__()
83 d55d4f34 Giorgos Korfiatis
            kwargs['ctx'] = ctx
84 d55d4f34 Giorgos Korfiatis
            typ = value = trace = None
85 d55d4f34 Giorgos Korfiatis
            result = None
86 d55d4f34 Giorgos Korfiatis
            try:
87 d55d4f34 Giorgos Korfiatis
                result = func(*args, **kwargs)
88 d55d4f34 Giorgos Korfiatis
            except Exception as e:
89 d55d4f34 Giorgos Korfiatis
                typ = type(e)
90 d55d4f34 Giorgos Korfiatis
                value = e
91 d55d4f34 Giorgos Korfiatis
                trace = None
92 d55d4f34 Giorgos Korfiatis
            finally:
93 d55d4f34 Giorgos Korfiatis
                silent = self.__exit__(typ, value, trace)
94 d55d4f34 Giorgos Korfiatis
                if not silent and value:
95 d55d4f34 Giorgos Korfiatis
                    raise value
96 d55d4f34 Giorgos Korfiatis
            return result
97 d55d4f34 Giorgos Korfiatis
        return wrap
98 d55d4f34 Giorgos Korfiatis
99 d55d4f34 Giorgos Korfiatis
    def __enter__(self):
100 d55d4f34 Giorgos Korfiatis
        db = self.db
101 d55d4f34 Giorgos Korfiatis
        transaction.enter_transaction_management(using=db)
102 d55d4f34 Giorgos Korfiatis
        transaction.managed(True, using=db)
103 d55d4f34 Giorgos Korfiatis
        self.ctx = self.ctx_class(self.ctx_kwargs)
104 d55d4f34 Giorgos Korfiatis
        return self.ctx
105 d55d4f34 Giorgos Korfiatis
106 d55d4f34 Giorgos Korfiatis
    def __exit__(self, type, value, traceback):
107 d55d4f34 Giorgos Korfiatis
        db = self.db
108 d55d4f34 Giorgos Korfiatis
        try:
109 d55d4f34 Giorgos Korfiatis
            if value is not None: # exception
110 d55d4f34 Giorgos Korfiatis
                if transaction.is_dirty(using=db):
111 d55d4f34 Giorgos Korfiatis
                    transaction.rollback(using=db)
112 d55d4f34 Giorgos Korfiatis
            else:
113 d55d4f34 Giorgos Korfiatis
                if transaction.is_dirty(using=db):
114 d55d4f34 Giorgos Korfiatis
                    if self.ctx.is_marked_rollback():
115 d55d4f34 Giorgos Korfiatis
                        transaction.rollback(using=db)
116 d55d4f34 Giorgos Korfiatis
                    else:
117 d55d4f34 Giorgos Korfiatis
                        try:
118 d55d4f34 Giorgos Korfiatis
                            transaction.commit(using=db)
119 d55d4f34 Giorgos Korfiatis
                        except:
120 d55d4f34 Giorgos Korfiatis
                            transaction.rollback(using=db)
121 d55d4f34 Giorgos Korfiatis
                            raise
122 d55d4f34 Giorgos Korfiatis
                        else:
123 d55d4f34 Giorgos Korfiatis
                            self.ctx.postprocess()
124 d55d4f34 Giorgos Korfiatis
        finally:
125 d55d4f34 Giorgos Korfiatis
            transaction.leave_transaction_management(using=db)