Revision a6db1af2

b/lib/mcpu.py
81 81
    "_random_fn",
82 82
    "_start_time",
83 83
    "_time_fn",
84
    "_running_timeout",
84 85
    ]
85 86

  
86 87
  _TIMEOUT_PER_ATTEMPT = _CalculateLockAttemptTimeouts()
......
103 104
    self._time_fn = _time_fn
104 105
    self._random_fn = _random_fn
105 106

  
106
    self._start_time = None
107
    try:
108
      timeout = self._TIMEOUT_PER_ATTEMPT[attempt]
109
    except IndexError:
110
      # No more timeouts, do blocking acquire
111
      timeout = None
112

  
113
    self._running_timeout = locking.RunningTimeout(timeout, False,
114
                                                   _time_fn=_time_fn)
107 115

  
108 116
  def NextAttempt(self):
109 117
    """Returns the strategy for the next attempt.
......
117 125
    """Returns the remaining timeout.
118 126

  
119 127
    """
120
    try:
121
      timeout = self._TIMEOUT_PER_ATTEMPT[self._attempt]
122
    except IndexError:
123
      # No more timeouts, do blocking acquire
124
      return None
125

  
126
    # Get start time on first calculation
127
    if self._start_time is None:
128
      self._start_time = self._time_fn()
129

  
130
    # Calculate remaining time for this attempt
131
    remaining_timeout = self._start_time + timeout - self._time_fn()
132

  
133
    # Add a small variation (-/+ 5%) to timeouts. This helps in situations
134
    # where two or more jobs are fighting for the same lock(s).
135
    variation_range = remaining_timeout * 0.1
136
    remaining_timeout += ((self._random_fn() * variation_range) -
137
                          (variation_range * 0.5))
128
    timeout = self._running_timeout.Remaining()
138 129

  
139
    # Make sure timeout is >= 0
140
    remaining_timeout = max(0.0, remaining_timeout)
130
    if timeout is not None:
131
      # Add a small variation (-/+ 5%) to timeout. This helps in situations
132
      # where two or more jobs are fighting for the same lock(s).
133
      variation_range = timeout * 0.1
134
      timeout += ((self._random_fn() * variation_range) -
135
                  (variation_range * 0.5))
141 136

  
142
    return remaining_timeout
137
    return timeout
143 138

  
144 139

  
145 140
class OpExecCbBase:
b/test/ganeti.mcpu_unittest.py
40 40
    self.assertEqual(strat._attempt, 0)
41 41

  
42 42
    prev = None
43
    for _ in range(len(mcpu._LockAttemptTimeoutStrategy._TIMEOUT_PER_ATTEMPT)):
43
    for i in range(len(mcpu._LockAttemptTimeoutStrategy._TIMEOUT_PER_ATTEMPT)):
44 44
      timeout = strat.CalcRemainingTimeout()
45 45
      self.assert_(timeout is not None)
46 46

  
47 47
      self.assert_(timeout <= 10.0)
48
      self.assert_(timeout >= 0.0)
48 49
      self.assert_(prev is None or timeout >= prev)
49 50

  
50 51
      strat = strat.NextAttempt()
52
      self.assertEqual(strat._attempt, i + 1)
51 53

  
52 54
      prev = timeout
53 55

  
54
    self.assert_(strat.CalcRemainingTimeout() is None)
56
    for _ in range(10):
57
      self.assert_(strat.CalcRemainingTimeout() is None)
55 58

  
56 59

  
57 60
if __name__ == "__main__":

Also available in: Unified diff