diff --git a/lib/locking.py b/lib/locking.py index e28f2f0b1128542629cc73a01f4d121e00ce263e..09c0b4ad2777f433ce86ad5c88d51ccd436828bf 100644 --- a/lib/locking.py +++ b/lib/locking.py @@ -1033,6 +1033,18 @@ class LockSet: else: return False + def owning_all(self): + """Checks whether current thread owns internal lock. + + Holding the internal lock is equivalent with holding all locks in the set + (the opposite does not necessarily hold as it can not be easily + determined). L{add} and L{remove} require the internal lock. + + @rtype: boolean + + """ + return self.__lock.is_owned() + def _add_owned(self, name=None): """Note the current thread owns the given lock""" if name is None: @@ -1620,6 +1632,14 @@ class GanetiLockManager: """ return self.__keyring[level].check_owned(names, shared=shared) + def owning_all(self, level): + """Checks whether current thread owns all locks at a certain level. + + @see: L{LockSet.owning_all} + + """ + return self.__keyring[level].owning_all() + def _upper_owned(self, level): """Check that we don't own any lock at a level greater than the given one. diff --git a/test/ganeti.locking_unittest.py b/test/ganeti.locking_unittest.py index 04b46fce05eb9545550256359752d47abc312c2b..6863d6d90ce77000a132d770ca300ab27c6ef7f6 100755 --- a/test/ganeti.locking_unittest.py +++ b/test/ganeti.locking_unittest.py @@ -1606,6 +1606,7 @@ class TestLockSet(_ThreadedTestCase): self.assertEqual(self.ls.acquire(None), set(["one", "two", "three"])) # now empty it... self.ls.remove(["one", "two", "three"]) + self.assertFalse(self.ls._names()) # and adds/locks by another thread still wait self._addThread(target=self._doAddSet, args=(["nine"])) self._addThread(target=self._doLockSet, args=(None, 1)) @@ -1713,6 +1714,7 @@ class TestLockSet(_ThreadedTestCase): def testDowngradeEverything(self): self.assertEqual(self.ls.acquire(locking.ALL_SET, shared=0), set(["one", "two", "three"])) + self.assertTrue(self.ls.owning_all()) # Ensure all locks are now owned in exclusive mode for name in self.ls._names(): @@ -1725,6 +1727,8 @@ class TestLockSet(_ThreadedTestCase): for name in self.ls._names(): self.assertTrue(self.ls.check_owned(name, shared=1)) + self.assertTrue(self.ls.owning_all()) + def testPriority(self): def _Acquire(prev, next, name, priority, success_fn): prev.wait() @@ -1890,12 +1894,16 @@ class TestGanetiLockManager(_ThreadedTestCase): set(self.nodes)) self.assertEquals(self.GL.list_owned(locking.LEVEL_NODE), set(self.nodes)) + self.assertTrue(self.GL.owning_all(locking.LEVEL_INSTANCE)) + self.assertTrue(self.GL.owning_all(locking.LEVEL_NODEGROUP)) + self.assertTrue(self.GL.owning_all(locking.LEVEL_NODE)) self.GL.release(locking.LEVEL_NODE) self.GL.release(locking.LEVEL_NODEGROUP) self.GL.release(locking.LEVEL_INSTANCE) self.GL.release(locking.LEVEL_CLUSTER) def testAcquireWholeAndPartial(self): + self.assertFalse(self.GL.owning_all(locking.LEVEL_INSTANCE)) self.GL.acquire(locking.LEVEL_CLUSTER, ["BGL"], shared=1) self.assertEquals(self.GL.acquire(locking.LEVEL_INSTANCE, None), set(self.instances)) @@ -1905,6 +1913,8 @@ class TestGanetiLockManager(_ThreadedTestCase): set(["n2"])) self.assertEquals(self.GL.list_owned(locking.LEVEL_NODE), set(["n2"])) + self.assertTrue(self.GL.owning_all(locking.LEVEL_INSTANCE)) + self.assertFalse(self.GL.owning_all(locking.LEVEL_NODE)) self.GL.release(locking.LEVEL_NODE) self.GL.release(locking.LEVEL_INSTANCE) self.GL.release(locking.LEVEL_CLUSTER)