Revision 7f93570a
b/lib/config.py | ||
---|---|---|
1 | 1 |
# |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2006, 2007 Google Inc. |
|
4 |
# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
47 | 47 |
from ganeti import netutils |
48 | 48 |
|
49 | 49 |
|
50 |
_config_lock = locking.SharedLock() |
|
50 |
_config_lock = locking.SharedLock("ConfigWriter")
|
|
51 | 51 |
|
52 | 52 |
# job id used for resource management at config upgrade time |
53 | 53 |
_UPGRADE_CONFIG_JID = "jid-cfg-upgrade" |
b/lib/jqueue.py | ||
---|---|---|
1 | 1 |
# |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2006, 2007, 2008 Google Inc. |
|
4 |
# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
855 | 855 |
# shared mode, including itself. In order not to acquire it at all |
856 | 856 |
# concurrency must be guaranteed with all code acquiring it in shared mode |
857 | 857 |
# and all code acquiring it exclusively. |
858 |
self._lock = locking.SharedLock() |
|
858 |
self._lock = locking.SharedLock("JobQueue")
|
|
859 | 859 |
|
860 | 860 |
self.acquire = self._lock.acquire |
861 | 861 |
self.release = self._lock.release |
b/lib/locking.py | ||
---|---|---|
1 | 1 |
# |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2006, 2007 Google Inc. |
|
4 |
# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
404 | 404 |
the shared lock in the order they queued for it, just that they will |
405 | 405 |
eventually do so. |
406 | 406 |
|
407 |
@type name: string |
|
408 |
@ivar name: the name of the lock |
|
409 |
|
|
407 | 410 |
""" |
408 | 411 |
__slots__ = [ |
409 | 412 |
"__active_shr_c", |
... | ... | |
413 | 416 |
"__lock", |
414 | 417 |
"__pending", |
415 | 418 |
"__shr", |
419 |
"name", |
|
416 | 420 |
] |
417 | 421 |
|
418 | 422 |
__condition_class = PipeCondition |
419 | 423 |
|
420 |
def __init__(self): |
|
424 |
def __init__(self, name):
|
|
421 | 425 |
"""Construct a new SharedLock. |
422 | 426 |
|
427 |
@param name: the name of the lock |
|
428 |
|
|
423 | 429 |
""" |
424 | 430 |
object.__init__(self) |
425 | 431 |
|
432 |
self.name = name |
|
433 |
|
|
426 | 434 |
# Internal lock |
427 | 435 |
self.__lock = threading.Lock() |
428 | 436 |
|
... | ... | |
445 | 453 |
|
446 | 454 |
""" |
447 | 455 |
if self.__deleted: |
448 |
raise errors.LockError("Deleted lock")
|
|
456 |
raise errors.LockError("Deleted lock %s" % self.name)
|
|
449 | 457 |
|
450 | 458 |
def __is_sharer(self): |
451 | 459 |
"""Is the current thread sharing the lock at this time? |
... | ... | |
537 | 545 |
self.__check_deleted() |
538 | 546 |
|
539 | 547 |
# We cannot acquire the lock if we already have it |
540 |
assert not self.__is_owned(), "double acquire() on a non-recursive lock" |
|
548 |
assert not self.__is_owned(), ("double acquire() on a non-recursive lock" |
|
549 |
" %s" % self.name) |
|
541 | 550 |
|
542 | 551 |
# Check whether someone else holds the lock or there are pending acquires. |
543 | 552 |
if not self.__pending and self.__can_acquire(shared): |
... | ... | |
700 | 709 |
|
701 | 710 |
All the locks needed in the same set must be acquired together, though. |
702 | 711 |
|
712 |
@type name: string |
|
713 |
@ivar name: the name of the lockset |
|
714 |
|
|
703 | 715 |
""" |
704 |
def __init__(self, members=None):
|
|
716 |
def __init__(self, members, name):
|
|
705 | 717 |
"""Constructs a new LockSet. |
706 | 718 |
|
707 | 719 |
@type members: list of strings |
708 | 720 |
@param members: initial members of the set |
709 | 721 |
|
710 | 722 |
""" |
723 |
assert members is not None, "members parameter is not a list" |
|
724 |
self.name = name |
|
725 |
|
|
711 | 726 |
# Used internally to guarantee coherency. |
712 |
self.__lock = SharedLock() |
|
727 |
self.__lock = SharedLock(name)
|
|
713 | 728 |
|
714 | 729 |
# The lockdict indexes the relationship name -> lock |
715 | 730 |
# The order-of-locking is implied by the alphabetical order of names |
716 | 731 |
self.__lockdict = {} |
717 | 732 |
|
718 |
if members is not None: |
|
719 |
for name in members: |
|
720 |
self.__lockdict[name] = SharedLock() |
|
733 |
for mname in members: |
|
734 |
self.__lockdict[mname] = SharedLock("%s/%s" % (name, mname)) |
|
721 | 735 |
|
722 | 736 |
# The owner dict contains the set of locks each thread owns. For |
723 | 737 |
# performance each thread can access its own key without a global lock on |
... | ... | |
824 | 838 |
assert timeout is None or timeout >= 0.0 |
825 | 839 |
|
826 | 840 |
# Check we don't already own locks at this level |
827 |
assert not self._is_owned(), "Cannot acquire locks in the same set twice" |
|
841 |
assert not self._is_owned(), ("Cannot acquire locks in the same set twice" |
|
842 |
" (lockset %s)" % self.name) |
|
828 | 843 |
|
829 | 844 |
# We need to keep track of how long we spent waiting for a lock. The |
830 | 845 |
# timeout passed to this function is over all lock acquires. |
... | ... | |
894 | 909 |
# element is not there anymore. |
895 | 910 |
continue |
896 | 911 |
|
897 |
raise errors.LockError("Non-existing lock in set (%s)" % lname) |
|
912 |
raise errors.LockError("Non-existing lock %s in set %s" % |
|
913 |
(lname, self.name)) |
|
898 | 914 |
|
899 | 915 |
acquire_list.append((lname, lock)) |
900 | 916 |
|
... | ... | |
925 | 941 |
# particular element is not there anymore. |
926 | 942 |
continue |
927 | 943 |
|
928 |
raise errors.LockError("Non-existing lock in set (%s)" % lname) |
|
944 |
raise errors.LockError("Non-existing lock %s in set %s" % |
|
945 |
(lname, self.name)) |
|
929 | 946 |
|
930 | 947 |
if not acq_success: |
931 | 948 |
# Couldn't get lock or timeout occurred |
932 | 949 |
if timeout is None: |
933 | 950 |
# This shouldn't happen as SharedLock.acquire(timeout=None) is |
934 | 951 |
# blocking. |
935 |
raise errors.LockError("Failed to get lock %s" % lname) |
|
952 |
raise errors.LockError("Failed to get lock %s (set %s)" % |
|
953 |
(lname, self.name)) |
|
936 | 954 |
|
937 | 955 |
raise _AcquireTimeout() |
938 | 956 |
|
... | ... | |
967 | 985 |
(defaults to all the locks acquired at that level). |
968 | 986 |
|
969 | 987 |
""" |
970 |
assert self._is_owned(), "release() on lock set while not owner" |
|
988 |
assert self._is_owned(), ("release() on lock set %s while not owner" % |
|
989 |
self.name) |
|
971 | 990 |
|
972 | 991 |
# Support passing in a single resource to release rather than many |
973 | 992 |
if isinstance(names, basestring): |
... | ... | |
978 | 997 |
else: |
979 | 998 |
names = set(names) |
980 | 999 |
assert self._list_owned().issuperset(names), ( |
981 |
"release() on unheld resources %s" % |
|
982 |
names.difference(self._list_owned()))
|
|
1000 |
"release() on unheld resources %s (set %s)" %
|
|
1001 |
(names.difference(self._list_owned()), self.name))
|
|
983 | 1002 |
|
984 | 1003 |
# First of all let's release the "all elements" lock, if set. |
985 | 1004 |
# After this 'add' can work again |
... | ... | |
1006 | 1025 |
""" |
1007 | 1026 |
# Check we don't already own locks at this level |
1008 | 1027 |
assert not self._is_owned() or self.__lock._is_owned(shared=0), \ |
1009 |
"Cannot add locks if the set is only partially owned, or shared" |
|
1028 |
("Cannot add locks if the set %s is only partially owned, or shared" % |
|
1029 |
self.name) |
|
1010 | 1030 |
|
1011 | 1031 |
# Support passing in a single resource to add rather than many |
1012 | 1032 |
if isinstance(names, basestring): |
... | ... | |
1025 | 1045 |
# This must be an explicit raise, not an assert, because assert is |
1026 | 1046 |
# turned off when using optimization, and this can happen because of |
1027 | 1047 |
# concurrency even if the user doesn't want it. |
1028 |
raise errors.LockError("duplicate add() (%s)" % invalid_names) |
|
1048 |
raise errors.LockError("duplicate add(%s) on lockset %s" % |
|
1049 |
(invalid_names, self.name)) |
|
1029 | 1050 |
|
1030 | 1051 |
for lockname in names: |
1031 |
lock = SharedLock() |
|
1052 |
lock = SharedLock("%s/%s" % (self.name, lockname))
|
|
1032 | 1053 |
|
1033 | 1054 |
if acquired: |
1034 | 1055 |
lock.acquire(shared=shared) |
... | ... | |
1076 | 1097 |
# to delete. The ownership must also be exclusive, but that will be checked |
1077 | 1098 |
# by the lock itself. |
1078 | 1099 |
assert not self._is_owned() or self._list_owned().issuperset(names), ( |
1079 |
"remove() on acquired lockset while not owning all elements") |
|
1100 |
"remove() on acquired lockset %s while not owning all elements" % |
|
1101 |
self.name) |
|
1080 | 1102 |
|
1081 | 1103 |
removed = [] |
1082 | 1104 |
|
... | ... | |
1091 | 1113 |
removed.append(lname) |
1092 | 1114 |
except (KeyError, errors.LockError): |
1093 | 1115 |
# This cannot happen if we were already holding it, verify: |
1094 |
assert not self._is_owned(), "remove failed while holding lockset" |
|
1116 |
assert not self._is_owned(), ("remove failed while holding lockset %s" |
|
1117 |
% self.name) |
|
1095 | 1118 |
else: |
1096 | 1119 |
# If no LockError was raised we are the ones who deleted the lock. |
1097 | 1120 |
# This means we can safely remove it from lockdict, as any further or |
... | ... | |
1167 | 1190 |
# The keyring contains all the locks, at their level and in the correct |
1168 | 1191 |
# locking order. |
1169 | 1192 |
self.__keyring = { |
1170 |
LEVEL_CLUSTER: LockSet([BGL]), |
|
1171 |
LEVEL_NODE: LockSet(nodes), |
|
1172 |
LEVEL_INSTANCE: LockSet(instances), |
|
1193 |
LEVEL_CLUSTER: LockSet([BGL], "bgl lockset"),
|
|
1194 |
LEVEL_NODE: LockSet(nodes, "nodes lockset"),
|
|
1195 |
LEVEL_INSTANCE: LockSet(instances, "instances lockset"),
|
|
1173 | 1196 |
} |
1174 | 1197 |
|
1175 | 1198 |
def _names(self, level): |
b/test/ganeti.locking_unittest.py | ||
---|---|---|
1 | 1 |
#!/usr/bin/python |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2006, 2007 Google Inc. |
|
4 |
# Copyright (C) 2006, 2007, 2010 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
36 | 36 |
|
37 | 37 |
# This is used to test the ssynchronize decorator. |
38 | 38 |
# Since it's passed as input to a decorator it must be declared as a global. |
39 |
_decoratorlock = locking.SharedLock() |
|
39 |
_decoratorlock = locking.SharedLock("decorator lock")
|
|
40 | 40 |
|
41 | 41 |
#: List for looping tests |
42 | 42 |
ITERATIONS = range(8) |
... | ... | |
256 | 256 |
|
257 | 257 |
def setUp(self): |
258 | 258 |
_ThreadedTestCase.setUp(self) |
259 |
self.sl = locking.SharedLock() |
|
259 |
self.sl = locking.SharedLock("TestSharedLock")
|
|
260 | 260 |
|
261 | 261 |
def testSequenceAndOwnership(self): |
262 | 262 |
self.assertFalse(self.sl._is_owned()) |
... | ... | |
350 | 350 |
self.sl.release() |
351 | 351 |
self._waitThreads() |
352 | 352 |
self.failUnlessEqual(self.done.get_nowait(), 'DEL') |
353 |
self.sl = locking.SharedLock() |
|
353 |
self.sl = locking.SharedLock(self.sl.name)
|
|
354 | 354 |
|
355 | 355 |
@_Repeat |
356 | 356 |
def testExclusiveBlocksSharer(self): |
... | ... | |
378 | 378 |
self.sl.release() |
379 | 379 |
self._waitThreads() |
380 | 380 |
self.failUnlessEqual(self.done.get_nowait(), 'DEL') |
381 |
self.sl = locking.SharedLock() |
|
381 |
self.sl = locking.SharedLock(self.sl.name)
|
|
382 | 382 |
|
383 | 383 |
@_Repeat |
384 | 384 |
def testWaitingExclusiveBlocksSharer(self): |
... | ... | |
441 | 441 |
# The threads who were pending return ERR |
442 | 442 |
for _ in range(4): |
443 | 443 |
self.assertEqual(self.done.get_nowait(), 'ERR') |
444 |
self.sl = locking.SharedLock() |
|
444 |
self.sl = locking.SharedLock(self.sl.name)
|
|
445 | 445 |
|
446 | 446 |
@_Repeat |
447 | 447 |
def testDeletePendingDeleteExclusiveSharers(self): |
... | ... | |
457 | 457 |
self.assertEqual(self.done.get_nowait(), 'ERR') |
458 | 458 |
self.assertEqual(self.done.get_nowait(), 'ERR') |
459 | 459 |
self.assertEqual(self.done.get_nowait(), 'ERR') |
460 |
self.sl = locking.SharedLock() |
|
460 |
self.sl = locking.SharedLock(self.sl.name)
|
|
461 | 461 |
|
462 | 462 |
@_Repeat |
463 | 463 |
def testExclusiveAcquireTimeout(self): |
... | ... | |
703 | 703 |
|
704 | 704 |
def setUp(self): |
705 | 705 |
_ThreadedTestCase.setUp(self) |
706 |
self.sl = locking.SharedLock() |
|
706 |
self.sl = locking.SharedLock("TestSharedLockInCondition")
|
|
707 | 707 |
self.setCondition() |
708 | 708 |
|
709 | 709 |
def setCondition(self): |
... | ... | |
796 | 796 |
def _setUpLS(self): |
797 | 797 |
"""Helper to (re)initialize the lock set""" |
798 | 798 |
self.resources = ['one', 'two', 'three'] |
799 |
self.ls = locking.LockSet(members=self.resources)
|
|
799 |
self.ls = locking.LockSet(self.resources, "TestLockSet")
|
|
800 | 800 |
|
801 | 801 |
def testResources(self): |
802 | 802 |
self.assertEquals(self.ls._names(), set(self.resources)) |
803 |
newls = locking.LockSet() |
|
803 |
newls = locking.LockSet([], "TestLockSet.testResources")
|
|
804 | 804 |
self.assertEquals(newls._names(), set()) |
805 | 805 |
|
806 | 806 |
def testAcquireRelease(self): |
... | ... | |
1288 | 1288 |
|
1289 | 1289 |
def testInitAndResources(self): |
1290 | 1290 |
locking.GanetiLockManager._instance = None |
1291 |
self.GL = locking.GanetiLockManager() |
|
1291 |
self.GL = locking.GanetiLockManager([], [])
|
|
1292 | 1292 |
self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL'])) |
1293 | 1293 |
self.assertEqual(self.GL._names(locking.LEVEL_NODE), set()) |
1294 | 1294 |
self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set()) |
1295 | 1295 |
|
1296 | 1296 |
locking.GanetiLockManager._instance = None |
1297 |
self.GL = locking.GanetiLockManager(nodes=self.nodes)
|
|
1297 |
self.GL = locking.GanetiLockManager(self.nodes, [])
|
|
1298 | 1298 |
self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL'])) |
1299 | 1299 |
self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes)) |
1300 | 1300 |
self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set()) |
1301 | 1301 |
|
1302 | 1302 |
locking.GanetiLockManager._instance = None |
1303 |
self.GL = locking.GanetiLockManager(instances=self.instances)
|
|
1303 |
self.GL = locking.GanetiLockManager([], self.instances)
|
|
1304 | 1304 |
self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL'])) |
1305 | 1305 |
self.assertEqual(self.GL._names(locking.LEVEL_NODE), set()) |
1306 | 1306 |
self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), |
Also available in: Unified diff