Commit ee2b99e3 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

locking: Make some aliased methods public



Some methods, such as “_is_owned” and “list_owned”, have been aliased to
make them public for a while now. This patch makes the actual
implementation public.

SharedLock's “is_owned” needs to be aliased to “_is_owned” to remain
compatible with Python's built-in threaded.Condition class.
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent 63e6a7f6
......@@ -161,7 +161,7 @@ class _BaseCondition(object):
except AttributeError:
self._acquire_restore = self._base_acquire_restore
try:
self._is_owned = lock._is_owned
self._is_owned = lock.is_owned
except AttributeError:
self._is_owned = self._base_is_owned
......@@ -526,7 +526,7 @@ class SharedLock(object):
else:
return self.__is_exclusive()
def _is_owned(self, shared=-1):
def is_owned(self, shared=-1):
"""Is the current thread somehow owning the lock at this time?
@param shared:
......@@ -541,7 +541,9 @@ class SharedLock(object):
finally:
self.__lock.release()
is_owned = _is_owned
#: Necessary to remain compatible with threading.Condition, which tries to
#: retrieve a locks' "_is_owned" attribute
_is_owned = is_owned
def _count_pending(self):
"""Returns the number of pending acquires.
......@@ -940,17 +942,17 @@ class LockSet:
"""
return self.__lockdict
def _is_owned(self):
def is_owned(self):
"""Is the current thread a current level owner?"""
return threading.currentThread() in self.__owners
def _add_owned(self, name=None):
"""Note the current thread owns the given lock"""
if name is None:
if not self._is_owned():
if not self.is_owned():
self.__owners[threading.currentThread()] = set()
else:
if self._is_owned():
if self.is_owned():
self.__owners[threading.currentThread()].add(name)
else:
self.__owners[threading.currentThread()] = set([name])
......@@ -958,29 +960,29 @@ class LockSet:
def _del_owned(self, name=None):
"""Note the current thread owns the given lock"""
assert not (name is None and self.__lock._is_owned()), \
assert not (name is None and self.__lock.is_owned()), \
"Cannot hold internal lock when deleting owner status"
if name is not None:
self.__owners[threading.currentThread()].remove(name)
# Only remove the key if we don't hold the set-lock as well
if (not self.__lock._is_owned() and
if (not self.__lock.is_owned() and
not self.__owners[threading.currentThread()]):
del self.__owners[threading.currentThread()]
def _list_owned(self):
def list_owned(self):
"""Get the set of resource names owned by the current thread"""
if self._is_owned():
if self.is_owned():
return self.__owners[threading.currentThread()].copy()
else:
return set()
def _release_and_delete_owned(self):
"""Release and delete all resources owned by the current thread"""
for lname in self._list_owned():
for lname in self.list_owned():
lock = self.__lockdict[lname]
if lock._is_owned():
if lock.is_owned():
lock.release()
self._del_owned(name=lname)
......@@ -1002,7 +1004,7 @@ class LockSet:
# If we don't already own the set-level lock acquired
# we'll get it and note we need to release it later.
release_lock = False
if not self.__lock._is_owned():
if not self.__lock.is_owned():
release_lock = True
self.__lock.acquire(shared=1)
try:
......@@ -1039,8 +1041,8 @@ class LockSet:
assert timeout is None or timeout >= 0.0
# Check we don't already own locks at this level
assert not self._is_owned(), ("Cannot acquire locks in the same set twice"
" (lockset %s)" % self.name)
assert not self.is_owned(), ("Cannot acquire locks in the same set twice"
" (lockset %s)" % self.name)
if priority is None:
priority = _DEFAULT_PRIORITY
......@@ -1170,7 +1172,7 @@ class LockSet:
# We shouldn't have problems adding the lock to the owners list, but
# if we did we'll try to release this lock and re-raise exception.
# Of course something is going to be really wrong after this.
if lock._is_owned():
if lock.is_owned():
lock.release()
raise
......@@ -1187,14 +1189,14 @@ class LockSet:
The locks must have been acquired in exclusive mode.
"""
assert self._is_owned(), ("downgrade on lockset %s while not owning any"
" lock" % self.name)
assert self.is_owned(), ("downgrade on lockset %s while not owning any"
" lock" % self.name)
# Support passing in a single resource to downgrade rather than many
if isinstance(names, basestring):
names = [names]
owned = self._list_owned()
owned = self.list_owned()
if names is None:
names = owned
......@@ -1208,12 +1210,12 @@ class LockSet:
self.__lockdict[lockname].downgrade()
# Do we own the lockset in exclusive mode?
if self.__lock._is_owned(shared=0):
if self.__lock.is_owned(shared=0):
# Have all locks been downgraded?
if not compat.any(lock._is_owned(shared=0)
if not compat.any(lock.is_owned(shared=0)
for lock in self.__lockdict.values()):
self.__lock.downgrade()
assert self.__lock._is_owned(shared=1)
assert self.__lock.is_owned(shared=1)
return True
......@@ -1228,24 +1230,24 @@ class LockSet:
(defaults to all the locks acquired at that level).
"""
assert self._is_owned(), ("release() on lock set %s while not owner" %
self.name)
assert self.is_owned(), ("release() on lock set %s while not owner" %
self.name)
# Support passing in a single resource to release rather than many
if isinstance(names, basestring):
names = [names]
if names is None:
names = self._list_owned()
names = self.list_owned()
else:
names = set(names)
assert self._list_owned().issuperset(names), (
assert self.list_owned().issuperset(names), (
"release() on unheld resources %s (set %s)" %
(names.difference(self._list_owned()), self.name))
(names.difference(self.list_owned()), self.name))
# First of all let's release the "all elements" lock, if set.
# After this 'add' can work again
if self.__lock._is_owned():
if self.__lock.is_owned():
self.__lock.release()
self._del_owned()
......@@ -1267,7 +1269,7 @@ class LockSet:
"""
# Check we don't already own locks at this level
assert not self._is_owned() or self.__lock._is_owned(shared=0), \
assert not self.is_owned() or self.__lock.is_owned(shared=0), \
("Cannot add locks if the set %s is only partially owned, or shared" %
self.name)
......@@ -1278,7 +1280,7 @@ class LockSet:
# If we don't already own the set-level lock acquired in an exclusive way
# we'll get it and note we need to release it later.
release_lock = False
if not self.__lock._is_owned():
if not self.__lock.is_owned():
release_lock = True
self.__lock.acquire()
......@@ -1341,7 +1343,7 @@ class LockSet:
# If we own any subset of this lock it must be a superset of what we want
# to delete. The ownership must also be exclusive, but that will be checked
# by the lock itself.
assert not self._is_owned() or self._list_owned().issuperset(names), (
assert not self.is_owned() or self.list_owned().issuperset(names), (
"remove() on acquired lockset %s while not owning all elements" %
self.name)
......@@ -1358,8 +1360,8 @@ class LockSet:
removed.append(lname)
except (KeyError, errors.LockError):
# This cannot happen if we were already holding it, verify:
assert not self._is_owned(), ("remove failed while holding lockset %s"
% self.name)
assert not self.is_owned(), ("remove failed while holding lockset %s" %
self.name)
else:
# If no LockError was raised we are the ones who deleted the lock.
# This means we can safely remove it from lockdict, as any further or
......@@ -1370,7 +1372,7 @@ class LockSet:
# it's the job of the one who actually deleted it.
del self.__lockdict[lname]
# And let's remove it from our private list if we owned it.
if self._is_owned():
if self.is_owned():
self._del_owned(name=lname)
return removed
......@@ -1498,21 +1500,17 @@ class GanetiLockManager:
assert level in LEVELS, "Invalid locking level %s" % level
return self.__keyring[level]._names()
def _is_owned(self, level):
def is_owned(self, level):
"""Check whether we are owning locks at the given level
"""
return self.__keyring[level]._is_owned()
return self.__keyring[level].is_owned()
is_owned = _is_owned
def _list_owned(self, level):
def list_owned(self, level):
"""Get the set of owned locks at the given level
"""
return self.__keyring[level]._list_owned()
list_owned = _list_owned
return self.__keyring[level].list_owned()
def _upper_owned(self, level):
"""Check that we don't own any lock at a level greater than the given one.
......@@ -1520,7 +1518,7 @@ class GanetiLockManager:
"""
# This way of checking only works if LEVELS[i] = i, which we check for in
# the test cases.
return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
return compat.any((self.is_owned(l) for l in LEVELS[level + 1:]))
def _BGL_owned(self): # pylint: disable=C0103
"""Check if the current thread owns the BGL.
......@@ -1528,7 +1526,7 @@ class GanetiLockManager:
Both an exclusive or a shared acquisition work.
"""
return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
return BGL in self.__keyring[LEVEL_CLUSTER].list_owned()
@staticmethod
def _contains_BGL(level, names): # pylint: disable=C0103
......@@ -1610,7 +1608,7 @@ class GanetiLockManager:
not self._upper_owned(LEVEL_CLUSTER)), (
"Cannot release the Big Ganeti Lock while holding something"
" at upper levels (%r)" %
(utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
(utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self.list_owned(i))
for i in self.__keyring.keys()]), ))
# Release will complain if we don't own the locks already
......@@ -1655,7 +1653,7 @@ class GanetiLockManager:
# Check we either own the level or don't own anything from here
# up. LockSet.remove() will check the case in which we don't own
# all the needed resources, or we have a shared ownership.
assert self._is_owned(level) or not self._upper_owned(level), (
assert self.is_owned(level) or not self._upper_owned(level), (
"Cannot remove locks at a level while not owning it or"
" owning some at a greater one")
return self.__keyring[level].remove(names)
......
......@@ -269,25 +269,25 @@ class TestSharedLock(_ThreadedTestCase):
self.sl = locking.SharedLock("TestSharedLock")
def testSequenceAndOwnership(self):
self.assertFalse(self.sl._is_owned())
self.assertFalse(self.sl.is_owned())
self.sl.acquire(shared=1)
self.assert_(self.sl._is_owned())
self.assert_(self.sl._is_owned(shared=1))
self.assertFalse(self.sl._is_owned(shared=0))
self.assert_(self.sl.is_owned())
self.assert_(self.sl.is_owned(shared=1))
self.assertFalse(self.sl.is_owned(shared=0))
self.sl.release()
self.assertFalse(self.sl._is_owned())
self.assertFalse(self.sl.is_owned())
self.sl.acquire()
self.assert_(self.sl._is_owned())
self.assertFalse(self.sl._is_owned(shared=1))
self.assert_(self.sl._is_owned(shared=0))
self.assert_(self.sl.is_owned())
self.assertFalse(self.sl.is_owned(shared=1))
self.assert_(self.sl.is_owned(shared=0))
self.sl.release()
self.assertFalse(self.sl._is_owned())
self.assertFalse(self.sl.is_owned())
self.sl.acquire(shared=1)
self.assert_(self.sl._is_owned())
self.assert_(self.sl._is_owned(shared=1))
self.assertFalse(self.sl._is_owned(shared=0))
self.assert_(self.sl.is_owned())
self.assert_(self.sl.is_owned(shared=1))
self.assertFalse(self.sl.is_owned(shared=0))
self.sl.release()
self.assertFalse(self.sl._is_owned())
self.assertFalse(self.sl.is_owned())
def testBooleanValue(self):
# semaphores are supposed to return a true value on a successful acquire
......@@ -618,45 +618,45 @@ class TestSharedLock(_ThreadedTestCase):
# Acquire in shared mode, downgrade should be no-op
self.assertTrue(self.sl.acquire(shared=1))
self.assertTrue(self.sl._is_owned(shared=1))
self.assertTrue(self.sl.is_owned(shared=1))
self.assertTrue(self.sl.downgrade())
self.assertTrue(self.sl._is_owned(shared=1))
self.assertTrue(self.sl.is_owned(shared=1))
self.sl.release()
def testDowngrade(self):
self.assertTrue(self.sl.acquire())
self.assertTrue(self.sl._is_owned(shared=0))
self.assertTrue(self.sl.is_owned(shared=0))
self.assertTrue(self.sl.downgrade())
self.assertTrue(self.sl._is_owned(shared=1))
self.assertTrue(self.sl.is_owned(shared=1))
self.sl.release()
@_Repeat
def testDowngradeJumpsAheadOfExclusive(self):
def _KeepExclusive(ev_got, ev_downgrade, ev_release):
self.assertTrue(self.sl.acquire())
self.assertTrue(self.sl._is_owned(shared=0))
self.assertTrue(self.sl.is_owned(shared=0))
ev_got.set()
ev_downgrade.wait()
self.assertTrue(self.sl._is_owned(shared=0))
self.assertTrue(self.sl.is_owned(shared=0))
self.assertTrue(self.sl.downgrade())
self.assertTrue(self.sl._is_owned(shared=1))
self.assertTrue(self.sl.is_owned(shared=1))
ev_release.wait()
self.assertTrue(self.sl._is_owned(shared=1))
self.assertTrue(self.sl.is_owned(shared=1))
self.sl.release()
def _KeepExclusive2(ev_started, ev_release):
self.assertTrue(self.sl.acquire(test_notify=ev_started.set))
self.assertTrue(self.sl._is_owned(shared=0))
self.assertTrue(self.sl.is_owned(shared=0))
ev_release.wait()
self.assertTrue(self.sl._is_owned(shared=0))
self.assertTrue(self.sl.is_owned(shared=0))
self.sl.release()
def _KeepShared(ev_started, ev_got, ev_release):
self.assertTrue(self.sl.acquire(shared=1, test_notify=ev_started.set))
self.assertTrue(self.sl._is_owned(shared=1))
self.assertTrue(self.sl.is_owned(shared=1))
ev_got.set()
ev_release.wait()
self.assertTrue(self.sl._is_owned(shared=1))
self.assertTrue(self.sl.is_owned(shared=1))
self.sl.release()
# Acquire lock in exclusive mode
......@@ -943,14 +943,14 @@ class TestSharedLockInCondition(_ThreadedTestCase):
def testKeepMode(self):
self.cond.acquire(shared=1)
self.assert_(self.sl._is_owned(shared=1))
self.assert_(self.sl.is_owned(shared=1))
self.cond.wait(0)
self.assert_(self.sl._is_owned(shared=1))
self.assert_(self.sl.is_owned(shared=1))
self.cond.release()
self.cond.acquire(shared=0)
self.assert_(self.sl._is_owned(shared=0))
self.assert_(self.sl.is_owned(shared=0))
self.cond.wait(0)
self.assert_(self.sl._is_owned(shared=0))
self.assert_(self.sl.is_owned(shared=0))
self.cond.release()
......@@ -969,19 +969,19 @@ class TestSSynchronizedDecorator(_ThreadedTestCase):
@locking.ssynchronized(_decoratorlock)
def _doItExclusive(self):
self.assert_(_decoratorlock._is_owned())
self.assert_(_decoratorlock.is_owned())
self.done.put('EXC')
@locking.ssynchronized(_decoratorlock, shared=1)
def _doItSharer(self):
self.assert_(_decoratorlock._is_owned(shared=1))
self.assert_(_decoratorlock.is_owned(shared=1))
self.done.put('SHR')
def testDecoratedFunctions(self):
self._doItExclusive()
self.assertFalse(_decoratorlock._is_owned())
self.assertFalse(_decoratorlock.is_owned())
self._doItSharer()
self.assertFalse(_decoratorlock._is_owned())
self.assertFalse(_decoratorlock.is_owned())
def testSharersCanCoexist(self):
_decoratorlock.acquire(shared=1)
......@@ -1037,25 +1037,25 @@ class TestLockSet(_ThreadedTestCase):
def testAcquireRelease(self):
self.assert_(self.ls.acquire('one'))
self.assertEquals(self.ls._list_owned(), set(['one']))
self.assertEquals(self.ls.list_owned(), set(['one']))
self.ls.release()
self.assertEquals(self.ls._list_owned(), set())
self.assertEquals(self.ls.list_owned(), set())
self.assertEquals(self.ls.acquire(['one']), set(['one']))
self.assertEquals(self.ls._list_owned(), set(['one']))
self.assertEquals(self.ls.list_owned(), set(['one']))
self.ls.release()
self.assertEquals(self.ls._list_owned(), set())
self.assertEquals(self.ls.list_owned(), set())
self.ls.acquire(['one', 'two', 'three'])
self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
self.assertEquals(self.ls.list_owned(), set(['one', 'two', 'three']))
self.ls.release('one')
self.assertEquals(self.ls._list_owned(), set(['two', 'three']))
self.assertEquals(self.ls.list_owned(), set(['two', 'three']))
self.ls.release(['three'])
self.assertEquals(self.ls._list_owned(), set(['two']))
self.assertEquals(self.ls.list_owned(), set(['two']))
self.ls.release()
self.assertEquals(self.ls._list_owned(), set())
self.assertEquals(self.ls.list_owned(), set())
self.assertEquals(self.ls.acquire(['one', 'three']), set(['one', 'three']))
self.assertEquals(self.ls._list_owned(), set(['one', 'three']))
self.assertEquals(self.ls.list_owned(), set(['one', 'three']))
self.ls.release()
self.assertEquals(self.ls._list_owned(), set())
self.assertEquals(self.ls.list_owned(), set())
def testNoDoubleAcquire(self):
self.ls.acquire('one')
......@@ -1075,31 +1075,31 @@ class TestLockSet(_ThreadedTestCase):
def testAddRemove(self):
self.ls.add('four')
self.assertEquals(self.ls._list_owned(), set())
self.assertEquals(self.ls.list_owned(), set())
self.assert_('four' in self.ls._names())
self.ls.add(['five', 'six', 'seven'], acquired=1)
self.assert_('five' in self.ls._names())
self.assert_('six' in self.ls._names())
self.assert_('seven' in self.ls._names())
self.assertEquals(self.ls._list_owned(), set(['five', 'six', 'seven']))
self.assertEquals(self.ls.list_owned(), set(['five', 'six', 'seven']))
self.assertEquals(self.ls.remove(['five', 'six']), ['five', 'six'])
self.assert_('five' not in self.ls._names())
self.assert_('six' not in self.ls._names())
self.assertEquals(self.ls._list_owned(), set(['seven']))
self.assertEquals(self.ls.list_owned(), set(['seven']))
self.assertRaises(AssertionError, self.ls.add, 'eight', acquired=1)
self.ls.remove('seven')
self.assert_('seven' not in self.ls._names())
self.assertEquals(self.ls._list_owned(), set([]))
self.assertEquals(self.ls.list_owned(), set([]))
self.ls.acquire(None, shared=1)
self.assertRaises(AssertionError, self.ls.add, 'eight')
self.ls.release()
self.ls.acquire(None)
self.ls.add('eight', acquired=1)
self.assert_('eight' in self.ls._names())
self.assert_('eight' in self.ls._list_owned())
self.assert_('eight' in self.ls.list_owned())
self.ls.add('nine')
self.assert_('nine' in self.ls._names())
self.assert_('nine' not in self.ls._list_owned())
self.assert_('nine' not in self.ls.list_owned())
self.ls.release()
self.ls.remove(['two'])
self.assert_('two' not in self.ls._names())
......@@ -1132,8 +1132,8 @@ class TestLockSet(_ThreadedTestCase):
def testAcquireSetLock(self):
# acquire the set-lock exclusively
self.assertEquals(self.ls.acquire(None), set(['one', 'two', 'three']))
self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
self.assertEquals(self.ls._is_owned(), True)
self.assertEquals(self.ls.list_owned(), set(['one', 'two', 'three']))
self.assertEquals(self.ls.is_owned(), True)
self.assertEquals(self.ls._names(), set(['one', 'two', 'three']))
# I can still add/remove elements...
self.assertEquals(self.ls.remove(['two', 'three']), ['two', 'three'])
......@@ -1149,17 +1149,17 @@ class TestLockSet(_ThreadedTestCase):
self.assertEquals(self.ls.acquire(['two', 'two', 'three'], shared=1),
set(['two', 'two', 'three']))
self.ls.release(['two', 'two'])
self.assertEquals(self.ls._list_owned(), set(['three']))
self.assertEquals(self.ls.list_owned(), set(['three']))
def testEmptyAcquire(self):
# Acquire an empty list of locks...
self.assertEquals(self.ls.acquire([]), set())
self.assertEquals(self.ls._list_owned(), set())
self.assertEquals(self.ls.list_owned(), set())
# New locks can still be addded
self.assert_(self.ls.add('six'))
# "re-acquiring" is not an issue, since we had really acquired nothing
self.assertEquals(self.ls.acquire([], shared=1), set())
self.assertEquals(self.ls._list_owned(), set())
self.assertEquals(self.ls.list_owned(), set())
# We haven't really acquired anything, so we cannot release
self.assertRaises(AssertionError, self.ls.release)
......@@ -1258,8 +1258,8 @@ class TestLockSet(_ThreadedTestCase):
self.ls.release()
else:
self.assert_(acquired is None)
self.assertFalse(self.ls._list_owned())
self.assertFalse(self.ls._is_owned())
self.assertFalse(self.ls.list_owned())
self.assertFalse(self.ls.is_owned())
self.done.put("not acquired")
self._addThread(target=_AcquireOne)
......@@ -1331,7 +1331,7 @@ class TestLockSet(_ThreadedTestCase):
self.ls.release(names=name)
self.assertFalse(self.ls._list_owned())
self.assertFalse(self.ls.list_owned())
self._waitThreads()
......@@ -1446,9 +1446,9 @@ class TestLockSet(_ThreadedTestCase):
self.ls.add('four')
self.ls.add('five', acquired=1)
self.ls.add('six', acquired=1, shared=1)
self.assertEquals(self.ls._list_owned(),
self.assertEquals(self.ls.list_owned(),
set(['one', 'two', 'three', 'five', 'six']))
self.assertEquals(self.ls._is_owned(), True)
self.assertEquals(self.ls.is_owned(), True)
self.assertEquals(self.ls._names(),
set(['one', 'two', 'three', 'four', 'five', 'six']))
self.ls.release()
......@@ -1489,55 +1489,55 @@ class TestLockSet(_ThreadedTestCase):
def testAcquireWithNamesDowngrade(self):
self.assertEquals(self.ls.acquire("two", shared=0), set(["two"]))
self.assertTrue(self.ls._is_owned())
self.assertFalse(self.ls._get_lock()._is_owned())
self.assertTrue(self.ls.is_owned())
self.assertFalse(self.ls._get_lock().is_owned())
self.ls.release()
self.assertFalse(self.ls._is_owned())
self.assertFalse(self.ls._get_lock()._is_owned())
self.assertFalse(self.ls.is_owned())
self.assertFalse(self.ls._get_lock().is_owned())
# Can't downgrade after releasing
self.assertRaises(AssertionError, self.ls.downgrade, "two")
def testDowngrade(self):
# Not owning anything, must raise an exception
self.assertFalse(self.ls._is_owned())
self.assertFalse(self.ls.is_owned())
self.assertRaises(AssertionError, self.ls.downgrade)
self.assertFalse(compat.any(i._is_owned()
self.assertFalse(compat.any(i.is_owned()
for i in self.ls._get_lockdict().values()))
self.assertEquals(self.ls.acquire(None, shared=0),
set(["one", "two", "three"]))
self.assertRaises(AssertionError, self.ls.downgrade, "unknown lock")
self.assertTrue(self.ls._get_lock()._is_owned(shared=0))
self.assertTrue(compat.all(i._is_owned(shared=0)
self.assertTrue(self.ls._get_lock().is_owned(shared=0))
self.assertTrue(compat.all(i.is_owned(shared=0)
for i in self.ls._get_lockdict().values()))
# Start downgrading locks
self.assertTrue(self.ls.downgrade(names=["one"]))
self.assertTrue(self.ls._get_lock()._is_owned(shared=0))
self.assertTrue(compat.all(lock._is_owned(shared=[0, 1][int(name == "one")])
self.assertTrue(self.ls._get_lock().is_owned(shared=0))
self.assertTrue(compat.all(lock.is_owned(shared=[0, 1][int(name == "one")])
for name, lock in
self.ls._get_lockdict().items()))