Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 48436b97

History | View | Annotate | Download (40.3 kB)

1 162c1c1f Guido Trotter
#
2 162c1c1f Guido Trotter
#
3 162c1c1f Guido Trotter
4 162c1c1f Guido Trotter
# Copyright (C) 2006, 2007 Google Inc.
5 162c1c1f Guido Trotter
#
6 162c1c1f Guido Trotter
# This program is free software; you can redistribute it and/or modify
7 162c1c1f Guido Trotter
# it under the terms of the GNU General Public License as published by
8 162c1c1f Guido Trotter
# the Free Software Foundation; either version 2 of the License, or
9 162c1c1f Guido Trotter
# (at your option) any later version.
10 162c1c1f Guido Trotter
#
11 162c1c1f Guido Trotter
# This program is distributed in the hope that it will be useful, but
12 162c1c1f Guido Trotter
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 162c1c1f Guido Trotter
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 162c1c1f Guido Trotter
# General Public License for more details.
15 162c1c1f Guido Trotter
#
16 162c1c1f Guido Trotter
# You should have received a copy of the GNU General Public License
17 162c1c1f Guido Trotter
# along with this program; if not, write to the Free Software
18 162c1c1f Guido Trotter
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 162c1c1f Guido Trotter
# 02110-1301, USA.
20 162c1c1f Guido Trotter
21 162c1c1f Guido Trotter
"""Module implementing the Ganeti locking code."""
22 162c1c1f Guido Trotter
23 c70d2d9b Iustin Pop
# pylint: disable-msg=W0212
24 c70d2d9b Iustin Pop
25 c70d2d9b Iustin Pop
# W0212 since e.g. LockSet methods use (a lot) the internals of
26 c70d2d9b Iustin Pop
# SharedLock
27 162c1c1f Guido Trotter
28 d76167a5 Michael Hanselmann
import os
29 d76167a5 Michael Hanselmann
import select
30 162c1c1f Guido Trotter
import threading
31 d76167a5 Michael Hanselmann
import time
32 d76167a5 Michael Hanselmann
import errno
33 84e344d4 Michael Hanselmann
34 a95fd5d7 Guido Trotter
from ganeti import errors
35 7ee7c0c7 Guido Trotter
from ganeti import utils
36 cea881e5 Michael Hanselmann
from ganeti import compat
37 162c1c1f Guido Trotter
38 162c1c1f Guido Trotter
39 42a999d1 Guido Trotter
def ssynchronized(lock, shared=0):
40 42a999d1 Guido Trotter
  """Shared Synchronization decorator.
41 42a999d1 Guido Trotter

42 42a999d1 Guido Trotter
  Calls the function holding the given lock, either in exclusive or shared
43 42a999d1 Guido Trotter
  mode. It requires the passed lock to be a SharedLock (or support its
44 42a999d1 Guido Trotter
  semantics).
45 42a999d1 Guido Trotter

46 42a999d1 Guido Trotter
  """
47 42a999d1 Guido Trotter
  def wrap(fn):
48 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
49 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
50 42a999d1 Guido Trotter
      try:
51 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
52 42a999d1 Guido Trotter
      finally:
53 42a999d1 Guido Trotter
        lock.release()
54 42a999d1 Guido Trotter
    return sync_function
55 42a999d1 Guido Trotter
  return wrap
56 42a999d1 Guido Trotter
57 42a999d1 Guido Trotter
58 7e8841bd Michael Hanselmann
class RunningTimeout(object):
59 7e8841bd Michael Hanselmann
  """Class to calculate remaining timeout when doing several operations.
60 7e8841bd Michael Hanselmann

61 7e8841bd Michael Hanselmann
  """
62 7e8841bd Michael Hanselmann
  __slots__ = [
63 7e8841bd Michael Hanselmann
    "_allow_negative",
64 7e8841bd Michael Hanselmann
    "_start_time",
65 7e8841bd Michael Hanselmann
    "_time_fn",
66 7e8841bd Michael Hanselmann
    "_timeout",
67 7e8841bd Michael Hanselmann
    ]
68 7e8841bd Michael Hanselmann
69 7e8841bd Michael Hanselmann
  def __init__(self, timeout, allow_negative, _time_fn=time.time):
70 7e8841bd Michael Hanselmann
    """Initializes this class.
71 7e8841bd Michael Hanselmann

72 7e8841bd Michael Hanselmann
    @type timeout: float
73 7e8841bd Michael Hanselmann
    @param timeout: Timeout duration
74 7e8841bd Michael Hanselmann
    @type allow_negative: bool
75 7e8841bd Michael Hanselmann
    @param allow_negative: Whether to return values below zero
76 7e8841bd Michael Hanselmann
    @param _time_fn: Time function for unittests
77 7e8841bd Michael Hanselmann

78 7e8841bd Michael Hanselmann
    """
79 7e8841bd Michael Hanselmann
    object.__init__(self)
80 7e8841bd Michael Hanselmann
81 7e8841bd Michael Hanselmann
    if timeout is not None and timeout < 0.0:
82 7e8841bd Michael Hanselmann
      raise ValueError("Timeout must not be negative")
83 7e8841bd Michael Hanselmann
84 7e8841bd Michael Hanselmann
    self._timeout = timeout
85 7e8841bd Michael Hanselmann
    self._allow_negative = allow_negative
86 7e8841bd Michael Hanselmann
    self._time_fn = _time_fn
87 7e8841bd Michael Hanselmann
88 7e8841bd Michael Hanselmann
    self._start_time = None
89 7e8841bd Michael Hanselmann
90 7e8841bd Michael Hanselmann
  def Remaining(self):
91 7e8841bd Michael Hanselmann
    """Returns the remaining timeout.
92 7e8841bd Michael Hanselmann

93 7e8841bd Michael Hanselmann
    """
94 7e8841bd Michael Hanselmann
    if self._timeout is None:
95 7e8841bd Michael Hanselmann
      return None
96 7e8841bd Michael Hanselmann
97 7e8841bd Michael Hanselmann
    # Get start time on first calculation
98 7e8841bd Michael Hanselmann
    if self._start_time is None:
99 7e8841bd Michael Hanselmann
      self._start_time = self._time_fn()
100 7e8841bd Michael Hanselmann
101 7e8841bd Michael Hanselmann
    # Calculate remaining time
102 7e8841bd Michael Hanselmann
    remaining_timeout = self._start_time + self._timeout - self._time_fn()
103 7e8841bd Michael Hanselmann
104 7e8841bd Michael Hanselmann
    if not self._allow_negative:
105 7e8841bd Michael Hanselmann
      # Ensure timeout is always >= 0
106 7e8841bd Michael Hanselmann
      return max(0.0, remaining_timeout)
107 7e8841bd Michael Hanselmann
108 7e8841bd Michael Hanselmann
    return remaining_timeout
109 7e8841bd Michael Hanselmann
110 7e8841bd Michael Hanselmann
111 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
112 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
113 d76167a5 Michael Hanselmann

114 d76167a5 Michael Hanselmann
  """
115 d76167a5 Michael Hanselmann
  __slots__ = [
116 d76167a5 Michael Hanselmann
    "_fd",
117 d76167a5 Michael Hanselmann
    "_poller",
118 d76167a5 Michael Hanselmann
    ]
119 d76167a5 Michael Hanselmann
120 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
121 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
122 d76167a5 Michael Hanselmann

123 d76167a5 Michael Hanselmann
    @type poller: select.poll
124 d76167a5 Michael Hanselmann
    @param poller: Poller object
125 d76167a5 Michael Hanselmann
    @type fd: int
126 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
127 d76167a5 Michael Hanselmann

128 d76167a5 Michael Hanselmann
    """
129 d76167a5 Michael Hanselmann
    object.__init__(self)
130 d76167a5 Michael Hanselmann
    self._poller = poller
131 d76167a5 Michael Hanselmann
    self._fd = fd
132 d76167a5 Michael Hanselmann
133 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
134 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
135 d76167a5 Michael Hanselmann

136 d76167a5 Michael Hanselmann
    @type timeout: float or None
137 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
138 d76167a5 Michael Hanselmann

139 d76167a5 Michael Hanselmann
    """
140 f4e673fb Michael Hanselmann
    running_timeout = RunningTimeout(timeout, True)
141 f4e673fb Michael Hanselmann
142 f4e673fb Michael Hanselmann
    while True:
143 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
144 f4e673fb Michael Hanselmann
145 b44b0141 Michael Hanselmann
      if remaining_time is not None:
146 b44b0141 Michael Hanselmann
        if remaining_time < 0.0:
147 b44b0141 Michael Hanselmann
          break
148 d76167a5 Michael Hanselmann
149 413b7472 Michael Hanselmann
        # Our calculation uses seconds, poll() wants milliseconds
150 b44b0141 Michael Hanselmann
        remaining_time *= 1000
151 d76167a5 Michael Hanselmann
152 d76167a5 Michael Hanselmann
      try:
153 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
154 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
155 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
156 d76167a5 Michael Hanselmann
          raise
157 d76167a5 Michael Hanselmann
        result = None
158 d76167a5 Michael Hanselmann
159 d76167a5 Michael Hanselmann
      # Check whether we were notified
160 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
161 d76167a5 Michael Hanselmann
        break
162 d76167a5 Michael Hanselmann
163 d76167a5 Michael Hanselmann
164 2419060d Guido Trotter
class _BaseCondition(object):
165 2419060d Guido Trotter
  """Base class containing common code for conditions.
166 2419060d Guido Trotter

167 2419060d Guido Trotter
  Some of this code is taken from python's threading module.
168 2419060d Guido Trotter

169 2419060d Guido Trotter
  """
170 2419060d Guido Trotter
  __slots__ = [
171 2419060d Guido Trotter
    "_lock",
172 2419060d Guido Trotter
    "acquire",
173 2419060d Guido Trotter
    "release",
174 2419060d Guido Trotter
    ]
175 2419060d Guido Trotter
176 2419060d Guido Trotter
  def __init__(self, lock):
177 2419060d Guido Trotter
    """Constructor for _BaseCondition.
178 2419060d Guido Trotter

179 69b99987 Michael Hanselmann
    @type lock: threading.Lock
180 2419060d Guido Trotter
    @param lock: condition base lock
181 2419060d Guido Trotter

182 2419060d Guido Trotter
    """
183 2419060d Guido Trotter
    object.__init__(self)
184 2419060d Guido Trotter
185 2419060d Guido Trotter
    # Recursive locks are not supported
186 2419060d Guido Trotter
    assert not hasattr(lock, "_acquire_restore")
187 2419060d Guido Trotter
    assert not hasattr(lock, "_release_save")
188 2419060d Guido Trotter
189 2419060d Guido Trotter
    self._lock = lock
190 2419060d Guido Trotter
191 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
192 2419060d Guido Trotter
    self.acquire = lock.acquire
193 2419060d Guido Trotter
    self.release = lock.release
194 2419060d Guido Trotter
195 2419060d Guido Trotter
  def _is_owned(self):
196 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
197 2419060d Guido Trotter

198 2419060d Guido Trotter
    """
199 2419060d Guido Trotter
    if self._lock.acquire(0):
200 2419060d Guido Trotter
      self._lock.release()
201 2419060d Guido Trotter
      return False
202 2419060d Guido Trotter
203 2419060d Guido Trotter
    return True
204 2419060d Guido Trotter
205 2419060d Guido Trotter
  def _check_owned(self):
206 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
207 2419060d Guido Trotter

208 2419060d Guido Trotter
    """
209 2419060d Guido Trotter
    if not self._is_owned():
210 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
211 2419060d Guido Trotter
212 2419060d Guido Trotter
213 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
214 34cb5617 Guido Trotter
  """Condition which can only be notified once.
215 d76167a5 Michael Hanselmann

216 34cb5617 Guido Trotter
  This condition class uses pipes and poll, internally, to be able to wait for
217 34cb5617 Guido Trotter
  notification with a timeout, without resorting to polling. It is almost
218 34cb5617 Guido Trotter
  compatible with Python's threading.Condition, with the following differences:
219 34cb5617 Guido Trotter
    - notifyAll can only be called once, and no wait can happen after that
220 34cb5617 Guido Trotter
    - notify is not supported, only notifyAll
221 d76167a5 Michael Hanselmann

222 d76167a5 Michael Hanselmann
  """
223 34cb5617 Guido Trotter
224 154b9580 Balazs Lecz
  __slots__ = [
225 d76167a5 Michael Hanselmann
    "_poller",
226 d76167a5 Michael Hanselmann
    "_read_fd",
227 d76167a5 Michael Hanselmann
    "_write_fd",
228 d76167a5 Michael Hanselmann
    "_nwaiters",
229 34cb5617 Guido Trotter
    "_notified",
230 d76167a5 Michael Hanselmann
    ]
231 d76167a5 Michael Hanselmann
232 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
233 d76167a5 Michael Hanselmann
234 34cb5617 Guido Trotter
  def __init__(self, lock):
235 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
236 d76167a5 Michael Hanselmann

237 d76167a5 Michael Hanselmann
    """
238 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
239 d76167a5 Michael Hanselmann
    self._nwaiters = 0
240 34cb5617 Guido Trotter
    self._notified = False
241 34cb5617 Guido Trotter
    self._read_fd = None
242 34cb5617 Guido Trotter
    self._write_fd = None
243 34cb5617 Guido Trotter
    self._poller = None
244 d76167a5 Michael Hanselmann
245 34cb5617 Guido Trotter
  def _check_unnotified(self):
246 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
247 69b99987 Michael Hanselmann

248 69b99987 Michael Hanselmann
    """
249 34cb5617 Guido Trotter
    if self._notified:
250 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
251 d76167a5 Michael Hanselmann
252 34cb5617 Guido Trotter
  def _Cleanup(self):
253 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
254 d76167a5 Michael Hanselmann

255 d76167a5 Michael Hanselmann
    """
256 34cb5617 Guido Trotter
    if self._read_fd is not None:
257 34cb5617 Guido Trotter
      os.close(self._read_fd)
258 34cb5617 Guido Trotter
      self._read_fd = None
259 d76167a5 Michael Hanselmann
260 34cb5617 Guido Trotter
    if self._write_fd is not None:
261 34cb5617 Guido Trotter
      os.close(self._write_fd)
262 34cb5617 Guido Trotter
      self._write_fd = None
263 34cb5617 Guido Trotter
    self._poller = None
264 d76167a5 Michael Hanselmann
265 34cb5617 Guido Trotter
  def wait(self, timeout=None):
266 34cb5617 Guido Trotter
    """Wait for a notification.
267 d76167a5 Michael Hanselmann

268 34cb5617 Guido Trotter
    @type timeout: float or None
269 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
270 d76167a5 Michael Hanselmann

271 d76167a5 Michael Hanselmann
    """
272 34cb5617 Guido Trotter
    self._check_owned()
273 34cb5617 Guido Trotter
    self._check_unnotified()
274 d76167a5 Michael Hanselmann
275 34cb5617 Guido Trotter
    self._nwaiters += 1
276 34cb5617 Guido Trotter
    try:
277 34cb5617 Guido Trotter
      if self._poller is None:
278 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
279 34cb5617 Guido Trotter
        self._poller = select.poll()
280 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
281 d76167a5 Michael Hanselmann
282 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
283 34cb5617 Guido Trotter
      self.release()
284 34cb5617 Guido Trotter
      try:
285 34cb5617 Guido Trotter
        # Wait for notification
286 34cb5617 Guido Trotter
        wait_fn(timeout)
287 34cb5617 Guido Trotter
      finally:
288 34cb5617 Guido Trotter
        # Re-acquire lock
289 34cb5617 Guido Trotter
        self.acquire()
290 34cb5617 Guido Trotter
    finally:
291 34cb5617 Guido Trotter
      self._nwaiters -= 1
292 34cb5617 Guido Trotter
      if self._nwaiters == 0:
293 34cb5617 Guido Trotter
        self._Cleanup()
294 d76167a5 Michael Hanselmann
295 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
296 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
297 d76167a5 Michael Hanselmann

298 d76167a5 Michael Hanselmann
    """
299 34cb5617 Guido Trotter
    self._check_owned()
300 34cb5617 Guido Trotter
    self._check_unnotified()
301 34cb5617 Guido Trotter
    self._notified = True
302 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
303 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
304 d76167a5 Michael Hanselmann
      self._write_fd = None
305 d76167a5 Michael Hanselmann
306 d76167a5 Michael Hanselmann
307 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
308 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
309 48dabc6a Michael Hanselmann

310 48dabc6a Michael Hanselmann
  This condition class uses pipes and poll, internally, to be able to wait for
311 48dabc6a Michael Hanselmann
  notification with a timeout, without resorting to polling. It is almost
312 48dabc6a Michael Hanselmann
  compatible with Python's threading.Condition, but only supports notifyAll and
313 48dabc6a Michael Hanselmann
  non-recursive locks. As an additional features it's able to report whether
314 48dabc6a Michael Hanselmann
  there are any waiting threads.
315 48dabc6a Michael Hanselmann

316 48dabc6a Michael Hanselmann
  """
317 154b9580 Balazs Lecz
  __slots__ = [
318 48dabc6a Michael Hanselmann
    "_nwaiters",
319 34cb5617 Guido Trotter
    "_single_condition",
320 48dabc6a Michael Hanselmann
    ]
321 48dabc6a Michael Hanselmann
322 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
323 48dabc6a Michael Hanselmann
324 48dabc6a Michael Hanselmann
  def __init__(self, lock):
325 48dabc6a Michael Hanselmann
    """Initializes this class.
326 48dabc6a Michael Hanselmann

327 48dabc6a Michael Hanselmann
    """
328 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
329 48dabc6a Michael Hanselmann
    self._nwaiters = 0
330 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
331 48dabc6a Michael Hanselmann
332 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
333 48dabc6a Michael Hanselmann
    """Wait for a notification.
334 48dabc6a Michael Hanselmann

335 48dabc6a Michael Hanselmann
    @type timeout: float or None
336 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
337 48dabc6a Michael Hanselmann

338 48dabc6a Michael Hanselmann
    """
339 48dabc6a Michael Hanselmann
    self._check_owned()
340 48dabc6a Michael Hanselmann
341 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
342 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
343 34cb5617 Guido Trotter
    my_condition = self._single_condition
344 48dabc6a Michael Hanselmann
345 48dabc6a Michael Hanselmann
    assert self._nwaiters >= 0
346 48dabc6a Michael Hanselmann
    self._nwaiters += 1
347 48dabc6a Michael Hanselmann
    try:
348 34cb5617 Guido Trotter
      my_condition.wait(timeout)
349 48dabc6a Michael Hanselmann
    finally:
350 48dabc6a Michael Hanselmann
      assert self._nwaiters > 0
351 48dabc6a Michael Hanselmann
      self._nwaiters -= 1
352 48dabc6a Michael Hanselmann
353 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
354 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
355 48dabc6a Michael Hanselmann

356 48dabc6a Michael Hanselmann
    """
357 48dabc6a Michael Hanselmann
    self._check_owned()
358 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
359 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
360 48dabc6a Michael Hanselmann
361 48dabc6a Michael Hanselmann
  def has_waiting(self):
362 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
363 48dabc6a Michael Hanselmann

364 48dabc6a Michael Hanselmann
    """
365 48dabc6a Michael Hanselmann
    self._check_owned()
366 48dabc6a Michael Hanselmann
367 48dabc6a Michael Hanselmann
    return bool(self._nwaiters)
368 48dabc6a Michael Hanselmann
369 48dabc6a Michael Hanselmann
370 84e344d4 Michael Hanselmann
class _CountingCondition(object):
371 84e344d4 Michael Hanselmann
  """Wrapper for Python's built-in threading.Condition class.
372 84e344d4 Michael Hanselmann

373 84e344d4 Michael Hanselmann
  This wrapper keeps a count of active waiters. We can't access the internal
374 84e344d4 Michael Hanselmann
  "__waiters" attribute of threading.Condition because it's not thread-safe.
375 84e344d4 Michael Hanselmann

376 84e344d4 Michael Hanselmann
  """
377 84e344d4 Michael Hanselmann
  __slots__ = [
378 84e344d4 Michael Hanselmann
    "_cond",
379 84e344d4 Michael Hanselmann
    "_nwaiters",
380 84e344d4 Michael Hanselmann
    ]
381 84e344d4 Michael Hanselmann
382 84e344d4 Michael Hanselmann
  def __init__(self, lock):
383 84e344d4 Michael Hanselmann
    """Initializes this class.
384 84e344d4 Michael Hanselmann

385 84e344d4 Michael Hanselmann
    """
386 84e344d4 Michael Hanselmann
    object.__init__(self)
387 84e344d4 Michael Hanselmann
    self._cond = threading.Condition(lock=lock)
388 84e344d4 Michael Hanselmann
    self._nwaiters = 0
389 84e344d4 Michael Hanselmann
390 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
391 84e344d4 Michael Hanselmann
    """Notifies the condition.
392 84e344d4 Michael Hanselmann

393 84e344d4 Michael Hanselmann
    """
394 84e344d4 Michael Hanselmann
    return self._cond.notifyAll()
395 84e344d4 Michael Hanselmann
396 84e344d4 Michael Hanselmann
  def wait(self, timeout=None):
397 84e344d4 Michael Hanselmann
    """Waits for the condition to be notified.
398 84e344d4 Michael Hanselmann

399 84e344d4 Michael Hanselmann
    @type timeout: float or None
400 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
401 84e344d4 Michael Hanselmann

402 84e344d4 Michael Hanselmann
    """
403 84e344d4 Michael Hanselmann
    assert self._nwaiters >= 0
404 84e344d4 Michael Hanselmann
405 84e344d4 Michael Hanselmann
    self._nwaiters += 1
406 84e344d4 Michael Hanselmann
    try:
407 84e344d4 Michael Hanselmann
      return self._cond.wait(timeout=timeout)
408 84e344d4 Michael Hanselmann
    finally:
409 84e344d4 Michael Hanselmann
      self._nwaiters -= 1
410 84e344d4 Michael Hanselmann
411 84e344d4 Michael Hanselmann
  def has_waiting(self):
412 84e344d4 Michael Hanselmann
    """Returns whether there are active waiters.
413 84e344d4 Michael Hanselmann

414 84e344d4 Michael Hanselmann
    """
415 84e344d4 Michael Hanselmann
    return bool(self._nwaiters)
416 84e344d4 Michael Hanselmann
417 84e344d4 Michael Hanselmann
418 84e344d4 Michael Hanselmann
class SharedLock(object):
419 162c1c1f Guido Trotter
  """Implements a shared lock.
420 162c1c1f Guido Trotter

421 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
422 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
423 162c1c1f Guido Trotter
  can call acquire_exclusive().
424 162c1c1f Guido Trotter

425 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
426 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
427 162c1c1f Guido Trotter
  eventually do so.
428 162c1c1f Guido Trotter

429 162c1c1f Guido Trotter
  """
430 84e344d4 Michael Hanselmann
  __slots__ = [
431 84e344d4 Michael Hanselmann
    "__active_shr_c",
432 84e344d4 Michael Hanselmann
    "__inactive_shr_c",
433 84e344d4 Michael Hanselmann
    "__deleted",
434 84e344d4 Michael Hanselmann
    "__exc",
435 84e344d4 Michael Hanselmann
    "__lock",
436 84e344d4 Michael Hanselmann
    "__pending",
437 84e344d4 Michael Hanselmann
    "__shr",
438 84e344d4 Michael Hanselmann
    ]
439 84e344d4 Michael Hanselmann
440 34cb5617 Guido Trotter
  __condition_class = PipeCondition
441 84e344d4 Michael Hanselmann
442 162c1c1f Guido Trotter
  def __init__(self):
443 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
444 84e344d4 Michael Hanselmann

445 84e344d4 Michael Hanselmann
    """
446 84e344d4 Michael Hanselmann
    object.__init__(self)
447 84e344d4 Michael Hanselmann
448 84e344d4 Michael Hanselmann
    # Internal lock
449 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
450 162c1c1f Guido Trotter
451 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
452 84e344d4 Michael Hanselmann
    self.__pending = []
453 84e344d4 Michael Hanselmann
454 84e344d4 Michael Hanselmann
    # Active and inactive conditions for shared locks
455 84e344d4 Michael Hanselmann
    self.__active_shr_c = self.__condition_class(self.__lock)
456 84e344d4 Michael Hanselmann
    self.__inactive_shr_c = self.__condition_class(self.__lock)
457 84e344d4 Michael Hanselmann
458 84e344d4 Michael Hanselmann
    # Current lock holders
459 162c1c1f Guido Trotter
    self.__shr = set()
460 162c1c1f Guido Trotter
    self.__exc = None
461 162c1c1f Guido Trotter
462 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
463 a95fd5d7 Guido Trotter
    self.__deleted = False
464 a95fd5d7 Guido Trotter
465 84e344d4 Michael Hanselmann
  def __check_deleted(self):
466 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
467 84e344d4 Michael Hanselmann

468 84e344d4 Michael Hanselmann
    """
469 84e344d4 Michael Hanselmann
    if self.__deleted:
470 84e344d4 Michael Hanselmann
      raise errors.LockError("Deleted lock")
471 84e344d4 Michael Hanselmann
472 162c1c1f Guido Trotter
  def __is_sharer(self):
473 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
474 84e344d4 Michael Hanselmann

475 84e344d4 Michael Hanselmann
    """
476 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
477 162c1c1f Guido Trotter
478 162c1c1f Guido Trotter
  def __is_exclusive(self):
479 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
480 84e344d4 Michael Hanselmann

481 84e344d4 Michael Hanselmann
    """
482 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
483 162c1c1f Guido Trotter
484 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
485 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
486 162c1c1f Guido Trotter

487 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
488 162c1c1f Guido Trotter
    the internal lock.
489 162c1c1f Guido Trotter

490 162c1c1f Guido Trotter
    """
491 162c1c1f Guido Trotter
    if shared < 0:
492 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
493 162c1c1f Guido Trotter
    elif shared:
494 162c1c1f Guido Trotter
      return self.__is_sharer()
495 162c1c1f Guido Trotter
    else:
496 162c1c1f Guido Trotter
      return self.__is_exclusive()
497 162c1c1f Guido Trotter
498 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
499 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
500 162c1c1f Guido Trotter

501 c41eea6e Iustin Pop
    @param shared:
502 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
503 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
504 c41eea6e Iustin Pop
        - > 0: check for shared ownership
505 162c1c1f Guido Trotter

506 162c1c1f Guido Trotter
    """
507 162c1c1f Guido Trotter
    self.__lock.acquire()
508 162c1c1f Guido Trotter
    try:
509 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
510 162c1c1f Guido Trotter
    finally:
511 162c1c1f Guido Trotter
      self.__lock.release()
512 162c1c1f Guido Trotter
513 84e344d4 Michael Hanselmann
  def _count_pending(self):
514 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
515 a95fd5d7 Guido Trotter

516 84e344d4 Michael Hanselmann
    @rtype: int
517 a95fd5d7 Guido Trotter

518 a95fd5d7 Guido Trotter
    """
519 84e344d4 Michael Hanselmann
    self.__lock.acquire()
520 84e344d4 Michael Hanselmann
    try:
521 84e344d4 Michael Hanselmann
      return len(self.__pending)
522 84e344d4 Michael Hanselmann
    finally:
523 84e344d4 Michael Hanselmann
      self.__lock.release()
524 a95fd5d7 Guido Trotter
525 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
526 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
527 84e344d4 Michael Hanselmann

528 84e344d4 Michael Hanselmann
    """
529 84e344d4 Michael Hanselmann
    if shared:
530 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
531 84e344d4 Michael Hanselmann
    else:
532 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
533 a95fd5d7 Guido Trotter
534 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
535 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
536 a95fd5d7 Guido Trotter

537 a95fd5d7 Guido Trotter
    """
538 84e344d4 Michael Hanselmann
    if shared:
539 84e344d4 Michael Hanselmann
      return self.__exc is None
540 84e344d4 Michael Hanselmann
    else:
541 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
542 a95fd5d7 Guido Trotter
543 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
544 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
545 a95fd5d7 Guido Trotter

546 84e344d4 Michael Hanselmann
    The caller must make sure the queue isn't empty.
547 a95fd5d7 Guido Trotter

548 84e344d4 Michael Hanselmann
    """
549 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
550 4d686df8 Guido Trotter
551 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
552 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
553 9216a9f7 Michael Hanselmann

554 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
555 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
556 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
557 9216a9f7 Michael Hanselmann

558 9216a9f7 Michael Hanselmann
    """
559 84e344d4 Michael Hanselmann
    self.__check_deleted()
560 9216a9f7 Michael Hanselmann
561 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
562 84e344d4 Michael Hanselmann
    assert not self.__is_owned(), "double acquire() on a non-recursive lock"
563 84e344d4 Michael Hanselmann
564 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
565 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
566 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
567 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
568 84e344d4 Michael Hanselmann
      return True
569 9216a9f7 Michael Hanselmann
570 84e344d4 Michael Hanselmann
    if shared:
571 84e344d4 Michael Hanselmann
      wait_condition = self.__active_shr_c
572 9216a9f7 Michael Hanselmann
573 84e344d4 Michael Hanselmann
      # Check if we're not yet in the queue
574 84e344d4 Michael Hanselmann
      if wait_condition not in self.__pending:
575 84e344d4 Michael Hanselmann
        self.__pending.append(wait_condition)
576 84e344d4 Michael Hanselmann
    else:
577 84e344d4 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock)
578 84e344d4 Michael Hanselmann
      # Always add to queue
579 84e344d4 Michael Hanselmann
      self.__pending.append(wait_condition)
580 84e344d4 Michael Hanselmann
581 84e344d4 Michael Hanselmann
    try:
582 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
583 84e344d4 Michael Hanselmann
      # expires.
584 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
585 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
586 84e344d4 Michael Hanselmann
        # Wait for notification
587 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
588 84e344d4 Michael Hanselmann
        self.__check_deleted()
589 84e344d4 Michael Hanselmann
590 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
591 84e344d4 Michael Hanselmann
        # internally for that case.
592 84e344d4 Michael Hanselmann
        if timeout is not None:
593 84e344d4 Michael Hanselmann
          break
594 84e344d4 Michael Hanselmann
595 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
596 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
597 84e344d4 Michael Hanselmann
        return True
598 9216a9f7 Michael Hanselmann
    finally:
599 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
600 84e344d4 Michael Hanselmann
      if not wait_condition.has_waiting() and not self.__deleted:
601 84e344d4 Michael Hanselmann
        self.__pending.remove(wait_condition)
602 9216a9f7 Michael Hanselmann
603 84e344d4 Michael Hanselmann
    return False
604 9216a9f7 Michael Hanselmann
605 008b92fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, test_notify=None):
606 162c1c1f Guido Trotter
    """Acquire a shared lock.
607 162c1c1f Guido Trotter

608 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
609 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
610 c41eea6e Iustin Pop
        exclusive lock will be acquired
611 84e344d4 Michael Hanselmann
    @type timeout: float
612 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
613 008b92fa Michael Hanselmann
    @type test_notify: callable or None
614 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
615 162c1c1f Guido Trotter

616 162c1c1f Guido Trotter
    """
617 162c1c1f Guido Trotter
    self.__lock.acquire()
618 162c1c1f Guido Trotter
    try:
619 008b92fa Michael Hanselmann
      # We already got the lock, notify now
620 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
621 008b92fa Michael Hanselmann
        test_notify()
622 008b92fa Michael Hanselmann
623 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
624 162c1c1f Guido Trotter
    finally:
625 162c1c1f Guido Trotter
      self.__lock.release()
626 162c1c1f Guido Trotter
627 162c1c1f Guido Trotter
  def release(self):
628 162c1c1f Guido Trotter
    """Release a Shared Lock.
629 162c1c1f Guido Trotter

630 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
631 162c1c1f Guido Trotter
    before calling this function.
632 162c1c1f Guido Trotter

633 162c1c1f Guido Trotter
    """
634 162c1c1f Guido Trotter
    self.__lock.acquire()
635 162c1c1f Guido Trotter
    try:
636 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
637 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
638 84e344d4 Michael Hanselmann
639 162c1c1f Guido Trotter
      # Autodetect release type
640 162c1c1f Guido Trotter
      if self.__is_exclusive():
641 162c1c1f Guido Trotter
        self.__exc = None
642 84e344d4 Michael Hanselmann
      else:
643 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
644 162c1c1f Guido Trotter
645 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
646 84e344d4 Michael Hanselmann
      if self.__pending:
647 84e344d4 Michael Hanselmann
        first_condition = self.__pending[0]
648 84e344d4 Michael Hanselmann
        first_condition.notifyAll()
649 4d686df8 Guido Trotter
650 84e344d4 Michael Hanselmann
        if first_condition == self.__active_shr_c:
651 84e344d4 Michael Hanselmann
          self.__active_shr_c = self.__inactive_shr_c
652 84e344d4 Michael Hanselmann
          self.__inactive_shr_c = first_condition
653 162c1c1f Guido Trotter
654 162c1c1f Guido Trotter
    finally:
655 162c1c1f Guido Trotter
      self.__lock.release()
656 162c1c1f Guido Trotter
657 84e344d4 Michael Hanselmann
  def delete(self, timeout=None):
658 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
659 a95fd5d7 Guido Trotter

660 a95fd5d7 Guido Trotter
    This operation will declare the lock for removal. First the lock will be
661 a95fd5d7 Guido Trotter
    acquired in exclusive mode if you don't already own it, then the lock
662 a95fd5d7 Guido Trotter
    will be put in a state where any future and pending acquire() fail.
663 a95fd5d7 Guido Trotter

664 84e344d4 Michael Hanselmann
    @type timeout: float
665 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
666 a95fd5d7 Guido Trotter

667 a95fd5d7 Guido Trotter
    """
668 a95fd5d7 Guido Trotter
    self.__lock.acquire()
669 a95fd5d7 Guido Trotter
    try:
670 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
671 84e344d4 Michael Hanselmann
672 84e344d4 Michael Hanselmann
      self.__check_deleted()
673 a95fd5d7 Guido Trotter
674 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
675 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
676 a95fd5d7 Guido Trotter
677 84e344d4 Michael Hanselmann
      if not acquired:
678 a66bd91b Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout)
679 a66bd91b Michael Hanselmann
680 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
681 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
682 84e344d4 Michael Hanselmann
683 84e344d4 Michael Hanselmann
      if acquired:
684 84e344d4 Michael Hanselmann
        self.__deleted = True
685 84e344d4 Michael Hanselmann
        self.__exc = None
686 a95fd5d7 Guido Trotter
687 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
688 84e344d4 Michael Hanselmann
        while self.__pending:
689 84e344d4 Michael Hanselmann
          self.__pending.pop().notifyAll()
690 a95fd5d7 Guido Trotter
691 84e344d4 Michael Hanselmann
      return acquired
692 a95fd5d7 Guido Trotter
    finally:
693 a95fd5d7 Guido Trotter
      self.__lock.release()
694 a95fd5d7 Guido Trotter
695 aaae9bc0 Guido Trotter
696 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
697 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
698 e310b019 Guido Trotter
ALL_SET = None
699 e310b019 Guido Trotter
700 e310b019 Guido Trotter
701 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
702 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
703 5aab242c Michael Hanselmann

704 5aab242c Michael Hanselmann
  """
705 5aab242c Michael Hanselmann
706 5aab242c Michael Hanselmann
707 aaae9bc0 Guido Trotter
class LockSet:
708 aaae9bc0 Guido Trotter
  """Implements a set of locks.
709 aaae9bc0 Guido Trotter

710 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
711 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
712 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
713 aaae9bc0 Guido Trotter
  preventing deadlock.
714 aaae9bc0 Guido Trotter

715 aaae9bc0 Guido Trotter
  All the locks needed in the same set must be acquired together, though.
716 aaae9bc0 Guido Trotter

717 aaae9bc0 Guido Trotter
  """
718 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
719 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
720 aaae9bc0 Guido Trotter

721 ec44d893 Guido Trotter
    @type members: list of strings
722 c41eea6e Iustin Pop
    @param members: initial members of the set
723 aaae9bc0 Guido Trotter

724 aaae9bc0 Guido Trotter
    """
725 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
726 aaae9bc0 Guido Trotter
    self.__lock = SharedLock()
727 aaae9bc0 Guido Trotter
728 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
729 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
730 aaae9bc0 Guido Trotter
    self.__lockdict = {}
731 aaae9bc0 Guido Trotter
732 aaae9bc0 Guido Trotter
    if members is not None:
733 aaae9bc0 Guido Trotter
      for name in members:
734 aaae9bc0 Guido Trotter
        self.__lockdict[name] = SharedLock()
735 aaae9bc0 Guido Trotter
736 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
737 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
738 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
739 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
740 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
741 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
742 aaae9bc0 Guido Trotter
    # will be trouble.
743 aaae9bc0 Guido Trotter
    self.__owners = {}
744 aaae9bc0 Guido Trotter
745 aaae9bc0 Guido Trotter
  def _is_owned(self):
746 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
747 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
748 aaae9bc0 Guido Trotter
749 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
750 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
751 b2dabfd6 Guido Trotter
    if name is None:
752 b2dabfd6 Guido Trotter
      if not self._is_owned():
753 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
754 aaae9bc0 Guido Trotter
    else:
755 b2dabfd6 Guido Trotter
      if self._is_owned():
756 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
757 b2dabfd6 Guido Trotter
      else:
758 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
759 b2dabfd6 Guido Trotter
760 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
761 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
762 aaae9bc0 Guido Trotter
763 e4335b5b Michael Hanselmann
    assert not (name is None and self.__lock._is_owned()), \
764 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
765 e4335b5b Michael Hanselmann
766 b2dabfd6 Guido Trotter
    if name is not None:
767 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
768 b2dabfd6 Guido Trotter
769 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
770 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
771 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
772 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
773 aaae9bc0 Guido Trotter
774 aaae9bc0 Guido Trotter
  def _list_owned(self):
775 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
776 aaae9bc0 Guido Trotter
    if self._is_owned():
777 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
778 aaae9bc0 Guido Trotter
    else:
779 aaae9bc0 Guido Trotter
      return set()
780 aaae9bc0 Guido Trotter
781 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
782 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
783 5aab242c Michael Hanselmann
    for lname in self._list_owned():
784 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
785 56452af7 Michael Hanselmann
      if lock._is_owned():
786 56452af7 Michael Hanselmann
        lock.release()
787 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
788 5aab242c Michael Hanselmann
789 aaae9bc0 Guido Trotter
  def __names(self):
790 aaae9bc0 Guido Trotter
    """Return the current set of names.
791 aaae9bc0 Guido Trotter

792 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
793 aaae9bc0 Guido Trotter
    result after releasing the lock.
794 aaae9bc0 Guido Trotter

795 aaae9bc0 Guido Trotter
    """
796 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
797 aaae9bc0 Guido Trotter
798 aaae9bc0 Guido Trotter
  def _names(self):
799 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
800 aaae9bc0 Guido Trotter

801 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
802 cdb08f44 Michael Hanselmann

803 aaae9bc0 Guido Trotter
    """
804 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
805 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
806 d4803c24 Guido Trotter
    release_lock = False
807 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
808 d4803c24 Guido Trotter
      release_lock = True
809 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
810 aaae9bc0 Guido Trotter
    try:
811 aaae9bc0 Guido Trotter
      result = self.__names()
812 aaae9bc0 Guido Trotter
    finally:
813 d4803c24 Guido Trotter
      if release_lock:
814 d4803c24 Guido Trotter
        self.__lock.release()
815 0cf257c5 Guido Trotter
    return set(result)
816 aaae9bc0 Guido Trotter
817 5aab242c Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, test_notify=None):
818 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
819 aaae9bc0 Guido Trotter

820 ec44d893 Guido Trotter
    @type names: list of strings (or string)
821 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
822 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
823 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
824 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
825 c41eea6e Iustin Pop
        exclusive lock will be acquired
826 5aab242c Michael Hanselmann
    @type timeout: float or None
827 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
828 5aab242c Michael Hanselmann
    @type test_notify: callable or None
829 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
830 aaae9bc0 Guido Trotter

831 5aab242c Michael Hanselmann
    @return: Set of all locks successfully acquired or None in case of timeout
832 aaae9bc0 Guido Trotter

833 c41eea6e Iustin Pop
    @raise errors.LockError: when any lock we try to acquire has
834 c41eea6e Iustin Pop
        been deleted before we succeed. In this case none of the
835 c41eea6e Iustin Pop
        locks requested will be acquired.
836 aaae9bc0 Guido Trotter

837 aaae9bc0 Guido Trotter
    """
838 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
839 aaae9bc0 Guido Trotter
840 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
841 aaae9bc0 Guido Trotter
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
842 aaae9bc0 Guido Trotter
843 5aab242c Michael Hanselmann
    # We need to keep track of how long we spent waiting for a lock. The
844 5aab242c Michael Hanselmann
    # timeout passed to this function is over all lock acquires.
845 7e8841bd Michael Hanselmann
    running_timeout = RunningTimeout(timeout, False)
846 5aab242c Michael Hanselmann
847 806e20fd Guido Trotter
    try:
848 76e2f08a Michael Hanselmann
      if names is not None:
849 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
850 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
851 5aab242c Michael Hanselmann
          names = [names]
852 5aab242c Michael Hanselmann
853 76e2f08a Michael Hanselmann
        return self.__acquire_inner(names, False, shared,
854 7e8841bd Michael Hanselmann
                                    running_timeout.Remaining, test_notify)
855 76e2f08a Michael Hanselmann
856 76e2f08a Michael Hanselmann
      else:
857 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
858 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
859 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
860 76e2f08a Michael Hanselmann
        #
861 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
862 76e2f08a Michael Hanselmann
        # everybody else can use the instances at the same time. If are
863 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
864 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
865 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
866 76e2f08a Michael Hanselmann
        if not self.__lock.acquire(shared=shared,
867 7e8841bd Michael Hanselmann
                                   timeout=running_timeout.Remaining()):
868 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
869 76e2f08a Michael Hanselmann
        try:
870 76e2f08a Michael Hanselmann
          # note we own the set-lock
871 76e2f08a Michael Hanselmann
          self._add_owned()
872 76e2f08a Michael Hanselmann
873 76e2f08a Michael Hanselmann
          return self.__acquire_inner(self.__names(), True, shared,
874 7e8841bd Michael Hanselmann
                                      running_timeout.Remaining, test_notify)
875 76e2f08a Michael Hanselmann
        except:
876 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
877 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
878 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
879 5aab242c Michael Hanselmann
          self.__lock.release()
880 76e2f08a Michael Hanselmann
          self._del_owned()
881 76e2f08a Michael Hanselmann
          raise
882 5aab242c Michael Hanselmann
883 5aab242c Michael Hanselmann
    except _AcquireTimeout:
884 5aab242c Michael Hanselmann
      return None
885 aaae9bc0 Guido Trotter
886 76e2f08a Michael Hanselmann
  def __acquire_inner(self, names, want_all, shared, timeout_fn, test_notify):
887 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
888 7e8841bd Michael Hanselmann

889 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
890 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
891 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
892 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
893 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
894 76e2f08a Michael Hanselmann

895 76e2f08a Michael Hanselmann
    """
896 76e2f08a Michael Hanselmann
    acquire_list = []
897 76e2f08a Michael Hanselmann
898 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
899 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
900 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
901 71e1863e Michael Hanselmann
    # deadlocks.
902 71e1863e Michael Hanselmann
    for lname in sorted(utils.UniqueSequence(names)):
903 76e2f08a Michael Hanselmann
      try:
904 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
905 76e2f08a Michael Hanselmann
      except KeyError:
906 76e2f08a Michael Hanselmann
        if want_all:
907 76e2f08a Michael Hanselmann
          # We are acquiring all the set, it doesn't matter if this particular
908 76e2f08a Michael Hanselmann
          # element is not there anymore.
909 76e2f08a Michael Hanselmann
          continue
910 76e2f08a Michael Hanselmann
911 76e2f08a Michael Hanselmann
        raise errors.LockError("Non-existing lock in set (%s)" % lname)
912 76e2f08a Michael Hanselmann
913 9b154270 Michael Hanselmann
      acquire_list.append((lname, lock))
914 9b154270 Michael Hanselmann
915 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
916 76e2f08a Michael Hanselmann
    acquired = set()
917 76e2f08a Michael Hanselmann
918 76e2f08a Michael Hanselmann
    try:
919 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
920 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
921 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
922 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
923 76e2f08a Michael Hanselmann
      # lock gets deleted.
924 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
925 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
926 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
927 76e2f08a Michael Hanselmann
        else:
928 76e2f08a Michael Hanselmann
          test_notify_fn = None
929 76e2f08a Michael Hanselmann
930 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
931 76e2f08a Michael Hanselmann
932 76e2f08a Michael Hanselmann
        try:
933 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
934 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
935 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
936 76e2f08a Michael Hanselmann
        except errors.LockError:
937 76e2f08a Michael Hanselmann
          if want_all:
938 76e2f08a Michael Hanselmann
            # We are acquiring all the set, it doesn't matter if this
939 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
940 76e2f08a Michael Hanselmann
            continue
941 76e2f08a Michael Hanselmann
942 76e2f08a Michael Hanselmann
          raise errors.LockError("Non-existing lock in set (%s)" % lname)
943 76e2f08a Michael Hanselmann
944 76e2f08a Michael Hanselmann
        if not acq_success:
945 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
946 76e2f08a Michael Hanselmann
          if timeout is None:
947 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
948 76e2f08a Michael Hanselmann
            # blocking.
949 76e2f08a Michael Hanselmann
            raise errors.LockError("Failed to get lock %s" % lname)
950 76e2f08a Michael Hanselmann
951 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
952 76e2f08a Michael Hanselmann
953 76e2f08a Michael Hanselmann
        try:
954 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
955 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
956 76e2f08a Michael Hanselmann
          acquired.add(lname)
957 76e2f08a Michael Hanselmann
958 76e2f08a Michael Hanselmann
        except:
959 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
960 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
961 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
962 76e2f08a Michael Hanselmann
          if lock._is_owned():
963 76e2f08a Michael Hanselmann
            lock.release()
964 76e2f08a Michael Hanselmann
          raise
965 76e2f08a Michael Hanselmann
966 76e2f08a Michael Hanselmann
    except:
967 76e2f08a Michael Hanselmann
      # Release all owned locks
968 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
969 76e2f08a Michael Hanselmann
      raise
970 76e2f08a Michael Hanselmann
971 0cc00929 Guido Trotter
    return acquired
972 aaae9bc0 Guido Trotter
973 aaae9bc0 Guido Trotter
  def release(self, names=None):
974 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
975 aaae9bc0 Guido Trotter

976 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
977 aaae9bc0 Guido Trotter
    before releasing them.
978 aaae9bc0 Guido Trotter

979 ec44d893 Guido Trotter
    @type names: list of strings, or None
980 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
981 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level).
982 aaae9bc0 Guido Trotter

983 aaae9bc0 Guido Trotter
    """
984 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
985 aaae9bc0 Guido Trotter
986 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
987 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
988 aaae9bc0 Guido Trotter
      names = [names]
989 aaae9bc0 Guido Trotter
990 aaae9bc0 Guido Trotter
    if names is None:
991 aaae9bc0 Guido Trotter
      names = self._list_owned()
992 aaae9bc0 Guido Trotter
    else:
993 aaae9bc0 Guido Trotter
      names = set(names)
994 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
995 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
996 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
997 aaae9bc0 Guido Trotter
998 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
999 3b7ed473 Guido Trotter
    # After this 'add' can work again
1000 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
1001 3b7ed473 Guido Trotter
      self.__lock.release()
1002 b2dabfd6 Guido Trotter
      self._del_owned()
1003 3b7ed473 Guido Trotter
1004 aaae9bc0 Guido Trotter
    for lockname in names:
1005 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1006 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1007 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1008 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1009 aaae9bc0 Guido Trotter
1010 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1011 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1012 aaae9bc0 Guido Trotter

1013 ec44d893 Guido Trotter
    @type names: list of strings
1014 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1015 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1016 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1017 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1018 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1019 aaae9bc0 Guido Trotter

1020 aaae9bc0 Guido Trotter
    """
1021 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1022 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
1023 d2aff862 Guido Trotter
      "Cannot add locks if the set is only partially owned, or shared"
1024 3b7ed473 Guido Trotter
1025 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1026 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1027 aaae9bc0 Guido Trotter
      names = [names]
1028 aaae9bc0 Guido Trotter
1029 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1030 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1031 3b7ed473 Guido Trotter
    release_lock = False
1032 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
1033 3b7ed473 Guido Trotter
      release_lock = True
1034 3b7ed473 Guido Trotter
      self.__lock.acquire()
1035 3b7ed473 Guido Trotter
1036 aaae9bc0 Guido Trotter
    try:
1037 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1038 aaae9bc0 Guido Trotter
      if invalid_names:
1039 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1040 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1041 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1042 aaae9bc0 Guido Trotter
        raise errors.LockError("duplicate add() (%s)" % invalid_names)
1043 aaae9bc0 Guido Trotter
1044 aaae9bc0 Guido Trotter
      for lockname in names:
1045 aaae9bc0 Guido Trotter
        lock = SharedLock()
1046 aaae9bc0 Guido Trotter
1047 aaae9bc0 Guido Trotter
        if acquired:
1048 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1049 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1050 aaae9bc0 Guido Trotter
          try:
1051 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1052 aaae9bc0 Guido Trotter
          except:
1053 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1054 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1055 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1056 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1057 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1058 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1059 aaae9bc0 Guido Trotter
            lock.release()
1060 aaae9bc0 Guido Trotter
            raise
1061 aaae9bc0 Guido Trotter
1062 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1063 aaae9bc0 Guido Trotter
1064 aaae9bc0 Guido Trotter
    finally:
1065 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1066 3b7ed473 Guido Trotter
      if release_lock:
1067 3b7ed473 Guido Trotter
        self.__lock.release()
1068 aaae9bc0 Guido Trotter
1069 aaae9bc0 Guido Trotter
    return True
1070 aaae9bc0 Guido Trotter
1071 5e0a6daf Michael Hanselmann
  def remove(self, names):
1072 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1073 aaae9bc0 Guido Trotter

1074 aaae9bc0 Guido Trotter
    You can either not hold anything in the lockset or already hold a superset
1075 aaae9bc0 Guido Trotter
    of the elements you want to delete, exclusively.
1076 aaae9bc0 Guido Trotter

1077 ec44d893 Guido Trotter
    @type names: list of strings
1078 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1079 aaae9bc0 Guido Trotter

1080 5aab242c Michael Hanselmann
    @return: a list of locks which we removed; the list is always
1081 c41eea6e Iustin Pop
        equal to the names list if we were holding all the locks
1082 c41eea6e Iustin Pop
        exclusively
1083 aaae9bc0 Guido Trotter

1084 aaae9bc0 Guido Trotter
    """
1085 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1086 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1087 aaae9bc0 Guido Trotter
      names = [names]
1088 aaae9bc0 Guido Trotter
1089 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1090 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1091 aaae9bc0 Guido Trotter
    # by the lock itself.
1092 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
1093 aaae9bc0 Guido Trotter
      "remove() on acquired lockset while not owning all elements")
1094 aaae9bc0 Guido Trotter
1095 3f404fc5 Guido Trotter
    removed = []
1096 aaae9bc0 Guido Trotter
1097 aaae9bc0 Guido Trotter
    for lname in names:
1098 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1099 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1100 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1101 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1102 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1103 aaae9bc0 Guido Trotter
      try:
1104 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1105 3f404fc5 Guido Trotter
        removed.append(lname)
1106 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1107 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1108 aaae9bc0 Guido Trotter
        assert not self._is_owned(), "remove failed while holding lockset"
1109 aaae9bc0 Guido Trotter
      else:
1110 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1111 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1112 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1113 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1114 aaae9bc0 Guido Trotter
        #
1115 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1116 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1117 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1118 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1119 aaae9bc0 Guido Trotter
        if self._is_owned():
1120 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1121 aaae9bc0 Guido Trotter
1122 3f404fc5 Guido Trotter
    return removed
1123 aaae9bc0 Guido Trotter
1124 7ee7c0c7 Guido Trotter
1125 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1126 7ee7c0c7 Guido Trotter
# Current rules are:
1127 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1128 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1129 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1130 7ee7c0c7 Guido Trotter
#   avoided.
1131 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1132 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1133 7ee7c0c7 Guido Trotter
#   the same time.
1134 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1135 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1136 04e1bfaf Guido Trotter
LEVEL_NODE = 2
1137 7ee7c0c7 Guido Trotter
1138 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1139 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1140 04e1bfaf Guido Trotter
          LEVEL_NODE]
1141 7ee7c0c7 Guido Trotter
1142 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1143 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
1144 7ee7c0c7 Guido Trotter
1145 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1146 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1147 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1148 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1149 ea205dbc Michael Hanselmann
  }
1150 ea205dbc Michael Hanselmann
1151 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1152 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1153 7ee7c0c7 Guido Trotter
1154 7ee7c0c7 Guido Trotter
1155 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1156 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1157 7ee7c0c7 Guido Trotter

1158 5bbd3f7f Michael Hanselmann
  The purpose of this small library is to manage locking for ganeti clusters
1159 7ee7c0c7 Guido Trotter
  in a central place, while at the same time doing dynamic checks against
1160 7ee7c0c7 Guido Trotter
  possible deadlocks. It will also make it easier to transition to a different
1161 7ee7c0c7 Guido Trotter
  lock type should we migrate away from python threads.
1162 7ee7c0c7 Guido Trotter

1163 7ee7c0c7 Guido Trotter
  """
1164 7ee7c0c7 Guido Trotter
  _instance = None
1165 7ee7c0c7 Guido Trotter
1166 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1167 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1168 7ee7c0c7 Guido Trotter

1169 4e07ec8c Guido Trotter
    There should be only a GanetiLockManager object at any time, so this
1170 4e07ec8c Guido Trotter
    function raises an error if this is not the case.
1171 7ee7c0c7 Guido Trotter

1172 c41eea6e Iustin Pop
    @param nodes: list of node names
1173 c41eea6e Iustin Pop
    @param instances: list of instance names
1174 7ee7c0c7 Guido Trotter

1175 7ee7c0c7 Guido Trotter
    """
1176 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1177 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1178 c41eea6e Iustin Pop
1179 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1180 7ee7c0c7 Guido Trotter
1181 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1182 7ee7c0c7 Guido Trotter
    # locking order.
1183 7ee7c0c7 Guido Trotter
    self.__keyring = {
1184 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
1185 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
1186 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
1187 7ee7c0c7 Guido Trotter
    }
1188 7ee7c0c7 Guido Trotter
1189 7ee7c0c7 Guido Trotter
  def _names(self, level):
1190 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1191 7ee7c0c7 Guido Trotter

1192 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1193 c41eea6e Iustin Pop

1194 c41eea6e Iustin Pop
    @param level: the level whose list of locks to get
1195 7ee7c0c7 Guido Trotter

1196 7ee7c0c7 Guido Trotter
    """
1197 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1198 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1199 7ee7c0c7 Guido Trotter
1200 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1201 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1202 7ee7c0c7 Guido Trotter

1203 7ee7c0c7 Guido Trotter
    """
1204 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1205 7ee7c0c7 Guido Trotter
1206 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1207 d4f4b3e7 Guido Trotter
1208 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1209 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1210 7ee7c0c7 Guido Trotter

1211 7ee7c0c7 Guido Trotter
    """
1212 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1213 7ee7c0c7 Guido Trotter
1214 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1215 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1216 7ee7c0c7 Guido Trotter

1217 7ee7c0c7 Guido Trotter
    """
1218 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1219 7ee7c0c7 Guido Trotter
    # the test cases.
1220 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1221 7ee7c0c7 Guido Trotter
1222 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1223 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1224 7ee7c0c7 Guido Trotter

1225 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1226 7ee7c0c7 Guido Trotter

1227 7ee7c0c7 Guido Trotter
    """
1228 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1229 7ee7c0c7 Guido Trotter
1230 c70d2d9b Iustin Pop
  @staticmethod
1231 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1232 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1233 c41eea6e Iustin Pop

1234 c41eea6e Iustin Pop
    Check if acting on the given level and set of names will change
1235 c41eea6e Iustin Pop
    the status of the Big Ganeti Lock.
1236 7ee7c0c7 Guido Trotter

1237 7ee7c0c7 Guido Trotter
    """
1238 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1239 7ee7c0c7 Guido Trotter
1240 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1241 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1242 7ee7c0c7 Guido Trotter

1243 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1244 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1245 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1246 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1247 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1248 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1249 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1250 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1251 5e0a6daf Michael Hanselmann
    @type timeout: float
1252 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1253 7ee7c0c7 Guido Trotter

1254 7ee7c0c7 Guido Trotter
    """
1255 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1256 7ee7c0c7 Guido Trotter
1257 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1258 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1259 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1260 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1261 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1262 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1263 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1264 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1265 7ee7c0c7 Guido Trotter
1266 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1267 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1268 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1269 7ee7c0c7 Guido Trotter
1270 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1271 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1272 7ee7c0c7 Guido Trotter
1273 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1274 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1275 7ee7c0c7 Guido Trotter

1276 c41eea6e Iustin Pop
    You must have acquired the locks, either in shared or in exclusive
1277 c41eea6e Iustin Pop
    mode, before releasing them.
1278 7ee7c0c7 Guido Trotter

1279 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1280 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1281 ec44d893 Guido Trotter
    @type names: list of strings, or None
1282 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1283 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1284 7ee7c0c7 Guido Trotter

1285 7ee7c0c7 Guido Trotter
    """
1286 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1287 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1288 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1289 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1290 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1291 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1292 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1293 7ee7c0c7 Guido Trotter
1294 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1295 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1296 7ee7c0c7 Guido Trotter
1297 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1298 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1299 7ee7c0c7 Guido Trotter

1300 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1301 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1302 ec44d893 Guido Trotter
    @type names: list of strings
1303 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1304 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1305 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1306 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1307 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1308 c41eea6e Iustin Pop

1309 7ee7c0c7 Guido Trotter
    """
1310 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1311 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1312 7ee7c0c7 Guido Trotter
           " operations")
1313 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1314 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1315 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1316 7ee7c0c7 Guido Trotter
1317 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1318 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1319 7ee7c0c7 Guido Trotter

1320 c41eea6e Iustin Pop
    You must either already own the locks you are trying to remove
1321 c41eea6e Iustin Pop
    exclusively or not own any lock at an upper level.
1322 7ee7c0c7 Guido Trotter

1323 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1324 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1325 ec44d893 Guido Trotter
    @type names: list of strings
1326 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1327 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1328 7ee7c0c7 Guido Trotter

1329 7ee7c0c7 Guido Trotter
    """
1330 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1331 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1332 7ee7c0c7 Guido Trotter
           " operations")
1333 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1334 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1335 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1336 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1337 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1338 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1339 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)