Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ f4e673fb

History | View | Annotate | Download (39.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 69b99987 Michael Hanselmann
# Disable "Invalid name ..." message
22 69b99987 Michael Hanselmann
# pylint: disable-msg=C0103
23 69b99987 Michael Hanselmann
24 162c1c1f Guido Trotter
"""Module implementing the Ganeti locking code."""
25 162c1c1f Guido Trotter
26 d76167a5 Michael Hanselmann
import os
27 d76167a5 Michael Hanselmann
import select
28 162c1c1f Guido Trotter
import threading
29 d76167a5 Michael Hanselmann
import time
30 d76167a5 Michael Hanselmann
import errno
31 84e344d4 Michael Hanselmann
32 a95fd5d7 Guido Trotter
from ganeti import errors
33 7ee7c0c7 Guido Trotter
from ganeti import utils
34 162c1c1f Guido Trotter
35 162c1c1f Guido Trotter
36 42a999d1 Guido Trotter
def ssynchronized(lock, shared=0):
37 42a999d1 Guido Trotter
  """Shared Synchronization decorator.
38 42a999d1 Guido Trotter

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

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

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

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

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

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

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

120 d76167a5 Michael Hanselmann
    @type poller: select.poll
121 d76167a5 Michael Hanselmann
    @param poller: Poller object
122 d76167a5 Michael Hanselmann
    @type fd: int
123 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
124 d76167a5 Michael Hanselmann

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

133 d76167a5 Michael Hanselmann
    @type timeout: float or None
134 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
135 d76167a5 Michael Hanselmann

136 d76167a5 Michael Hanselmann
    """
137 f4e673fb Michael Hanselmann
    running_timeout = RunningTimeout(timeout, True)
138 f4e673fb Michael Hanselmann
139 f4e673fb Michael Hanselmann
    while True:
140 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
141 f4e673fb Michael Hanselmann
142 f4e673fb Michael Hanselmann
      if remaining_time is not None and remaining_time < 0.0:
143 f4e673fb Michael Hanselmann
        break
144 d76167a5 Michael Hanselmann
145 d76167a5 Michael Hanselmann
      try:
146 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
147 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
148 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
149 d76167a5 Michael Hanselmann
          raise
150 d76167a5 Michael Hanselmann
        result = None
151 d76167a5 Michael Hanselmann
152 d76167a5 Michael Hanselmann
      # Check whether we were notified
153 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
154 d76167a5 Michael Hanselmann
        break
155 d76167a5 Michael Hanselmann
156 d76167a5 Michael Hanselmann
157 2419060d Guido Trotter
class _BaseCondition(object):
158 2419060d Guido Trotter
  """Base class containing common code for conditions.
159 2419060d Guido Trotter

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

162 2419060d Guido Trotter
  """
163 2419060d Guido Trotter
  __slots__ = [
164 2419060d Guido Trotter
    "_lock",
165 2419060d Guido Trotter
    "acquire",
166 2419060d Guido Trotter
    "release",
167 2419060d Guido Trotter
    ]
168 2419060d Guido Trotter
169 2419060d Guido Trotter
  def __init__(self, lock):
170 2419060d Guido Trotter
    """Constructor for _BaseCondition.
171 2419060d Guido Trotter

172 69b99987 Michael Hanselmann
    @type lock: threading.Lock
173 2419060d Guido Trotter
    @param lock: condition base lock
174 2419060d Guido Trotter

175 2419060d Guido Trotter
    """
176 2419060d Guido Trotter
    object.__init__(self)
177 2419060d Guido Trotter
178 2419060d Guido Trotter
    # Recursive locks are not supported
179 2419060d Guido Trotter
    assert not hasattr(lock, "_acquire_restore")
180 2419060d Guido Trotter
    assert not hasattr(lock, "_release_save")
181 2419060d Guido Trotter
182 2419060d Guido Trotter
    self._lock = lock
183 2419060d Guido Trotter
184 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
185 2419060d Guido Trotter
    self.acquire = lock.acquire
186 2419060d Guido Trotter
    self.release = lock.release
187 2419060d Guido Trotter
188 2419060d Guido Trotter
  def _is_owned(self):
189 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
190 2419060d Guido Trotter

191 2419060d Guido Trotter
    """
192 2419060d Guido Trotter
    if self._lock.acquire(0):
193 2419060d Guido Trotter
      self._lock.release()
194 2419060d Guido Trotter
      return False
195 2419060d Guido Trotter
196 2419060d Guido Trotter
    return True
197 2419060d Guido Trotter
198 2419060d Guido Trotter
  def _check_owned(self):
199 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
200 2419060d Guido Trotter

201 2419060d Guido Trotter
    """
202 2419060d Guido Trotter
    if not self._is_owned():
203 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
204 2419060d Guido Trotter
205 2419060d Guido Trotter
206 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
207 34cb5617 Guido Trotter
  """Condition which can only be notified once.
208 d76167a5 Michael Hanselmann

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

215 d76167a5 Michael Hanselmann
  """
216 34cb5617 Guido Trotter
217 34cb5617 Guido Trotter
  __slots__ = _BaseCondition.__slots__ + [
218 d76167a5 Michael Hanselmann
    "_poller",
219 d76167a5 Michael Hanselmann
    "_read_fd",
220 d76167a5 Michael Hanselmann
    "_write_fd",
221 d76167a5 Michael Hanselmann
    "_nwaiters",
222 34cb5617 Guido Trotter
    "_notified",
223 d76167a5 Michael Hanselmann
    ]
224 d76167a5 Michael Hanselmann
225 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
226 d76167a5 Michael Hanselmann
227 34cb5617 Guido Trotter
  def __init__(self, lock):
228 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
229 d76167a5 Michael Hanselmann

230 d76167a5 Michael Hanselmann
    """
231 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
232 d76167a5 Michael Hanselmann
    self._nwaiters = 0
233 34cb5617 Guido Trotter
    self._notified = False
234 34cb5617 Guido Trotter
    self._read_fd = None
235 34cb5617 Guido Trotter
    self._write_fd = None
236 34cb5617 Guido Trotter
    self._poller = None
237 d76167a5 Michael Hanselmann
238 34cb5617 Guido Trotter
  def _check_unnotified(self):
239 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
240 69b99987 Michael Hanselmann

241 69b99987 Michael Hanselmann
    """
242 34cb5617 Guido Trotter
    if self._notified:
243 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
244 d76167a5 Michael Hanselmann
245 34cb5617 Guido Trotter
  def _Cleanup(self):
246 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
247 d76167a5 Michael Hanselmann

248 d76167a5 Michael Hanselmann
    """
249 34cb5617 Guido Trotter
    if self._read_fd is not None:
250 34cb5617 Guido Trotter
      os.close(self._read_fd)
251 34cb5617 Guido Trotter
      self._read_fd = None
252 d76167a5 Michael Hanselmann
253 34cb5617 Guido Trotter
    if self._write_fd is not None:
254 34cb5617 Guido Trotter
      os.close(self._write_fd)
255 34cb5617 Guido Trotter
      self._write_fd = None
256 34cb5617 Guido Trotter
    self._poller = None
257 d76167a5 Michael Hanselmann
258 34cb5617 Guido Trotter
  def wait(self, timeout=None):
259 34cb5617 Guido Trotter
    """Wait for a notification.
260 d76167a5 Michael Hanselmann

261 34cb5617 Guido Trotter
    @type timeout: float or None
262 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
263 d76167a5 Michael Hanselmann

264 d76167a5 Michael Hanselmann
    """
265 34cb5617 Guido Trotter
    self._check_owned()
266 34cb5617 Guido Trotter
    self._check_unnotified()
267 d76167a5 Michael Hanselmann
268 34cb5617 Guido Trotter
    self._nwaiters += 1
269 34cb5617 Guido Trotter
    try:
270 34cb5617 Guido Trotter
      if self._poller is None:
271 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
272 34cb5617 Guido Trotter
        self._poller = select.poll()
273 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
274 d76167a5 Michael Hanselmann
275 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
276 34cb5617 Guido Trotter
      self.release()
277 34cb5617 Guido Trotter
      try:
278 34cb5617 Guido Trotter
        # Wait for notification
279 34cb5617 Guido Trotter
        wait_fn(timeout)
280 34cb5617 Guido Trotter
      finally:
281 34cb5617 Guido Trotter
        # Re-acquire lock
282 34cb5617 Guido Trotter
        self.acquire()
283 34cb5617 Guido Trotter
    finally:
284 34cb5617 Guido Trotter
      self._nwaiters -= 1
285 34cb5617 Guido Trotter
      if self._nwaiters == 0:
286 34cb5617 Guido Trotter
        self._Cleanup()
287 d76167a5 Michael Hanselmann
288 d76167a5 Michael Hanselmann
  def notifyAll(self):
289 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
290 d76167a5 Michael Hanselmann

291 d76167a5 Michael Hanselmann
    """
292 34cb5617 Guido Trotter
    self._check_owned()
293 34cb5617 Guido Trotter
    self._check_unnotified()
294 34cb5617 Guido Trotter
    self._notified = True
295 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
296 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
297 d76167a5 Michael Hanselmann
      self._write_fd = None
298 d76167a5 Michael Hanselmann
299 d76167a5 Michael Hanselmann
300 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
301 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
302 48dabc6a Michael Hanselmann

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

309 48dabc6a Michael Hanselmann
  """
310 2419060d Guido Trotter
  __slots__ = _BaseCondition.__slots__ + [
311 48dabc6a Michael Hanselmann
    "_nwaiters",
312 34cb5617 Guido Trotter
    "_single_condition",
313 48dabc6a Michael Hanselmann
    ]
314 48dabc6a Michael Hanselmann
315 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
316 48dabc6a Michael Hanselmann
317 48dabc6a Michael Hanselmann
  def __init__(self, lock):
318 48dabc6a Michael Hanselmann
    """Initializes this class.
319 48dabc6a Michael Hanselmann

320 48dabc6a Michael Hanselmann
    """
321 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
322 48dabc6a Michael Hanselmann
    self._nwaiters = 0
323 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
324 48dabc6a Michael Hanselmann
325 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
326 48dabc6a Michael Hanselmann
    """Wait for a notification.
327 48dabc6a Michael Hanselmann

328 48dabc6a Michael Hanselmann
    @type timeout: float or None
329 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
330 48dabc6a Michael Hanselmann

331 48dabc6a Michael Hanselmann
    """
332 48dabc6a Michael Hanselmann
    self._check_owned()
333 48dabc6a Michael Hanselmann
334 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
335 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
336 34cb5617 Guido Trotter
    my_condition = self._single_condition
337 48dabc6a Michael Hanselmann
338 48dabc6a Michael Hanselmann
    assert self._nwaiters >= 0
339 48dabc6a Michael Hanselmann
    self._nwaiters += 1
340 48dabc6a Michael Hanselmann
    try:
341 34cb5617 Guido Trotter
      my_condition.wait(timeout)
342 48dabc6a Michael Hanselmann
    finally:
343 48dabc6a Michael Hanselmann
      assert self._nwaiters > 0
344 48dabc6a Michael Hanselmann
      self._nwaiters -= 1
345 48dabc6a Michael Hanselmann
346 48dabc6a Michael Hanselmann
  def notifyAll(self):
347 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
348 48dabc6a Michael Hanselmann

349 48dabc6a Michael Hanselmann
    """
350 48dabc6a Michael Hanselmann
    self._check_owned()
351 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
352 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
353 48dabc6a Michael Hanselmann
354 48dabc6a Michael Hanselmann
  def has_waiting(self):
355 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
356 48dabc6a Michael Hanselmann

357 48dabc6a Michael Hanselmann
    """
358 48dabc6a Michael Hanselmann
    self._check_owned()
359 48dabc6a Michael Hanselmann
360 48dabc6a Michael Hanselmann
    return bool(self._nwaiters)
361 48dabc6a Michael Hanselmann
362 48dabc6a Michael Hanselmann
363 84e344d4 Michael Hanselmann
class _CountingCondition(object):
364 84e344d4 Michael Hanselmann
  """Wrapper for Python's built-in threading.Condition class.
365 84e344d4 Michael Hanselmann

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

369 84e344d4 Michael Hanselmann
  """
370 84e344d4 Michael Hanselmann
  __slots__ = [
371 84e344d4 Michael Hanselmann
    "_cond",
372 84e344d4 Michael Hanselmann
    "_nwaiters",
373 84e344d4 Michael Hanselmann
    ]
374 84e344d4 Michael Hanselmann
375 84e344d4 Michael Hanselmann
  def __init__(self, lock):
376 84e344d4 Michael Hanselmann
    """Initializes this class.
377 84e344d4 Michael Hanselmann

378 84e344d4 Michael Hanselmann
    """
379 84e344d4 Michael Hanselmann
    object.__init__(self)
380 84e344d4 Michael Hanselmann
    self._cond = threading.Condition(lock=lock)
381 84e344d4 Michael Hanselmann
    self._nwaiters = 0
382 84e344d4 Michael Hanselmann
383 84e344d4 Michael Hanselmann
  def notifyAll(self):
384 84e344d4 Michael Hanselmann
    """Notifies the condition.
385 84e344d4 Michael Hanselmann

386 84e344d4 Michael Hanselmann
    """
387 84e344d4 Michael Hanselmann
    return self._cond.notifyAll()
388 84e344d4 Michael Hanselmann
389 84e344d4 Michael Hanselmann
  def wait(self, timeout=None):
390 84e344d4 Michael Hanselmann
    """Waits for the condition to be notified.
391 84e344d4 Michael Hanselmann

392 84e344d4 Michael Hanselmann
    @type timeout: float or None
393 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
394 84e344d4 Michael Hanselmann

395 84e344d4 Michael Hanselmann
    """
396 84e344d4 Michael Hanselmann
    assert self._nwaiters >= 0
397 84e344d4 Michael Hanselmann
398 84e344d4 Michael Hanselmann
    self._nwaiters += 1
399 84e344d4 Michael Hanselmann
    try:
400 84e344d4 Michael Hanselmann
      return self._cond.wait(timeout=timeout)
401 84e344d4 Michael Hanselmann
    finally:
402 84e344d4 Michael Hanselmann
      self._nwaiters -= 1
403 84e344d4 Michael Hanselmann
404 84e344d4 Michael Hanselmann
  def has_waiting(self):
405 84e344d4 Michael Hanselmann
    """Returns whether there are active waiters.
406 84e344d4 Michael Hanselmann

407 84e344d4 Michael Hanselmann
    """
408 84e344d4 Michael Hanselmann
    return bool(self._nwaiters)
409 84e344d4 Michael Hanselmann
410 84e344d4 Michael Hanselmann
411 84e344d4 Michael Hanselmann
class SharedLock(object):
412 162c1c1f Guido Trotter
  """Implements a shared lock.
413 162c1c1f Guido Trotter

414 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
415 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
416 162c1c1f Guido Trotter
  can call acquire_exclusive().
417 162c1c1f Guido Trotter

418 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
419 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
420 162c1c1f Guido Trotter
  eventually do so.
421 162c1c1f Guido Trotter

422 162c1c1f Guido Trotter
  """
423 84e344d4 Michael Hanselmann
  __slots__ = [
424 84e344d4 Michael Hanselmann
    "__active_shr_c",
425 84e344d4 Michael Hanselmann
    "__inactive_shr_c",
426 84e344d4 Michael Hanselmann
    "__deleted",
427 84e344d4 Michael Hanselmann
    "__exc",
428 84e344d4 Michael Hanselmann
    "__lock",
429 84e344d4 Michael Hanselmann
    "__pending",
430 84e344d4 Michael Hanselmann
    "__shr",
431 84e344d4 Michael Hanselmann
    ]
432 84e344d4 Michael Hanselmann
433 34cb5617 Guido Trotter
  __condition_class = PipeCondition
434 84e344d4 Michael Hanselmann
435 162c1c1f Guido Trotter
  def __init__(self):
436 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
437 84e344d4 Michael Hanselmann

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

461 84e344d4 Michael Hanselmann
    """
462 84e344d4 Michael Hanselmann
    if self.__deleted:
463 84e344d4 Michael Hanselmann
      raise errors.LockError("Deleted lock")
464 84e344d4 Michael Hanselmann
465 162c1c1f Guido Trotter
  def __is_sharer(self):
466 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
467 84e344d4 Michael Hanselmann

468 84e344d4 Michael Hanselmann
    """
469 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
470 162c1c1f Guido Trotter
471 162c1c1f Guido Trotter
  def __is_exclusive(self):
472 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
473 84e344d4 Michael Hanselmann

474 84e344d4 Michael Hanselmann
    """
475 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
476 162c1c1f Guido Trotter
477 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
478 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
479 162c1c1f Guido Trotter

480 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
481 162c1c1f Guido Trotter
    the internal lock.
482 162c1c1f Guido Trotter

483 162c1c1f Guido Trotter
    """
484 162c1c1f Guido Trotter
    if shared < 0:
485 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
486 162c1c1f Guido Trotter
    elif shared:
487 162c1c1f Guido Trotter
      return self.__is_sharer()
488 162c1c1f Guido Trotter
    else:
489 162c1c1f Guido Trotter
      return self.__is_exclusive()
490 162c1c1f Guido Trotter
491 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
492 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
493 162c1c1f Guido Trotter

494 c41eea6e Iustin Pop
    @param shared:
495 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
496 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
497 c41eea6e Iustin Pop
        - > 0: check for shared ownership
498 162c1c1f Guido Trotter

499 162c1c1f Guido Trotter
    """
500 162c1c1f Guido Trotter
    self.__lock.acquire()
501 162c1c1f Guido Trotter
    try:
502 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
503 162c1c1f Guido Trotter
    finally:
504 162c1c1f Guido Trotter
      self.__lock.release()
505 162c1c1f Guido Trotter
506 84e344d4 Michael Hanselmann
  def _count_pending(self):
507 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
508 a95fd5d7 Guido Trotter

509 84e344d4 Michael Hanselmann
    @rtype: int
510 a95fd5d7 Guido Trotter

511 a95fd5d7 Guido Trotter
    """
512 84e344d4 Michael Hanselmann
    self.__lock.acquire()
513 84e344d4 Michael Hanselmann
    try:
514 84e344d4 Michael Hanselmann
      return len(self.__pending)
515 84e344d4 Michael Hanselmann
    finally:
516 84e344d4 Michael Hanselmann
      self.__lock.release()
517 a95fd5d7 Guido Trotter
518 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
519 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
520 84e344d4 Michael Hanselmann

521 84e344d4 Michael Hanselmann
    """
522 84e344d4 Michael Hanselmann
    if shared:
523 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
524 84e344d4 Michael Hanselmann
    else:
525 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
526 a95fd5d7 Guido Trotter
527 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
528 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
529 a95fd5d7 Guido Trotter

530 a95fd5d7 Guido Trotter
    """
531 84e344d4 Michael Hanselmann
    if shared:
532 84e344d4 Michael Hanselmann
      return self.__exc is None
533 84e344d4 Michael Hanselmann
    else:
534 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
535 a95fd5d7 Guido Trotter
536 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
537 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
538 a95fd5d7 Guido Trotter

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

541 84e344d4 Michael Hanselmann
    """
542 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
543 4d686df8 Guido Trotter
544 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
545 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
546 9216a9f7 Michael Hanselmann

547 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
548 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
549 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
550 9216a9f7 Michael Hanselmann

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

601 84e344d4 Michael Hanselmann
    @type shared: int
602 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
603 c41eea6e Iustin Pop
        exclusive lock will be acquired
604 84e344d4 Michael Hanselmann
    @type timeout: float
605 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
606 008b92fa Michael Hanselmann
    @type test_notify: callable or None
607 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
608 162c1c1f Guido Trotter

609 162c1c1f Guido Trotter
    """
610 162c1c1f Guido Trotter
    self.__lock.acquire()
611 162c1c1f Guido Trotter
    try:
612 008b92fa Michael Hanselmann
      # We already got the lock, notify now
613 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
614 008b92fa Michael Hanselmann
        test_notify()
615 008b92fa Michael Hanselmann
616 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
617 162c1c1f Guido Trotter
    finally:
618 162c1c1f Guido Trotter
      self.__lock.release()
619 162c1c1f Guido Trotter
620 162c1c1f Guido Trotter
  def release(self):
621 162c1c1f Guido Trotter
    """Release a Shared Lock.
622 162c1c1f Guido Trotter

623 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
624 162c1c1f Guido Trotter
    before calling this function.
625 162c1c1f Guido Trotter

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

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

657 84e344d4 Michael Hanselmann
    @type timeout: float
658 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
659 a95fd5d7 Guido Trotter

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

697 5aab242c Michael Hanselmann
  """
698 5aab242c Michael Hanselmann
699 5aab242c Michael Hanselmann
700 aaae9bc0 Guido Trotter
class LockSet:
701 aaae9bc0 Guido Trotter
  """Implements a set of locks.
702 aaae9bc0 Guido Trotter

703 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
704 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
705 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
706 aaae9bc0 Guido Trotter
  preventing deadlock.
707 aaae9bc0 Guido Trotter

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

710 aaae9bc0 Guido Trotter
  """
711 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
712 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
713 aaae9bc0 Guido Trotter

714 c41eea6e Iustin Pop
    @param members: initial members of the set
715 aaae9bc0 Guido Trotter

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

782 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
783 aaae9bc0 Guido Trotter
    result after releasing the lock.
784 aaae9bc0 Guido Trotter

785 aaae9bc0 Guido Trotter
    """
786 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
787 aaae9bc0 Guido Trotter
788 aaae9bc0 Guido Trotter
  def _names(self):
789 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
790 aaae9bc0 Guido Trotter

791 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
792 cdb08f44 Michael Hanselmann

793 aaae9bc0 Guido Trotter
    """
794 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
795 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
796 d4803c24 Guido Trotter
    release_lock = False
797 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
798 d4803c24 Guido Trotter
      release_lock = True
799 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
800 aaae9bc0 Guido Trotter
    try:
801 aaae9bc0 Guido Trotter
      result = self.__names()
802 aaae9bc0 Guido Trotter
    finally:
803 d4803c24 Guido Trotter
      if release_lock:
804 d4803c24 Guido Trotter
        self.__lock.release()
805 0cf257c5 Guido Trotter
    return set(result)
806 aaae9bc0 Guido Trotter
807 5aab242c Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, test_notify=None):
808 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
809 aaae9bc0 Guido Trotter

810 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
811 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
812 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
813 c41eea6e Iustin Pop
        exclusive lock will be acquired
814 5aab242c Michael Hanselmann
    @type timeout: float or None
815 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
816 5aab242c Michael Hanselmann
    @type test_notify: callable or None
817 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
818 aaae9bc0 Guido Trotter

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

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

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

879 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
880 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
881 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
882 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
883 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
884 76e2f08a Michael Hanselmann

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

964 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
965 aaae9bc0 Guido Trotter
    before releasing them.
966 aaae9bc0 Guido Trotter

967 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
968 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level).
969 aaae9bc0 Guido Trotter

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

1000 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1001 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1002 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1003 aaae9bc0 Guido Trotter

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

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

1061 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1062 aaae9bc0 Guido Trotter

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

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

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

1146 7ee7c0c7 Guido Trotter
  """
1147 7ee7c0c7 Guido Trotter
  _instance = None
1148 7ee7c0c7 Guido Trotter
1149 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1150 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1151 7ee7c0c7 Guido Trotter

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

1155 c41eea6e Iustin Pop
    @param nodes: list of node names
1156 c41eea6e Iustin Pop
    @param instances: list of instance names
1157 7ee7c0c7 Guido Trotter

1158 7ee7c0c7 Guido Trotter
    """
1159 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1160 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1161 c41eea6e Iustin Pop
1162 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1163 7ee7c0c7 Guido Trotter
1164 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1165 7ee7c0c7 Guido Trotter
    # locking order.
1166 7ee7c0c7 Guido Trotter
    self.__keyring = {
1167 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
1168 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
1169 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
1170 7ee7c0c7 Guido Trotter
    }
1171 7ee7c0c7 Guido Trotter
1172 7ee7c0c7 Guido Trotter
  def _names(self, level):
1173 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1174 7ee7c0c7 Guido Trotter

1175 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1176 c41eea6e Iustin Pop

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

1179 7ee7c0c7 Guido Trotter
    """
1180 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1181 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1182 7ee7c0c7 Guido Trotter
1183 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1184 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1185 7ee7c0c7 Guido Trotter

1186 7ee7c0c7 Guido Trotter
    """
1187 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1188 7ee7c0c7 Guido Trotter
1189 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1190 d4f4b3e7 Guido Trotter
1191 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1192 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1193 7ee7c0c7 Guido Trotter

1194 7ee7c0c7 Guido Trotter
    """
1195 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1196 7ee7c0c7 Guido Trotter
1197 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1198 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1199 7ee7c0c7 Guido Trotter

1200 7ee7c0c7 Guido Trotter
    """
1201 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1202 7ee7c0c7 Guido Trotter
    # the test cases.
1203 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1204 7ee7c0c7 Guido Trotter
1205 7ee7c0c7 Guido Trotter
  def _BGL_owned(self):
1206 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1207 7ee7c0c7 Guido Trotter

1208 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1209 7ee7c0c7 Guido Trotter

1210 7ee7c0c7 Guido Trotter
    """
1211 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1212 7ee7c0c7 Guido Trotter
1213 7ee7c0c7 Guido Trotter
  def _contains_BGL(self, level, names):
1214 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1215 c41eea6e Iustin Pop

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

1219 7ee7c0c7 Guido Trotter
    """
1220 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1221 7ee7c0c7 Guido Trotter
1222 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1223 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1224 7ee7c0c7 Guido Trotter

1225 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be acquired;
1226 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS.
1227 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1228 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1229 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1230 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1231 5e0a6daf Michael Hanselmann
    @type timeout: float
1232 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1233 7ee7c0c7 Guido Trotter

1234 7ee7c0c7 Guido Trotter
    """
1235 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1236 7ee7c0c7 Guido Trotter
1237 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1238 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1239 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1240 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1241 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1242 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1243 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1244 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1245 7ee7c0c7 Guido Trotter
1246 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1247 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1248 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1249 7ee7c0c7 Guido Trotter
1250 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1251 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1252 7ee7c0c7 Guido Trotter
1253 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1254 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1255 7ee7c0c7 Guido Trotter

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

1259 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be released;
1260 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS
1261 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1262 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1263 7ee7c0c7 Guido Trotter

1264 7ee7c0c7 Guido Trotter
    """
1265 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1266 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1267 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1268 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1269 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1270 e4335b5b Michael Hanselmann
            (", ".join(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1271 e4335b5b Michael Hanselmann
                        for i in self.__keyring.keys()]), ))
1272 7ee7c0c7 Guido Trotter
1273 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1274 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1275 7ee7c0c7 Guido Trotter
1276 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1277 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1278 7ee7c0c7 Guido Trotter

1279 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be added;
1280 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS_MOD.
1281 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1282 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1283 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1284 c41eea6e Iustin Pop

1285 7ee7c0c7 Guido Trotter
    """
1286 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1287 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1288 7ee7c0c7 Guido Trotter
           " operations")
1289 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1290 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1291 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1292 7ee7c0c7 Guido Trotter
1293 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1294 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1295 7ee7c0c7 Guido Trotter

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

1299 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be removed;
1300 c41eea6e Iustin Pop
        it must be a member of LEVELS_MOD
1301 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1302 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1303 7ee7c0c7 Guido Trotter

1304 7ee7c0c7 Guido Trotter
    """
1305 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1306 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1307 7ee7c0c7 Guido Trotter
           " operations")
1308 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1309 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1310 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1311 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1312 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1313 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1314 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)