from ganeti import rpc
from ganeti import cmdlib
from ganeti import locking
+from ganeti import utils
class LockAcquireTimeout(Exception):
return result
-class _LockAttemptTimeoutStrategy(object):
+class LockAttemptTimeoutStrategy(object):
"""Class with lock acquire timeout strategy.
"""
__slots__ = [
- "_attempt",
+ "_timeouts",
"_random_fn",
- "_start_time",
"_time_fn",
- "_running_timeout",
]
_TIMEOUT_PER_ATTEMPT = _CalculateLockAttemptTimeouts()
- def __init__(self, attempt=0, _time_fn=time.time, _random_fn=random.random):
+ def __init__(self, _time_fn=time.time, _random_fn=random.random):
"""Initializes this class.
- @type attempt: int
- @param attempt: Current attempt number
@param _time_fn: Time function for unittests
@param _random_fn: Random number generator for unittests
"""
object.__init__(self)
- if attempt < 0:
- raise ValueError("Attempt must be zero or positive")
-
- self._attempt = attempt
+ self._timeouts = iter(self._TIMEOUT_PER_ATTEMPT)
self._time_fn = _time_fn
self._random_fn = _random_fn
- try:
- timeout = self._TIMEOUT_PER_ATTEMPT[attempt]
- except IndexError:
- # No more timeouts, do blocking acquire
- timeout = None
-
- self._running_timeout = locking.RunningTimeout(timeout, False,
- _time_fn=_time_fn)
-
def NextAttempt(self):
- """Returns the strategy for the next attempt.
-
- """
- return _LockAttemptTimeoutStrategy(attempt=self._attempt + 1,
- _time_fn=self._time_fn,
- _random_fn=self._random_fn)
-
- def CalcRemainingTimeout(self):
- """Returns the remaining timeout.
+ """Returns the timeout for the next attempt.
"""
- timeout = self._running_timeout.Remaining()
+ try:
+ timeout = self._timeouts.next()
+ except StopIteration:
+ # No more timeouts, do blocking acquire
+ timeout = None
if timeout is not None:
# Add a small variation (-/+ 5%) to timeout. This helps in situations
opcodes.OpSetClusterParams: cmdlib.LUSetClusterParams,
opcodes.OpRedistributeConfig: cmdlib.LURedistributeConfig,
opcodes.OpRepairDiskSizes: cmdlib.LURepairDiskSizes,
+ opcodes.OpQuery: cmdlib.LUQuery,
+ opcodes.OpQueryFields: cmdlib.LUQueryFields,
# node lu
opcodes.OpAddNode: cmdlib.LUAddNode,
opcodes.OpQueryNodes: cmdlib.LUQueryNodes,
opcodes.OpQueryInstanceData: cmdlib.LUQueryInstanceData,
opcodes.OpSetInstanceParams: cmdlib.LUSetInstanceParams,
opcodes.OpGrowDisk: cmdlib.LUGrowDisk,
+ # node group lu
+ opcodes.OpQueryGroups: cmdlib.LUQueryGroups,
# os lu
opcodes.OpDiagnoseOS: cmdlib.LUDiagnoseOS,
# exports lu
self.rpc = rpc.RpcRunner(context.cfg)
self.hmclass = HooksMaster
- def _AcquireLocks(self, level, names, shared, timeout):
+ def _AcquireLocks(self, level, names, shared, timeout, priority):
"""Acquires locks via the Ganeti lock manager.
@type level: int
@param shared: Whether the locks should be acquired in shared mode
@type timeout: None or float
@param timeout: Timeout for acquiring the locks
+ @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
+ amount of time
"""
if self._cbs:
self._cbs.CheckCancel()
acquired = self.context.glm.acquire(level, names, shared=shared,
- timeout=timeout)
+ timeout=timeout, priority=priority)
+
+ if acquired is None:
+ raise LockAcquireTimeout()
return acquired
return result
- def _LockAndExecLU(self, lu, level, calc_timeout):
+ def _LockAndExecLU(self, lu, level, calc_timeout, priority):
"""Execute a Logical Unit, with the needed locks.
This is a recursive function that starts locking the given level, and
needed_locks = lu.needed_locks[level]
acquired = self._AcquireLocks(level, needed_locks, share,
- calc_timeout())
-
- if acquired is None:
- raise LockAcquireTimeout()
-
+ calc_timeout(), priority)
else:
# Adding locks
add_locks = lu.add_locks[level]
try:
lu.acquired_locks[level] = acquired
- result = self._LockAndExecLU(lu, level + 1, calc_timeout)
+ result = self._LockAndExecLU(lu, level + 1, calc_timeout, priority)
finally:
if level in lu.remove_locks:
self.context.glm.remove(level, lu.remove_locks[level])
self.context.glm.release(level)
else:
- result = self._LockAndExecLU(lu, level + 1, calc_timeout)
+ result = self._LockAndExecLU(lu, level + 1, calc_timeout, priority)
return result
- def ExecOpCode(self, op, cbs, timeout=None):
+ def ExecOpCode(self, op, cbs, timeout=None, priority=None):
"""Execute an opcode.
@type op: an OpCode instance
@param cbs: Runtime callbacks
@type timeout: float or None
@param timeout: Maximum time to acquire all locks, None for no timeout
+ @type priority: number or None
+ @param priority: Priority for acquiring lock(s)
@raise LockAcquireTimeout: In case locks couldn't be acquired in specified
amount of time
if timeout is None:
calc_timeout = lambda: None
else:
- calc_timeout = locking.RunningTimeout(timeout, False).Remaining
+ calc_timeout = utils.RunningTimeout(timeout, False).Remaining
self._cbs = cbs
try:
# Acquire the Big Ganeti Lock exclusively if this LU requires it,
# and in a shared fashion otherwise (to prevent concurrent run with
# an exclusive LU.
- if self._AcquireLocks(locking.LEVEL_CLUSTER, locking.BGL,
- not lu_class.REQ_BGL, calc_timeout()) is None:
- raise LockAcquireTimeout()
-
+ self._AcquireLocks(locking.LEVEL_CLUSTER, locking.BGL,
+ not lu_class.REQ_BGL, calc_timeout(),
+ priority)
try:
lu = lu_class(self, op, self.context, self.rpc)
lu.ExpandNames()
assert lu.needed_locks is not None, "needed_locks not set by LU"
try:
- return self._LockAndExecLU(lu, locking.LEVEL_INSTANCE, calc_timeout)
+ return self._LockAndExecLU(lu, locking.LEVEL_INSTANCE, calc_timeout,
+ priority)
finally:
if self._ec_id:
self.context.cfg.DropECReservations(self._ec_id)