Revision 44b4eddc lib/locking.py

b/lib/locking.py
434 434

  
435 435
    # Register with lock monitor
436 436
    if monitor:
437
      logging.debug("Adding lock %s to monitor", name)
437 438
      monitor.RegisterLock(self)
438 439

  
439
  def GetInfo(self, requested):
440
  def GetLockInfo(self, requested):
440 441
    """Retrieves information for querying locks.
441 442

  
442 443
    @type requested: set
......
489 490
      else:
490 491
        pending = None
491 492

  
492
      return (self.name, mode, owner_names, pending)
493
      return [(self.name, mode, owner_names, pending)]
493 494
    finally:
494 495
      self.__lock.release()
495 496

  
......
1638 1639
    return self.__keyring[level].remove(names)
1639 1640

  
1640 1641

  
1641
def _MonitorSortKey((num, item)):
1642
def _MonitorSortKey((item, idx, num)):
1642 1643
  """Sorting key function.
1643 1644

  
1644
  Sort by name, then by incoming order.
1645
  Sort by name, registration order and then order of information. This provides
1646
  a stable sort order over different providers, even if they return the same
1647
  name.
1645 1648

  
1646 1649
  """
1647 1650
  (name, _, _, _) = item
1648 1651

  
1649
  return (utils.NiceSortKey(name), num)
1652
  return (utils.NiceSortKey(name), num, idx)
1650 1653

  
1651 1654

  
1652 1655
class LockMonitor(object):
......
1666 1669
    self._locks = weakref.WeakKeyDictionary()
1667 1670

  
1668 1671
  @ssynchronized(_LOCK_ATTR)
1669
  def RegisterLock(self, lock):
1672
  def RegisterLock(self, provider):
1670 1673
    """Registers a new lock.
1671 1674

  
1675
    @param provider: Object with a callable method named C{GetLockInfo}, taking
1676
      a single C{set} containing the requested information items
1677
    @note: It would be nicer to only receive the function generating the
1678
      requested information but, as it turns out, weak references to bound
1679
      methods (e.g. C{self.GetLockInfo}) are tricky; there are several
1680
      workarounds, but none of the ones I found works properly in combination
1681
      with a standard C{WeakKeyDictionary}
1682

  
1672 1683
    """
1673
    logging.debug("Registering lock %s", lock.name)
1674
    assert lock not in self._locks, "Duplicate lock registration"
1684
    assert provider not in self._locks, "Duplicate registration"
1675 1685

  
1676 1686
    # There used to be a check for duplicate names here. As it turned out, when
1677 1687
    # a lock is re-created with the same name in a very short timeframe, the
......
1679 1689
    # By keeping track of the order of incoming registrations, a stable sort
1680 1690
    # ordering can still be guaranteed.
1681 1691

  
1682
    self._locks[lock] = self._counter.next()
1692
    self._locks[provider] = self._counter.next()
1683 1693

  
1684
  @ssynchronized(_LOCK_ATTR)
1685 1694
  def _GetLockInfo(self, requested):
1686
    """Get information from all locks while the monitor lock is held.
1695
    """Get information from all locks.
1687 1696

  
1688 1697
    """
1689
    return [(num, lock.GetInfo(requested)) for lock, num in self._locks.items()]
1698
    # Must hold lock while getting consistent list of tracked items
1699
    self._lock.acquire(shared=1)
1700
    try:
1701
      items = self._locks.items()
1702
    finally:
1703
      self._lock.release()
1704

  
1705
    return [(info, idx, num)
1706
            for (provider, num) in items
1707
            for (idx, info) in enumerate(provider.GetLockInfo(requested))]
1690 1708

  
1691 1709
  def _Query(self, fields):
1692 1710
    """Queries information from all locks.
......
1703 1721
                      key=_MonitorSortKey)
1704 1722

  
1705 1723
    # Extract lock information and build query data
1706
    return (qobj, query.LockQueryData(map(operator.itemgetter(1), lockinfo)))
1724
    return (qobj, query.LockQueryData(map(operator.itemgetter(0), lockinfo)))
1707 1725

  
1708 1726
  def QueryLocks(self, fields):
1709 1727
    """Queries information from all locks.

Also available in: Unified diff