From 8716b1dbd09263172495f65735bd109d4b99ac03 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann <hansmi@google.com> Date: Thu, 22 Nov 2012 22:41:44 +0100 Subject: [PATCH] Add new lock level for node allocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new lock is similar to the BGL in the sense that it has its own level and there is only one. It is called βnode allocation lockβ. Logical units will use it to synchronize with instance creations, which in turn will start using opportunistic locks on nodes. Additionally, an assertion in GanetiLockManager gained a message. Signed-off-by: Michael Hanselmann <hansmi@google.com> Reviewed-by: Guido Trotter <ultrotter@google.com> --- lib/locking.py | 49 +++++++++++++++++++++------------ test/ganeti.locking_unittest.py | 7 +++++ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/lib/locking.py b/lib/locking.py index 5a02fd5d4..e28f2f0b1 100644 --- a/lib/locking.py +++ b/lib/locking.py @@ -1467,26 +1467,33 @@ class LockSet: return removed -# Locking levels, must be acquired in increasing order. -# Current rules are: -# - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be -# acquired before performing any operation, either in shared or in exclusive -# mode. acquiring the BGL in exclusive mode is discouraged and should be -# avoided. -# - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks. -# If you need more than one node, or more than one instance, acquire them at -# the same time. -LEVEL_CLUSTER = 0 -LEVEL_INSTANCE = 1 -LEVEL_NODEGROUP = 2 -LEVEL_NODE = 3 -#: Level for node resources, used for operations with possibly high impact on -#: the node's disks. -LEVEL_NODE_RES = 4 -LEVEL_NETWORK = 5 +# Locking levels, must be acquired in increasing order. Current rules are: +# - At level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be +# acquired before performing any operation, either in shared or exclusive +# mode. Acquiring the BGL in exclusive mode is discouraged and should be +# avoided.. +# - At levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks. If +# you need more than one node, or more than one instance, acquire them at the +# same time. +# - LEVEL_NODE_RES is for node resources and should be used by operations with +# possibly high impact on the node's disks. +# - LEVEL_NODE_ALLOC blocks instance allocations for the whole cluster +# ("NAL" is the only lock at this level). It should be acquired in shared +# mode when an opcode blocks all or a significant amount of a cluster's +# locks. Opcodes doing instance allocations should acquire in exclusive mode. +# Once the set of acquired locks for an opcode has been reduced to the working +# set, the NAL should be released as well to allow allocations to proceed. +(LEVEL_CLUSTER, + LEVEL_NODE_ALLOC, + LEVEL_INSTANCE, + LEVEL_NODEGROUP, + LEVEL_NODE, + LEVEL_NODE_RES, + LEVEL_NETWORK) = range(0, 7) LEVELS = [ LEVEL_CLUSTER, + LEVEL_NODE_ALLOC, LEVEL_INSTANCE, LEVEL_NODEGROUP, LEVEL_NODE, @@ -1511,11 +1518,15 @@ LEVEL_NAMES = { LEVEL_NODE: "node", LEVEL_NODE_RES: "node-res", LEVEL_NETWORK: "network", + LEVEL_NODE_ALLOC: "node-alloc", } # Constant for the big ganeti lock BGL = "BGL" +#: Node allocation lock +NAL = "NAL" + class GanetiLockManager: """The Ganeti Locking Library @@ -1555,10 +1566,12 @@ class GanetiLockManager: LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroup", monitor=self._monitor), LEVEL_INSTANCE: LockSet(instances, "instance", monitor=self._monitor), LEVEL_NETWORK: LockSet(networks, "network", monitor=self._monitor), + LEVEL_NODE_ALLOC: LockSet([NAL], "node-alloc", monitor=self._monitor), } assert compat.all(ls.name == LEVEL_NAMES[level] - for (level, ls) in self.__keyring.items()) + for (level, ls) in self.__keyring.items()), \ + "Keyring name mismatch" def AddToLockMonitor(self, provider): """Registers a new lock with the monitor. diff --git a/test/ganeti.locking_unittest.py b/test/ganeti.locking_unittest.py index 45c8f6d46..04b46fce0 100755 --- a/test/ganeti.locking_unittest.py +++ b/test/ganeti.locking_unittest.py @@ -1804,6 +1804,7 @@ class TestGanetiLockManager(_ThreadedTestCase): def testLockNames(self): self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(["BGL"])) + self.assertEqual(self.GL._names(locking.LEVEL_NODE_ALLOC), set(["NAL"])) self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes)) self.assertEqual(self.GL._names(locking.LEVEL_NODEGROUP), set(self.nodegroups)) @@ -1816,6 +1817,7 @@ class TestGanetiLockManager(_ThreadedTestCase): locking.GanetiLockManager._instance = None self.GL = locking.GanetiLockManager([], [], [], []) self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(["BGL"])) + self.assertEqual(self.GL._names(locking.LEVEL_NODE_ALLOC), set(["NAL"])) self.assertEqual(self.GL._names(locking.LEVEL_NODE), set()) self.assertEqual(self.GL._names(locking.LEVEL_NODEGROUP), set()) self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set()) @@ -1824,6 +1826,7 @@ class TestGanetiLockManager(_ThreadedTestCase): locking.GanetiLockManager._instance = None self.GL = locking.GanetiLockManager(self.nodes, self.nodegroups, [], []) self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(["BGL"])) + self.assertEqual(self.GL._names(locking.LEVEL_NODE_ALLOC), set(["NAL"])) self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes)) self.assertEqual(self.GL._names(locking.LEVEL_NODEGROUP), set(self.nodegroups)) @@ -1833,6 +1836,7 @@ class TestGanetiLockManager(_ThreadedTestCase): locking.GanetiLockManager._instance = None self.GL = locking.GanetiLockManager([], [], self.instances, []) self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(["BGL"])) + self.assertEqual(self.GL._names(locking.LEVEL_NODE_ALLOC), set(["NAL"])) self.assertEqual(self.GL._names(locking.LEVEL_NODE), set()) self.assertEqual(self.GL._names(locking.LEVEL_NODEGROUP), set()) self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), @@ -1841,6 +1845,7 @@ class TestGanetiLockManager(_ThreadedTestCase): locking.GanetiLockManager._instance = None self.GL = locking.GanetiLockManager([], [], [], self.networks) self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(["BGL"])) + self.assertEqual(self.GL._names(locking.LEVEL_NODE_ALLOC), set(["NAL"])) self.assertEqual(self.GL._names(locking.LEVEL_NODE), set()) self.assertEqual(self.GL._names(locking.LEVEL_NODEGROUP), set()) self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set()) @@ -1946,6 +1951,8 @@ class TestGanetiLockManager(_ThreadedTestCase): def testModifiableLevels(self): self.assertRaises(AssertionError, self.GL.add, locking.LEVEL_CLUSTER, ["BGL2"]) + self.assertRaises(AssertionError, self.GL.add, locking.LEVEL_NODE_ALLOC, + ["NAL2"]) self.GL.acquire(locking.LEVEL_CLUSTER, ["BGL"]) self.GL.add(locking.LEVEL_INSTANCE, ["i4"]) self.GL.remove(locking.LEVEL_INSTANCE, ["i3"]) -- GitLab