~ubuntu-branches/ubuntu/utopic/maas/utopic-updates

« back to all changes in this revision

Viewing changes to src/maasserver/utils/dblocks.py

  • Committer: Package Import Robot
  • Author(s): Julian Edwards, Julian Edwards, Andres Rodriguez
  • Date: 2014-08-21 18:38:27 UTC
  • mfrom: (1.2.34)
  • Revision ID: package-import@ubuntu.com-20140821183827-9xyb5u2o4l8g3zxj
Tags: 1.6.1+bzr2550-0ubuntu1
* New upstream bugfix release:
  - Auto-link node MACs to Networks (LP: #1341619)

[ Julian Edwards ]
* debian/maas-region-controller.postinst: Don't restart RabbitMQ on
  upgrades, just ensure it's running.  Should prevent a race with the
  cluster celery restarting.
* debian/rules: Pull upstream branch from the right place.

[ Andres Rodriguez ]
* debian/maas-region-controller.postinst: Ensure cluster celery is
  started if it also runs on the region.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
__metaclass__ = type
15
15
__all__ = [
16
16
    "DatabaseLock",
 
17
    "DatabaseLockAttemptOutsideTransaction",
 
18
    "DatabaseLockNotHeld",
17
19
]
18
20
 
19
21
from contextlib import closing
26
28
classid = 20120116
27
29
 
28
30
 
 
31
class DatabaseLockAttemptOutsideTransaction(Exception):
 
32
    """A locking attempt was made outside of a transaction.
 
33
 
 
34
    :class:`DatabaseLock` should only be used within a transaction.
 
35
    Django agressively closes connections outside of atomic blocks to
 
36
    the extent that session-level locks are rendered unreliable at best.
 
37
    """
 
38
 
 
39
 
 
40
class DatabaseLockNotHeld(Exception):
 
41
    """A particular lock was not held."""
 
42
 
 
43
 
29
44
class DatabaseLock(tuple):
30
45
    """An advisory lock held in the database.
31
46
 
58
73
        return super(cls, DatabaseLock).__new__(cls, (classid, objid))
59
74
 
60
75
    def __enter__(self):
 
76
        if not connection.in_atomic_block:
 
77
            raise DatabaseLockAttemptOutsideTransaction(self)
61
78
        with closing(connection.cursor()) as cursor:
62
79
            cursor.execute("SELECT pg_advisory_lock(%s, %s)", self)
63
80
 
64
81
    def __exit__(self, *exc_info):
65
82
        with closing(connection.cursor()) as cursor:
66
83
            cursor.execute("SELECT pg_advisory_unlock(%s, %s)", self)
 
84
            if cursor.fetchone() != (True,):
 
85
                raise DatabaseLockNotHeld(self)
67
86
 
68
87
    def __repr__(self):
69
88
        return b"<%s classid=%d objid=%d>" % (
71
90
 
72
91
    def is_locked(self):
73
92
        stmt = (
74
 
            "SELECT 1 FROM pg_locks"
75
 
            " WHERE classid = %s AND objid = %s AND granted"
 
93
            "SELECT 1 FROM pg_locks, pg_database"
 
94
            " WHERE pg_locks.locktype = 'advisory'"
 
95
            "   AND pg_locks.classid = %s"
 
96
            "   AND pg_locks.objid = %s"
 
97
            # objsubid is 2 when using the 2-argument version of the
 
98
            # pg_advisory_* locking functions.
 
99
            "   AND pg_locks.objsubid = 2"
 
100
            "   AND pg_locks.granted"
 
101
            # Advisory locks are local to each database so we join to
 
102
            # pg_databases to discover the OID of the currrent database.
 
103
            "   AND pg_locks.database = pg_database.oid"
 
104
            "   AND pg_database.datname = current_database()"
76
105
        )
77
106
        with closing(connection.cursor()) as cursor:
78
107
            cursor.execute(stmt, self)