Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 76e2f08a

History | View | Annotate | Download (37.7 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 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
56 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
57 d76167a5 Michael Hanselmann

58 d76167a5 Michael Hanselmann
  """
59 d76167a5 Michael Hanselmann
  __slots__ = [
60 d76167a5 Michael Hanselmann
    "_fd",
61 d76167a5 Michael Hanselmann
    "_poller",
62 d76167a5 Michael Hanselmann
    ]
63 d76167a5 Michael Hanselmann
64 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
65 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
66 d76167a5 Michael Hanselmann

67 d76167a5 Michael Hanselmann
    @type poller: select.poll
68 d76167a5 Michael Hanselmann
    @param poller: Poller object
69 d76167a5 Michael Hanselmann
    @type fd: int
70 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
71 d76167a5 Michael Hanselmann

72 d76167a5 Michael Hanselmann
    """
73 d76167a5 Michael Hanselmann
    object.__init__(self)
74 d76167a5 Michael Hanselmann
    self._poller = poller
75 d76167a5 Michael Hanselmann
    self._fd = fd
76 d76167a5 Michael Hanselmann
77 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
78 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
79 d76167a5 Michael Hanselmann

80 d76167a5 Michael Hanselmann
    @type timeout: float or None
81 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
82 d76167a5 Michael Hanselmann

83 d76167a5 Michael Hanselmann
    """
84 d76167a5 Michael Hanselmann
    start_time = time.time()
85 d76167a5 Michael Hanselmann
    remaining_time = timeout
86 d76167a5 Michael Hanselmann
87 d76167a5 Michael Hanselmann
    while timeout is None or remaining_time > 0:
88 d76167a5 Michael Hanselmann
      try:
89 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
90 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
91 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
92 d76167a5 Michael Hanselmann
          raise
93 d76167a5 Michael Hanselmann
        result = None
94 d76167a5 Michael Hanselmann
95 d76167a5 Michael Hanselmann
      # Check whether we were notified
96 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
97 d76167a5 Michael Hanselmann
        break
98 d76167a5 Michael Hanselmann
99 d76167a5 Michael Hanselmann
      # Re-calculate timeout if necessary
100 d76167a5 Michael Hanselmann
      if timeout is not None:
101 d76167a5 Michael Hanselmann
        remaining_time = start_time + timeout - time.time()
102 d76167a5 Michael Hanselmann
103 d76167a5 Michael Hanselmann
104 2419060d Guido Trotter
class _BaseCondition(object):
105 2419060d Guido Trotter
  """Base class containing common code for conditions.
106 2419060d Guido Trotter

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

109 2419060d Guido Trotter
  """
110 2419060d Guido Trotter
  __slots__ = [
111 2419060d Guido Trotter
    "_lock",
112 2419060d Guido Trotter
    "acquire",
113 2419060d Guido Trotter
    "release",
114 2419060d Guido Trotter
    ]
115 2419060d Guido Trotter
116 2419060d Guido Trotter
  def __init__(self, lock):
117 2419060d Guido Trotter
    """Constructor for _BaseCondition.
118 2419060d Guido Trotter

119 69b99987 Michael Hanselmann
    @type lock: threading.Lock
120 2419060d Guido Trotter
    @param lock: condition base lock
121 2419060d Guido Trotter

122 2419060d Guido Trotter
    """
123 2419060d Guido Trotter
    object.__init__(self)
124 2419060d Guido Trotter
125 2419060d Guido Trotter
    # Recursive locks are not supported
126 2419060d Guido Trotter
    assert not hasattr(lock, "_acquire_restore")
127 2419060d Guido Trotter
    assert not hasattr(lock, "_release_save")
128 2419060d Guido Trotter
129 2419060d Guido Trotter
    self._lock = lock
130 2419060d Guido Trotter
131 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
132 2419060d Guido Trotter
    self.acquire = lock.acquire
133 2419060d Guido Trotter
    self.release = lock.release
134 2419060d Guido Trotter
135 2419060d Guido Trotter
  def _is_owned(self):
136 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
137 2419060d Guido Trotter

138 2419060d Guido Trotter
    """
139 2419060d Guido Trotter
    if self._lock.acquire(0):
140 2419060d Guido Trotter
      self._lock.release()
141 2419060d Guido Trotter
      return False
142 2419060d Guido Trotter
143 2419060d Guido Trotter
    return True
144 2419060d Guido Trotter
145 2419060d Guido Trotter
  def _check_owned(self):
146 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
147 2419060d Guido Trotter

148 2419060d Guido Trotter
    """
149 2419060d Guido Trotter
    if not self._is_owned():
150 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
151 2419060d Guido Trotter
152 2419060d Guido Trotter
153 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
154 34cb5617 Guido Trotter
  """Condition which can only be notified once.
155 d76167a5 Michael Hanselmann

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

162 d76167a5 Michael Hanselmann
  """
163 34cb5617 Guido Trotter
164 34cb5617 Guido Trotter
  __slots__ = _BaseCondition.__slots__ + [
165 d76167a5 Michael Hanselmann
    "_poller",
166 d76167a5 Michael Hanselmann
    "_read_fd",
167 d76167a5 Michael Hanselmann
    "_write_fd",
168 d76167a5 Michael Hanselmann
    "_nwaiters",
169 34cb5617 Guido Trotter
    "_notified",
170 d76167a5 Michael Hanselmann
    ]
171 d76167a5 Michael Hanselmann
172 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
173 d76167a5 Michael Hanselmann
174 34cb5617 Guido Trotter
  def __init__(self, lock):
175 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
176 d76167a5 Michael Hanselmann

177 d76167a5 Michael Hanselmann
    """
178 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
179 d76167a5 Michael Hanselmann
    self._nwaiters = 0
180 34cb5617 Guido Trotter
    self._notified = False
181 34cb5617 Guido Trotter
    self._read_fd = None
182 34cb5617 Guido Trotter
    self._write_fd = None
183 34cb5617 Guido Trotter
    self._poller = None
184 d76167a5 Michael Hanselmann
185 34cb5617 Guido Trotter
  def _check_unnotified(self):
186 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
187 69b99987 Michael Hanselmann

188 69b99987 Michael Hanselmann
    """
189 34cb5617 Guido Trotter
    if self._notified:
190 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
191 d76167a5 Michael Hanselmann
192 34cb5617 Guido Trotter
  def _Cleanup(self):
193 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
194 d76167a5 Michael Hanselmann

195 d76167a5 Michael Hanselmann
    """
196 34cb5617 Guido Trotter
    if self._read_fd is not None:
197 34cb5617 Guido Trotter
      os.close(self._read_fd)
198 34cb5617 Guido Trotter
      self._read_fd = None
199 d76167a5 Michael Hanselmann
200 34cb5617 Guido Trotter
    if self._write_fd is not None:
201 34cb5617 Guido Trotter
      os.close(self._write_fd)
202 34cb5617 Guido Trotter
      self._write_fd = None
203 34cb5617 Guido Trotter
    self._poller = None
204 d76167a5 Michael Hanselmann
205 34cb5617 Guido Trotter
  def wait(self, timeout=None):
206 34cb5617 Guido Trotter
    """Wait for a notification.
207 d76167a5 Michael Hanselmann

208 34cb5617 Guido Trotter
    @type timeout: float or None
209 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
210 d76167a5 Michael Hanselmann

211 d76167a5 Michael Hanselmann
    """
212 34cb5617 Guido Trotter
    self._check_owned()
213 34cb5617 Guido Trotter
    self._check_unnotified()
214 d76167a5 Michael Hanselmann
215 34cb5617 Guido Trotter
    self._nwaiters += 1
216 34cb5617 Guido Trotter
    try:
217 34cb5617 Guido Trotter
      if self._poller is None:
218 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
219 34cb5617 Guido Trotter
        self._poller = select.poll()
220 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
221 d76167a5 Michael Hanselmann
222 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
223 34cb5617 Guido Trotter
      self.release()
224 34cb5617 Guido Trotter
      try:
225 34cb5617 Guido Trotter
        # Wait for notification
226 34cb5617 Guido Trotter
        wait_fn(timeout)
227 34cb5617 Guido Trotter
      finally:
228 34cb5617 Guido Trotter
        # Re-acquire lock
229 34cb5617 Guido Trotter
        self.acquire()
230 34cb5617 Guido Trotter
    finally:
231 34cb5617 Guido Trotter
      self._nwaiters -= 1
232 34cb5617 Guido Trotter
      if self._nwaiters == 0:
233 34cb5617 Guido Trotter
        self._Cleanup()
234 d76167a5 Michael Hanselmann
235 d76167a5 Michael Hanselmann
  def notifyAll(self):
236 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
237 d76167a5 Michael Hanselmann

238 d76167a5 Michael Hanselmann
    """
239 34cb5617 Guido Trotter
    self._check_owned()
240 34cb5617 Guido Trotter
    self._check_unnotified()
241 34cb5617 Guido Trotter
    self._notified = True
242 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
243 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
244 d76167a5 Michael Hanselmann
      self._write_fd = None
245 d76167a5 Michael Hanselmann
246 d76167a5 Michael Hanselmann
247 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
248 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
249 48dabc6a Michael Hanselmann

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

256 48dabc6a Michael Hanselmann
  """
257 2419060d Guido Trotter
  __slots__ = _BaseCondition.__slots__ + [
258 48dabc6a Michael Hanselmann
    "_nwaiters",
259 34cb5617 Guido Trotter
    "_single_condition",
260 48dabc6a Michael Hanselmann
    ]
261 48dabc6a Michael Hanselmann
262 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
263 48dabc6a Michael Hanselmann
264 48dabc6a Michael Hanselmann
  def __init__(self, lock):
265 48dabc6a Michael Hanselmann
    """Initializes this class.
266 48dabc6a Michael Hanselmann

267 48dabc6a Michael Hanselmann
    """
268 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
269 48dabc6a Michael Hanselmann
    self._nwaiters = 0
270 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
271 48dabc6a Michael Hanselmann
272 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
273 48dabc6a Michael Hanselmann
    """Wait for a notification.
274 48dabc6a Michael Hanselmann

275 48dabc6a Michael Hanselmann
    @type timeout: float or None
276 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
277 48dabc6a Michael Hanselmann

278 48dabc6a Michael Hanselmann
    """
279 48dabc6a Michael Hanselmann
    self._check_owned()
280 48dabc6a Michael Hanselmann
281 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
282 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
283 34cb5617 Guido Trotter
    my_condition = self._single_condition
284 48dabc6a Michael Hanselmann
285 48dabc6a Michael Hanselmann
    assert self._nwaiters >= 0
286 48dabc6a Michael Hanselmann
    self._nwaiters += 1
287 48dabc6a Michael Hanselmann
    try:
288 34cb5617 Guido Trotter
      my_condition.wait(timeout)
289 48dabc6a Michael Hanselmann
    finally:
290 48dabc6a Michael Hanselmann
      assert self._nwaiters > 0
291 48dabc6a Michael Hanselmann
      self._nwaiters -= 1
292 48dabc6a Michael Hanselmann
293 48dabc6a Michael Hanselmann
  def notifyAll(self):
294 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
295 48dabc6a Michael Hanselmann

296 48dabc6a Michael Hanselmann
    """
297 48dabc6a Michael Hanselmann
    self._check_owned()
298 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
299 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
300 48dabc6a Michael Hanselmann
301 48dabc6a Michael Hanselmann
  def has_waiting(self):
302 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
303 48dabc6a Michael Hanselmann

304 48dabc6a Michael Hanselmann
    """
305 48dabc6a Michael Hanselmann
    self._check_owned()
306 48dabc6a Michael Hanselmann
307 48dabc6a Michael Hanselmann
    return bool(self._nwaiters)
308 48dabc6a Michael Hanselmann
309 48dabc6a Michael Hanselmann
310 84e344d4 Michael Hanselmann
class _CountingCondition(object):
311 84e344d4 Michael Hanselmann
  """Wrapper for Python's built-in threading.Condition class.
312 84e344d4 Michael Hanselmann

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

316 84e344d4 Michael Hanselmann
  """
317 84e344d4 Michael Hanselmann
  __slots__ = [
318 84e344d4 Michael Hanselmann
    "_cond",
319 84e344d4 Michael Hanselmann
    "_nwaiters",
320 84e344d4 Michael Hanselmann
    ]
321 84e344d4 Michael Hanselmann
322 84e344d4 Michael Hanselmann
  def __init__(self, lock):
323 84e344d4 Michael Hanselmann
    """Initializes this class.
324 84e344d4 Michael Hanselmann

325 84e344d4 Michael Hanselmann
    """
326 84e344d4 Michael Hanselmann
    object.__init__(self)
327 84e344d4 Michael Hanselmann
    self._cond = threading.Condition(lock=lock)
328 84e344d4 Michael Hanselmann
    self._nwaiters = 0
329 84e344d4 Michael Hanselmann
330 84e344d4 Michael Hanselmann
  def notifyAll(self):
331 84e344d4 Michael Hanselmann
    """Notifies the condition.
332 84e344d4 Michael Hanselmann

333 84e344d4 Michael Hanselmann
    """
334 84e344d4 Michael Hanselmann
    return self._cond.notifyAll()
335 84e344d4 Michael Hanselmann
336 84e344d4 Michael Hanselmann
  def wait(self, timeout=None):
337 84e344d4 Michael Hanselmann
    """Waits for the condition to be notified.
338 84e344d4 Michael Hanselmann

339 84e344d4 Michael Hanselmann
    @type timeout: float or None
340 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
341 84e344d4 Michael Hanselmann

342 84e344d4 Michael Hanselmann
    """
343 84e344d4 Michael Hanselmann
    assert self._nwaiters >= 0
344 84e344d4 Michael Hanselmann
345 84e344d4 Michael Hanselmann
    self._nwaiters += 1
346 84e344d4 Michael Hanselmann
    try:
347 84e344d4 Michael Hanselmann
      return self._cond.wait(timeout=timeout)
348 84e344d4 Michael Hanselmann
    finally:
349 84e344d4 Michael Hanselmann
      self._nwaiters -= 1
350 84e344d4 Michael Hanselmann
351 84e344d4 Michael Hanselmann
  def has_waiting(self):
352 84e344d4 Michael Hanselmann
    """Returns whether there are active waiters.
353 84e344d4 Michael Hanselmann

354 84e344d4 Michael Hanselmann
    """
355 84e344d4 Michael Hanselmann
    return bool(self._nwaiters)
356 84e344d4 Michael Hanselmann
357 84e344d4 Michael Hanselmann
358 84e344d4 Michael Hanselmann
class SharedLock(object):
359 162c1c1f Guido Trotter
  """Implements a shared lock.
360 162c1c1f Guido Trotter

361 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
362 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
363 162c1c1f Guido Trotter
  can call acquire_exclusive().
364 162c1c1f Guido Trotter

365 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
366 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
367 162c1c1f Guido Trotter
  eventually do so.
368 162c1c1f Guido Trotter

369 162c1c1f Guido Trotter
  """
370 84e344d4 Michael Hanselmann
  __slots__ = [
371 84e344d4 Michael Hanselmann
    "__active_shr_c",
372 84e344d4 Michael Hanselmann
    "__inactive_shr_c",
373 84e344d4 Michael Hanselmann
    "__deleted",
374 84e344d4 Michael Hanselmann
    "__exc",
375 84e344d4 Michael Hanselmann
    "__lock",
376 84e344d4 Michael Hanselmann
    "__pending",
377 84e344d4 Michael Hanselmann
    "__shr",
378 84e344d4 Michael Hanselmann
    ]
379 84e344d4 Michael Hanselmann
380 34cb5617 Guido Trotter
  __condition_class = PipeCondition
381 84e344d4 Michael Hanselmann
382 162c1c1f Guido Trotter
  def __init__(self):
383 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
384 84e344d4 Michael Hanselmann

385 84e344d4 Michael Hanselmann
    """
386 84e344d4 Michael Hanselmann
    object.__init__(self)
387 84e344d4 Michael Hanselmann
388 84e344d4 Michael Hanselmann
    # Internal lock
389 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
390 162c1c1f Guido Trotter
391 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
392 84e344d4 Michael Hanselmann
    self.__pending = []
393 84e344d4 Michael Hanselmann
394 84e344d4 Michael Hanselmann
    # Active and inactive conditions for shared locks
395 84e344d4 Michael Hanselmann
    self.__active_shr_c = self.__condition_class(self.__lock)
396 84e344d4 Michael Hanselmann
    self.__inactive_shr_c = self.__condition_class(self.__lock)
397 84e344d4 Michael Hanselmann
398 84e344d4 Michael Hanselmann
    # Current lock holders
399 162c1c1f Guido Trotter
    self.__shr = set()
400 162c1c1f Guido Trotter
    self.__exc = None
401 162c1c1f Guido Trotter
402 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
403 a95fd5d7 Guido Trotter
    self.__deleted = False
404 a95fd5d7 Guido Trotter
405 84e344d4 Michael Hanselmann
  def __check_deleted(self):
406 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
407 84e344d4 Michael Hanselmann

408 84e344d4 Michael Hanselmann
    """
409 84e344d4 Michael Hanselmann
    if self.__deleted:
410 84e344d4 Michael Hanselmann
      raise errors.LockError("Deleted lock")
411 84e344d4 Michael Hanselmann
412 162c1c1f Guido Trotter
  def __is_sharer(self):
413 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
414 84e344d4 Michael Hanselmann

415 84e344d4 Michael Hanselmann
    """
416 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
417 162c1c1f Guido Trotter
418 162c1c1f Guido Trotter
  def __is_exclusive(self):
419 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
420 84e344d4 Michael Hanselmann

421 84e344d4 Michael Hanselmann
    """
422 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
423 162c1c1f Guido Trotter
424 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
425 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
426 162c1c1f Guido Trotter

427 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
428 162c1c1f Guido Trotter
    the internal lock.
429 162c1c1f Guido Trotter

430 162c1c1f Guido Trotter
    """
431 162c1c1f Guido Trotter
    if shared < 0:
432 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
433 162c1c1f Guido Trotter
    elif shared:
434 162c1c1f Guido Trotter
      return self.__is_sharer()
435 162c1c1f Guido Trotter
    else:
436 162c1c1f Guido Trotter
      return self.__is_exclusive()
437 162c1c1f Guido Trotter
438 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
439 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
440 162c1c1f Guido Trotter

441 c41eea6e Iustin Pop
    @param shared:
442 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
443 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
444 c41eea6e Iustin Pop
        - > 0: check for shared ownership
445 162c1c1f Guido Trotter

446 162c1c1f Guido Trotter
    """
447 162c1c1f Guido Trotter
    self.__lock.acquire()
448 162c1c1f Guido Trotter
    try:
449 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
450 162c1c1f Guido Trotter
    finally:
451 162c1c1f Guido Trotter
      self.__lock.release()
452 162c1c1f Guido Trotter
453 84e344d4 Michael Hanselmann
  def _count_pending(self):
454 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
455 a95fd5d7 Guido Trotter

456 84e344d4 Michael Hanselmann
    @rtype: int
457 a95fd5d7 Guido Trotter

458 a95fd5d7 Guido Trotter
    """
459 84e344d4 Michael Hanselmann
    self.__lock.acquire()
460 84e344d4 Michael Hanselmann
    try:
461 84e344d4 Michael Hanselmann
      return len(self.__pending)
462 84e344d4 Michael Hanselmann
    finally:
463 84e344d4 Michael Hanselmann
      self.__lock.release()
464 a95fd5d7 Guido Trotter
465 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
466 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
467 84e344d4 Michael Hanselmann

468 84e344d4 Michael Hanselmann
    """
469 84e344d4 Michael Hanselmann
    if shared:
470 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
471 84e344d4 Michael Hanselmann
    else:
472 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
473 a95fd5d7 Guido Trotter
474 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
475 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
476 a95fd5d7 Guido Trotter

477 a95fd5d7 Guido Trotter
    """
478 84e344d4 Michael Hanselmann
    if shared:
479 84e344d4 Michael Hanselmann
      return self.__exc is None
480 84e344d4 Michael Hanselmann
    else:
481 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
482 a95fd5d7 Guido Trotter
483 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
484 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
485 a95fd5d7 Guido Trotter

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

488 84e344d4 Michael Hanselmann
    """
489 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
490 4d686df8 Guido Trotter
491 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
492 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
493 9216a9f7 Michael Hanselmann

494 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
495 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
496 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
497 9216a9f7 Michael Hanselmann

498 9216a9f7 Michael Hanselmann
    """
499 84e344d4 Michael Hanselmann
    self.__check_deleted()
500 9216a9f7 Michael Hanselmann
501 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
502 84e344d4 Michael Hanselmann
    assert not self.__is_owned(), "double acquire() on a non-recursive lock"
503 84e344d4 Michael Hanselmann
504 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
505 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
506 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
507 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
508 84e344d4 Michael Hanselmann
      return True
509 9216a9f7 Michael Hanselmann
510 84e344d4 Michael Hanselmann
    if shared:
511 84e344d4 Michael Hanselmann
      wait_condition = self.__active_shr_c
512 9216a9f7 Michael Hanselmann
513 84e344d4 Michael Hanselmann
      # Check if we're not yet in the queue
514 84e344d4 Michael Hanselmann
      if wait_condition not in self.__pending:
515 84e344d4 Michael Hanselmann
        self.__pending.append(wait_condition)
516 84e344d4 Michael Hanselmann
    else:
517 84e344d4 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock)
518 84e344d4 Michael Hanselmann
      # Always add to queue
519 84e344d4 Michael Hanselmann
      self.__pending.append(wait_condition)
520 84e344d4 Michael Hanselmann
521 84e344d4 Michael Hanselmann
    try:
522 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
523 84e344d4 Michael Hanselmann
      # expires.
524 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
525 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
526 84e344d4 Michael Hanselmann
        # Wait for notification
527 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
528 84e344d4 Michael Hanselmann
        self.__check_deleted()
529 84e344d4 Michael Hanselmann
530 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
531 84e344d4 Michael Hanselmann
        # internally for that case.
532 84e344d4 Michael Hanselmann
        if timeout is not None:
533 84e344d4 Michael Hanselmann
          break
534 84e344d4 Michael Hanselmann
535 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
536 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
537 84e344d4 Michael Hanselmann
        return True
538 9216a9f7 Michael Hanselmann
    finally:
539 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
540 84e344d4 Michael Hanselmann
      if not wait_condition.has_waiting() and not self.__deleted:
541 84e344d4 Michael Hanselmann
        self.__pending.remove(wait_condition)
542 9216a9f7 Michael Hanselmann
543 84e344d4 Michael Hanselmann
    return False
544 9216a9f7 Michael Hanselmann
545 008b92fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, test_notify=None):
546 162c1c1f Guido Trotter
    """Acquire a shared lock.
547 162c1c1f Guido Trotter

548 84e344d4 Michael Hanselmann
    @type shared: int
549 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
550 c41eea6e Iustin Pop
        exclusive lock will be acquired
551 84e344d4 Michael Hanselmann
    @type timeout: float
552 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
553 008b92fa Michael Hanselmann
    @type test_notify: callable or None
554 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
555 162c1c1f Guido Trotter

556 162c1c1f Guido Trotter
    """
557 162c1c1f Guido Trotter
    self.__lock.acquire()
558 162c1c1f Guido Trotter
    try:
559 008b92fa Michael Hanselmann
      # We already got the lock, notify now
560 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
561 008b92fa Michael Hanselmann
        test_notify()
562 008b92fa Michael Hanselmann
563 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
564 162c1c1f Guido Trotter
    finally:
565 162c1c1f Guido Trotter
      self.__lock.release()
566 162c1c1f Guido Trotter
567 162c1c1f Guido Trotter
  def release(self):
568 162c1c1f Guido Trotter
    """Release a Shared Lock.
569 162c1c1f Guido Trotter

570 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
571 162c1c1f Guido Trotter
    before calling this function.
572 162c1c1f Guido Trotter

573 162c1c1f Guido Trotter
    """
574 162c1c1f Guido Trotter
    self.__lock.acquire()
575 162c1c1f Guido Trotter
    try:
576 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
577 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
578 84e344d4 Michael Hanselmann
579 162c1c1f Guido Trotter
      # Autodetect release type
580 162c1c1f Guido Trotter
      if self.__is_exclusive():
581 162c1c1f Guido Trotter
        self.__exc = None
582 84e344d4 Michael Hanselmann
      else:
583 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
584 162c1c1f Guido Trotter
585 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
586 84e344d4 Michael Hanselmann
      if self.__pending:
587 84e344d4 Michael Hanselmann
        first_condition = self.__pending[0]
588 84e344d4 Michael Hanselmann
        first_condition.notifyAll()
589 4d686df8 Guido Trotter
590 84e344d4 Michael Hanselmann
        if first_condition == self.__active_shr_c:
591 84e344d4 Michael Hanselmann
          self.__active_shr_c = self.__inactive_shr_c
592 84e344d4 Michael Hanselmann
          self.__inactive_shr_c = first_condition
593 162c1c1f Guido Trotter
594 162c1c1f Guido Trotter
    finally:
595 162c1c1f Guido Trotter
      self.__lock.release()
596 162c1c1f Guido Trotter
597 84e344d4 Michael Hanselmann
  def delete(self, timeout=None):
598 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
599 a95fd5d7 Guido Trotter

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

604 84e344d4 Michael Hanselmann
    @type timeout: float
605 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
606 a95fd5d7 Guido Trotter

607 a95fd5d7 Guido Trotter
    """
608 a95fd5d7 Guido Trotter
    self.__lock.acquire()
609 a95fd5d7 Guido Trotter
    try:
610 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
611 84e344d4 Michael Hanselmann
612 84e344d4 Michael Hanselmann
      self.__check_deleted()
613 a95fd5d7 Guido Trotter
614 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
615 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
616 a95fd5d7 Guido Trotter
617 84e344d4 Michael Hanselmann
      if not acquired:
618 a66bd91b Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout)
619 a66bd91b Michael Hanselmann
620 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
621 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
622 84e344d4 Michael Hanselmann
623 84e344d4 Michael Hanselmann
      if acquired:
624 84e344d4 Michael Hanselmann
        self.__deleted = True
625 84e344d4 Michael Hanselmann
        self.__exc = None
626 a95fd5d7 Guido Trotter
627 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
628 84e344d4 Michael Hanselmann
        while self.__pending:
629 84e344d4 Michael Hanselmann
          self.__pending.pop().notifyAll()
630 a95fd5d7 Guido Trotter
631 84e344d4 Michael Hanselmann
      return acquired
632 a95fd5d7 Guido Trotter
    finally:
633 a95fd5d7 Guido Trotter
      self.__lock.release()
634 a95fd5d7 Guido Trotter
635 aaae9bc0 Guido Trotter
636 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
637 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
638 e310b019 Guido Trotter
ALL_SET = None
639 e310b019 Guido Trotter
640 e310b019 Guido Trotter
641 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
642 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
643 5aab242c Michael Hanselmann

644 5aab242c Michael Hanselmann
  """
645 5aab242c Michael Hanselmann
646 5aab242c Michael Hanselmann
647 aaae9bc0 Guido Trotter
class LockSet:
648 aaae9bc0 Guido Trotter
  """Implements a set of locks.
649 aaae9bc0 Guido Trotter

650 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
651 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
652 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
653 aaae9bc0 Guido Trotter
  preventing deadlock.
654 aaae9bc0 Guido Trotter

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

657 aaae9bc0 Guido Trotter
  """
658 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
659 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
660 aaae9bc0 Guido Trotter

661 c41eea6e Iustin Pop
    @param members: initial members of the set
662 aaae9bc0 Guido Trotter

663 aaae9bc0 Guido Trotter
    """
664 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
665 aaae9bc0 Guido Trotter
    self.__lock = SharedLock()
666 aaae9bc0 Guido Trotter
667 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
668 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
669 aaae9bc0 Guido Trotter
    self.__lockdict = {}
670 aaae9bc0 Guido Trotter
671 aaae9bc0 Guido Trotter
    if members is not None:
672 aaae9bc0 Guido Trotter
      for name in members:
673 aaae9bc0 Guido Trotter
        self.__lockdict[name] = SharedLock()
674 aaae9bc0 Guido Trotter
675 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
676 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
677 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
678 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
679 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
680 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
681 aaae9bc0 Guido Trotter
    # will be trouble.
682 aaae9bc0 Guido Trotter
    self.__owners = {}
683 aaae9bc0 Guido Trotter
684 aaae9bc0 Guido Trotter
  def _is_owned(self):
685 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
686 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
687 aaae9bc0 Guido Trotter
688 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
689 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
690 b2dabfd6 Guido Trotter
    if name is None:
691 b2dabfd6 Guido Trotter
      if not self._is_owned():
692 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
693 aaae9bc0 Guido Trotter
    else:
694 b2dabfd6 Guido Trotter
      if self._is_owned():
695 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
696 b2dabfd6 Guido Trotter
      else:
697 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
698 b2dabfd6 Guido Trotter
699 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
700 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
701 aaae9bc0 Guido Trotter
702 b2dabfd6 Guido Trotter
    if name is not None:
703 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
704 b2dabfd6 Guido Trotter
705 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
706 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
707 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
708 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
709 aaae9bc0 Guido Trotter
710 aaae9bc0 Guido Trotter
  def _list_owned(self):
711 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
712 aaae9bc0 Guido Trotter
    if self._is_owned():
713 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
714 aaae9bc0 Guido Trotter
    else:
715 aaae9bc0 Guido Trotter
      return set()
716 aaae9bc0 Guido Trotter
717 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
718 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
719 5aab242c Michael Hanselmann
    for lname in self._list_owned():
720 5aab242c Michael Hanselmann
      self.__lockdict[lname].release()
721 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
722 5aab242c Michael Hanselmann
723 aaae9bc0 Guido Trotter
  def __names(self):
724 aaae9bc0 Guido Trotter
    """Return the current set of names.
725 aaae9bc0 Guido Trotter

726 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
727 aaae9bc0 Guido Trotter
    result after releasing the lock.
728 aaae9bc0 Guido Trotter

729 aaae9bc0 Guido Trotter
    """
730 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
731 aaae9bc0 Guido Trotter
732 aaae9bc0 Guido Trotter
  def _names(self):
733 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
734 aaae9bc0 Guido Trotter

735 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
736 cdb08f44 Michael Hanselmann

737 aaae9bc0 Guido Trotter
    """
738 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
739 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
740 d4803c24 Guido Trotter
    release_lock = False
741 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
742 d4803c24 Guido Trotter
      release_lock = True
743 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
744 aaae9bc0 Guido Trotter
    try:
745 aaae9bc0 Guido Trotter
      result = self.__names()
746 aaae9bc0 Guido Trotter
    finally:
747 d4803c24 Guido Trotter
      if release_lock:
748 d4803c24 Guido Trotter
        self.__lock.release()
749 0cf257c5 Guido Trotter
    return set(result)
750 aaae9bc0 Guido Trotter
751 5aab242c Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, test_notify=None):
752 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
753 aaae9bc0 Guido Trotter

754 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
755 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
756 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
757 c41eea6e Iustin Pop
        exclusive lock will be acquired
758 5aab242c Michael Hanselmann
    @type timeout: float or None
759 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
760 5aab242c Michael Hanselmann
    @type test_notify: callable or None
761 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
762 aaae9bc0 Guido Trotter

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

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

769 aaae9bc0 Guido Trotter
    """
770 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
771 aaae9bc0 Guido Trotter
772 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
773 aaae9bc0 Guido Trotter
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
774 aaae9bc0 Guido Trotter
775 5aab242c Michael Hanselmann
    # We need to keep track of how long we spent waiting for a lock. The
776 5aab242c Michael Hanselmann
    # timeout passed to this function is over all lock acquires.
777 5aab242c Michael Hanselmann
    remaining_timeout = timeout
778 5aab242c Michael Hanselmann
    if timeout is None:
779 5aab242c Michael Hanselmann
      start = None
780 5aab242c Michael Hanselmann
      calc_remaining_timeout = lambda: None
781 5aab242c Michael Hanselmann
    else:
782 5aab242c Michael Hanselmann
      start = time.time()
783 5aab242c Michael Hanselmann
      calc_remaining_timeout = lambda: (start + timeout) - time.time()
784 5aab242c Michael Hanselmann
785 806e20fd Guido Trotter
    try:
786 76e2f08a Michael Hanselmann
      if names is not None:
787 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
788 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
789 5aab242c Michael Hanselmann
          names = [names]
790 5aab242c Michael Hanselmann
        else:
791 5aab242c Michael Hanselmann
          names = sorted(names)
792 5aab242c Michael Hanselmann
793 76e2f08a Michael Hanselmann
        return self.__acquire_inner(names, False, shared,
794 76e2f08a Michael Hanselmann
                                    calc_remaining_timeout, test_notify)
795 76e2f08a Michael Hanselmann
796 76e2f08a Michael Hanselmann
      else:
797 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
798 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
799 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
800 76e2f08a Michael Hanselmann
        #
801 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
802 76e2f08a Michael Hanselmann
        # everybody else can use the instances at the same time. If are
803 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
804 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
805 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
806 76e2f08a Michael Hanselmann
        if not self.__lock.acquire(shared=shared,
807 76e2f08a Michael Hanselmann
                                   timeout=calc_remaining_timeout()):
808 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
809 76e2f08a Michael Hanselmann
        try:
810 76e2f08a Michael Hanselmann
          # note we own the set-lock
811 76e2f08a Michael Hanselmann
          self._add_owned()
812 76e2f08a Michael Hanselmann
813 76e2f08a Michael Hanselmann
          return self.__acquire_inner(self.__names(), True, shared,
814 76e2f08a Michael Hanselmann
                                      calc_remaining_timeout, test_notify)
815 76e2f08a Michael Hanselmann
        except:
816 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
817 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
818 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
819 5aab242c Michael Hanselmann
          self.__lock.release()
820 76e2f08a Michael Hanselmann
          self._del_owned()
821 76e2f08a Michael Hanselmann
          raise
822 5aab242c Michael Hanselmann
823 5aab242c Michael Hanselmann
    except _AcquireTimeout:
824 5aab242c Michael Hanselmann
      return None
825 aaae9bc0 Guido Trotter
826 76e2f08a Michael Hanselmann
  def __acquire_inner(self, names, want_all, shared, timeout_fn, test_notify):
827 76e2f08a Michael Hanselmann
    """
828 76e2f08a Michael Hanselmann

829 76e2f08a Michael Hanselmann
    """
830 76e2f08a Michael Hanselmann
    acquire_list = []
831 76e2f08a Michael Hanselmann
832 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
833 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
834 76e2f08a Michael Hanselmann
    # just one of them be the already wrong
835 76e2f08a Michael Hanselmann
    for lname in utils.UniqueSequence(names):
836 76e2f08a Michael Hanselmann
      try:
837 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
838 76e2f08a Michael Hanselmann
        acquire_list.append((lname, lock))
839 76e2f08a Michael Hanselmann
      except KeyError:
840 76e2f08a Michael Hanselmann
        if want_all:
841 76e2f08a Michael Hanselmann
          # We are acquiring all the set, it doesn't matter if this particular
842 76e2f08a Michael Hanselmann
          # element is not there anymore.
843 76e2f08a Michael Hanselmann
          continue
844 76e2f08a Michael Hanselmann
845 76e2f08a Michael Hanselmann
        raise errors.LockError("Non-existing lock in set (%s)" % lname)
846 76e2f08a Michael Hanselmann
847 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
848 76e2f08a Michael Hanselmann
    acquired = set()
849 76e2f08a Michael Hanselmann
850 76e2f08a Michael Hanselmann
    try:
851 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
852 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
853 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
854 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
855 76e2f08a Michael Hanselmann
      # lock gets deleted.
856 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
857 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
858 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
859 76e2f08a Michael Hanselmann
        else:
860 76e2f08a Michael Hanselmann
          test_notify_fn = None
861 76e2f08a Michael Hanselmann
862 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
863 76e2f08a Michael Hanselmann
        if timeout is not None and timeout < 0:
864 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
865 76e2f08a Michael Hanselmann
866 76e2f08a Michael Hanselmann
        try:
867 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
868 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
869 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
870 76e2f08a Michael Hanselmann
        except errors.LockError:
871 76e2f08a Michael Hanselmann
          if want_all:
872 76e2f08a Michael Hanselmann
            # We are acquiring all the set, it doesn't matter if this
873 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
874 76e2f08a Michael Hanselmann
            continue
875 76e2f08a Michael Hanselmann
876 76e2f08a Michael Hanselmann
          raise errors.LockError("Non-existing lock in set (%s)" % lname)
877 76e2f08a Michael Hanselmann
878 76e2f08a Michael Hanselmann
        if not acq_success:
879 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
880 76e2f08a Michael Hanselmann
          if timeout is None:
881 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
882 76e2f08a Michael Hanselmann
            # blocking.
883 76e2f08a Michael Hanselmann
            raise errors.LockError("Failed to get lock %s" % lname)
884 76e2f08a Michael Hanselmann
885 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
886 76e2f08a Michael Hanselmann
887 76e2f08a Michael Hanselmann
        try:
888 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
889 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
890 76e2f08a Michael Hanselmann
          acquired.add(lname)
891 76e2f08a Michael Hanselmann
892 76e2f08a Michael Hanselmann
        except:
893 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
894 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
895 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
896 76e2f08a Michael Hanselmann
          if lock._is_owned():
897 76e2f08a Michael Hanselmann
            lock.release()
898 76e2f08a Michael Hanselmann
          raise
899 76e2f08a Michael Hanselmann
900 76e2f08a Michael Hanselmann
    except:
901 76e2f08a Michael Hanselmann
      # Release all owned locks
902 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
903 76e2f08a Michael Hanselmann
      raise
904 76e2f08a Michael Hanselmann
905 0cc00929 Guido Trotter
    return acquired
906 aaae9bc0 Guido Trotter
907 aaae9bc0 Guido Trotter
  def release(self, names=None):
908 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
909 aaae9bc0 Guido Trotter

910 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
911 aaae9bc0 Guido Trotter
    before releasing them.
912 aaae9bc0 Guido Trotter

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

916 aaae9bc0 Guido Trotter
    """
917 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
918 aaae9bc0 Guido Trotter
919 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
920 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
921 aaae9bc0 Guido Trotter
      names = [names]
922 aaae9bc0 Guido Trotter
923 aaae9bc0 Guido Trotter
    if names is None:
924 aaae9bc0 Guido Trotter
      names = self._list_owned()
925 aaae9bc0 Guido Trotter
    else:
926 aaae9bc0 Guido Trotter
      names = set(names)
927 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
928 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
929 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
930 aaae9bc0 Guido Trotter
931 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
932 3b7ed473 Guido Trotter
    # After this 'add' can work again
933 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
934 3b7ed473 Guido Trotter
      self.__lock.release()
935 b2dabfd6 Guido Trotter
      self._del_owned()
936 3b7ed473 Guido Trotter
937 aaae9bc0 Guido Trotter
    for lockname in names:
938 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
939 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
940 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
941 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
942 aaae9bc0 Guido Trotter
943 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
944 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
945 aaae9bc0 Guido Trotter

946 c41eea6e Iustin Pop
    @param names: names of the new elements to add
947 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
948 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
949 aaae9bc0 Guido Trotter

950 aaae9bc0 Guido Trotter
    """
951 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
952 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
953 d2aff862 Guido Trotter
      "Cannot add locks if the set is only partially owned, or shared"
954 3b7ed473 Guido Trotter
955 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
956 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
957 aaae9bc0 Guido Trotter
      names = [names]
958 aaae9bc0 Guido Trotter
959 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
960 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
961 3b7ed473 Guido Trotter
    release_lock = False
962 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
963 3b7ed473 Guido Trotter
      release_lock = True
964 3b7ed473 Guido Trotter
      self.__lock.acquire()
965 3b7ed473 Guido Trotter
966 aaae9bc0 Guido Trotter
    try:
967 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
968 aaae9bc0 Guido Trotter
      if invalid_names:
969 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
970 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
971 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
972 aaae9bc0 Guido Trotter
        raise errors.LockError("duplicate add() (%s)" % invalid_names)
973 aaae9bc0 Guido Trotter
974 aaae9bc0 Guido Trotter
      for lockname in names:
975 aaae9bc0 Guido Trotter
        lock = SharedLock()
976 aaae9bc0 Guido Trotter
977 aaae9bc0 Guido Trotter
        if acquired:
978 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
979 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
980 aaae9bc0 Guido Trotter
          try:
981 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
982 aaae9bc0 Guido Trotter
          except:
983 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
984 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
985 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
986 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
987 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
988 aaae9bc0 Guido Trotter
            # release is just a safety measure.
989 aaae9bc0 Guido Trotter
            lock.release()
990 aaae9bc0 Guido Trotter
            raise
991 aaae9bc0 Guido Trotter
992 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
993 aaae9bc0 Guido Trotter
994 aaae9bc0 Guido Trotter
    finally:
995 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
996 3b7ed473 Guido Trotter
      if release_lock:
997 3b7ed473 Guido Trotter
        self.__lock.release()
998 aaae9bc0 Guido Trotter
999 aaae9bc0 Guido Trotter
    return True
1000 aaae9bc0 Guido Trotter
1001 5e0a6daf Michael Hanselmann
  def remove(self, names):
1002 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1003 aaae9bc0 Guido Trotter

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

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

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

1013 aaae9bc0 Guido Trotter
    """
1014 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1015 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1016 aaae9bc0 Guido Trotter
      names = [names]
1017 aaae9bc0 Guido Trotter
1018 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1019 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1020 aaae9bc0 Guido Trotter
    # by the lock itself.
1021 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
1022 aaae9bc0 Guido Trotter
      "remove() on acquired lockset while not owning all elements")
1023 aaae9bc0 Guido Trotter
1024 3f404fc5 Guido Trotter
    removed = []
1025 aaae9bc0 Guido Trotter
1026 aaae9bc0 Guido Trotter
    for lname in names:
1027 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1028 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1029 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1030 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1031 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1032 aaae9bc0 Guido Trotter
      try:
1033 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1034 3f404fc5 Guido Trotter
        removed.append(lname)
1035 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1036 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1037 aaae9bc0 Guido Trotter
        assert not self._is_owned(), "remove failed while holding lockset"
1038 aaae9bc0 Guido Trotter
      else:
1039 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1040 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1041 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1042 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1043 aaae9bc0 Guido Trotter
        #
1044 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1045 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1046 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1047 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1048 aaae9bc0 Guido Trotter
        if self._is_owned():
1049 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1050 aaae9bc0 Guido Trotter
1051 3f404fc5 Guido Trotter
    return removed
1052 aaae9bc0 Guido Trotter
1053 7ee7c0c7 Guido Trotter
1054 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1055 7ee7c0c7 Guido Trotter
# Current rules are:
1056 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1057 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1058 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1059 7ee7c0c7 Guido Trotter
#   avoided.
1060 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1061 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1062 7ee7c0c7 Guido Trotter
#   the same time.
1063 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1064 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1065 04e1bfaf Guido Trotter
LEVEL_NODE = 2
1066 7ee7c0c7 Guido Trotter
1067 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1068 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1069 04e1bfaf Guido Trotter
          LEVEL_NODE]
1070 7ee7c0c7 Guido Trotter
1071 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1072 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
1073 7ee7c0c7 Guido Trotter
1074 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1075 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1076 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1077 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1078 ea205dbc Michael Hanselmann
  }
1079 ea205dbc Michael Hanselmann
1080 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1081 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1082 7ee7c0c7 Guido Trotter
1083 7ee7c0c7 Guido Trotter
1084 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1085 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1086 7ee7c0c7 Guido Trotter

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

1092 7ee7c0c7 Guido Trotter
  """
1093 7ee7c0c7 Guido Trotter
  _instance = None
1094 7ee7c0c7 Guido Trotter
1095 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1096 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1097 7ee7c0c7 Guido Trotter

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

1101 c41eea6e Iustin Pop
    @param nodes: list of node names
1102 c41eea6e Iustin Pop
    @param instances: list of instance names
1103 7ee7c0c7 Guido Trotter

1104 7ee7c0c7 Guido Trotter
    """
1105 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1106 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1107 c41eea6e Iustin Pop
1108 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1109 7ee7c0c7 Guido Trotter
1110 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1111 7ee7c0c7 Guido Trotter
    # locking order.
1112 7ee7c0c7 Guido Trotter
    self.__keyring = {
1113 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
1114 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
1115 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
1116 7ee7c0c7 Guido Trotter
    }
1117 7ee7c0c7 Guido Trotter
1118 7ee7c0c7 Guido Trotter
  def _names(self, level):
1119 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1120 7ee7c0c7 Guido Trotter

1121 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1122 c41eea6e Iustin Pop

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

1125 7ee7c0c7 Guido Trotter
    """
1126 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1127 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1128 7ee7c0c7 Guido Trotter
1129 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1130 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1131 7ee7c0c7 Guido Trotter

1132 7ee7c0c7 Guido Trotter
    """
1133 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1134 7ee7c0c7 Guido Trotter
1135 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1136 d4f4b3e7 Guido Trotter
1137 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1138 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1139 7ee7c0c7 Guido Trotter

1140 7ee7c0c7 Guido Trotter
    """
1141 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1142 7ee7c0c7 Guido Trotter
1143 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1144 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1145 7ee7c0c7 Guido Trotter

1146 7ee7c0c7 Guido Trotter
    """
1147 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1148 7ee7c0c7 Guido Trotter
    # the test cases.
1149 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1150 7ee7c0c7 Guido Trotter
1151 7ee7c0c7 Guido Trotter
  def _BGL_owned(self):
1152 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1153 7ee7c0c7 Guido Trotter

1154 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1155 7ee7c0c7 Guido Trotter

1156 7ee7c0c7 Guido Trotter
    """
1157 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1158 7ee7c0c7 Guido Trotter
1159 7ee7c0c7 Guido Trotter
  def _contains_BGL(self, level, names):
1160 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1161 c41eea6e Iustin Pop

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

1165 7ee7c0c7 Guido Trotter
    """
1166 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1167 7ee7c0c7 Guido Trotter
1168 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1169 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1170 7ee7c0c7 Guido Trotter

1171 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be acquired;
1172 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS.
1173 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1174 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1175 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1176 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1177 5e0a6daf Michael Hanselmann
    @type timeout: float
1178 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1179 7ee7c0c7 Guido Trotter

1180 7ee7c0c7 Guido Trotter
    """
1181 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1182 7ee7c0c7 Guido Trotter
1183 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1184 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1185 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1186 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1187 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1188 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1189 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1190 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1191 7ee7c0c7 Guido Trotter
1192 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1193 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1194 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1195 7ee7c0c7 Guido Trotter
1196 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1197 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1198 7ee7c0c7 Guido Trotter
1199 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1200 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1201 7ee7c0c7 Guido Trotter

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

1205 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be released;
1206 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS
1207 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1208 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1209 7ee7c0c7 Guido Trotter

1210 7ee7c0c7 Guido Trotter
    """
1211 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1212 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1213 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1214 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1215 7ee7c0c7 Guido Trotter
            " at upper levels")
1216 7ee7c0c7 Guido Trotter
1217 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1218 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1219 7ee7c0c7 Guido Trotter
1220 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1221 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1222 7ee7c0c7 Guido Trotter

1223 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be added;
1224 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS_MOD.
1225 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1226 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1227 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1228 c41eea6e Iustin Pop

1229 7ee7c0c7 Guido Trotter
    """
1230 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1231 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1232 7ee7c0c7 Guido Trotter
           " operations")
1233 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1234 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1235 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1236 7ee7c0c7 Guido Trotter
1237 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1238 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1239 7ee7c0c7 Guido Trotter

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

1243 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be removed;
1244 c41eea6e Iustin Pop
        it must be a member of LEVELS_MOD
1245 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1246 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1247 7ee7c0c7 Guido Trotter

1248 7ee7c0c7 Guido Trotter
    """
1249 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1250 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1251 7ee7c0c7 Guido Trotter
           " operations")
1252 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1253 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1254 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1255 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1256 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1257 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1258 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)