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