Revision e4e35357 lib/locking.py
b/lib/locking.py | ||
---|---|---|
33 | 33 |
import logging |
34 | 34 |
import heapq |
35 | 35 |
import operator |
36 |
import itertools |
|
36 | 37 |
|
37 | 38 |
from ganeti import errors |
38 | 39 |
from ganeti import utils |
... | ... | |
1514 | 1515 |
return self.__keyring[level].remove(names) |
1515 | 1516 |
|
1516 | 1517 |
|
1518 |
def _MonitorSortKey((num, item)): |
|
1519 |
"""Sorting key function. |
|
1520 |
|
|
1521 |
Sort by name, then by incoming order. |
|
1522 |
|
|
1523 |
""" |
|
1524 |
(name, _, _, _) = item |
|
1525 |
|
|
1526 |
return (utils.NiceSortKey(name), num) |
|
1527 |
|
|
1528 |
|
|
1517 | 1529 |
class LockMonitor(object): |
1518 | 1530 |
_LOCK_ATTR = "_lock" |
1519 | 1531 |
|
... | ... | |
1523 | 1535 |
""" |
1524 | 1536 |
self._lock = SharedLock("LockMonitor") |
1525 | 1537 |
|
1538 |
# Counter for stable sorting |
|
1539 |
self._counter = itertools.count(0) |
|
1540 |
|
|
1526 | 1541 |
# Tracked locks. Weak references are used to avoid issues with circular |
1527 | 1542 |
# references and deletion. |
1528 | 1543 |
self._locks = weakref.WeakKeyDictionary() |
... | ... | |
1534 | 1549 |
""" |
1535 | 1550 |
logging.debug("Registering lock %s", lock.name) |
1536 | 1551 |
assert lock not in self._locks, "Duplicate lock registration" |
1537 |
assert not compat.any(lock.name == i.name for i in self._locks.keys()), \ |
|
1538 |
"Found duplicate lock name" |
|
1539 |
self._locks[lock] = None |
|
1552 |
|
|
1553 |
# There used to be a check for duplicate names here. As it turned out, when |
|
1554 |
# a lock is re-created with the same name in a very short timeframe, the |
|
1555 |
# previous instance might not yet be removed from the weakref dictionary. |
|
1556 |
# By keeping track of the order of incoming registrations, a stable sort |
|
1557 |
# ordering can still be guaranteed. |
|
1558 |
|
|
1559 |
self._locks[lock] = self._counter.next() |
|
1540 | 1560 |
|
1541 | 1561 |
@ssynchronized(_LOCK_ATTR) |
1542 | 1562 |
def _GetLockInfo(self, requested): |
1543 | 1563 |
"""Get information from all locks while the monitor lock is held. |
1544 | 1564 |
|
1545 | 1565 |
""" |
1546 |
return [lock.GetInfo(requested) for lock in self._locks.keys()]
|
|
1566 |
return [(num, lock.GetInfo(requested)) for lock, num in self._locks.items()]
|
|
1547 | 1567 |
|
1548 | 1568 |
def _Query(self, fields): |
1549 | 1569 |
"""Queries information from all locks. |
... | ... | |
1554 | 1574 |
""" |
1555 | 1575 |
qobj = query.Query(query.LOCK_FIELDS, fields) |
1556 | 1576 |
|
1557 |
# Get all data and sort by name |
|
1558 |
lockinfo = utils.NiceSort(self._GetLockInfo(qobj.RequestedData()), |
|
1559 |
key=operator.itemgetter(0)) |
|
1577 |
# Get all data with internal lock held and then sort by name and incoming |
|
1578 |
# order |
|
1579 |
lockinfo = sorted(self._GetLockInfo(qobj.RequestedData()), |
|
1580 |
key=_MonitorSortKey) |
|
1560 | 1581 |
|
1561 |
return (qobj, query.LockQueryData(lockinfo)) |
|
1582 |
# Extract lock information and build query data |
|
1583 |
return (qobj, query.LockQueryData(map(operator.itemgetter(1), lockinfo))) |
|
1562 | 1584 |
|
1563 | 1585 |
def QueryLocks(self, fields): |
1564 | 1586 |
"""Queries information from all locks. |
Also available in: Unified diff