Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 6e6bb8d5

History | View | Annotate | Download (35.9 kB)

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

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

40 42a999d1 Guido Trotter
  """
41 42a999d1 Guido Trotter
  def wrap(fn):
42 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
43 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
44 42a999d1 Guido Trotter
      try:
45 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
46 42a999d1 Guido Trotter
      finally:
47 42a999d1 Guido Trotter
        lock.release()
48 42a999d1 Guido Trotter
    return sync_function
49 42a999d1 Guido Trotter
  return wrap
50 42a999d1 Guido Trotter
51 42a999d1 Guido Trotter
52 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
53 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
54 d76167a5 Michael Hanselmann

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

64 d76167a5 Michael Hanselmann
    @type poller: select.poll
65 d76167a5 Michael Hanselmann
    @param poller: Poller object
66 d76167a5 Michael Hanselmann
    @type fd: int
67 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
68 d76167a5 Michael Hanselmann

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

77 d76167a5 Michael Hanselmann
    @type timeout: float or None
78 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
79 d76167a5 Michael Hanselmann

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

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

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

116 2419060d Guido Trotter
    @type lock: L{threading.Lock}
117 2419060d Guido Trotter
    @param lock: condition base lock
118 2419060d Guido Trotter

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

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

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

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

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

174 d76167a5 Michael Hanselmann
    """
175 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
176 d76167a5 Michael Hanselmann
    self._nwaiters = 0
177 34cb5617 Guido Trotter
    self._notified = False
178 34cb5617 Guido Trotter
    self._read_fd = None
179 34cb5617 Guido Trotter
    self._write_fd = None
180 34cb5617 Guido Trotter
    self._poller = None
181 d76167a5 Michael Hanselmann
182 34cb5617 Guido Trotter
  def _check_unnotified(self):
183 34cb5617 Guido Trotter
    if self._notified:
184 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
185 d76167a5 Michael Hanselmann
186 34cb5617 Guido Trotter
  def _Cleanup(self):
187 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
188 d76167a5 Michael Hanselmann

189 d76167a5 Michael Hanselmann
    """
190 34cb5617 Guido Trotter
    if self._read_fd is not None:
191 34cb5617 Guido Trotter
      os.close(self._read_fd)
192 34cb5617 Guido Trotter
      self._read_fd = None
193 d76167a5 Michael Hanselmann
194 34cb5617 Guido Trotter
    if self._write_fd is not None:
195 34cb5617 Guido Trotter
      os.close(self._write_fd)
196 34cb5617 Guido Trotter
      self._write_fd = None
197 34cb5617 Guido Trotter
    self._poller = None
198 d76167a5 Michael Hanselmann
199 34cb5617 Guido Trotter
  def wait(self, timeout=None):
200 34cb5617 Guido Trotter
    """Wait for a notification.
201 d76167a5 Michael Hanselmann

202 34cb5617 Guido Trotter
    @type timeout: float or None
203 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
204 d76167a5 Michael Hanselmann

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

232 d76167a5 Michael Hanselmann
    """
233 34cb5617 Guido Trotter
    self._check_owned()
234 34cb5617 Guido Trotter
    self._check_unnotified()
235 34cb5617 Guido Trotter
    self._notified = True
236 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
237 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
238 d76167a5 Michael Hanselmann
      self._write_fd = None
239 d76167a5 Michael Hanselmann
240 d76167a5 Michael Hanselmann
241 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
242 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
243 48dabc6a Michael Hanselmann

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

250 48dabc6a Michael Hanselmann
  """
251 2419060d Guido Trotter
  __slots__ = _BaseCondition.__slots__ + [
252 48dabc6a Michael Hanselmann
    "_nwaiters",
253 34cb5617 Guido Trotter
    "_single_condition",
254 48dabc6a Michael Hanselmann
    ]
255 48dabc6a Michael Hanselmann
256 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
257 48dabc6a Michael Hanselmann
258 48dabc6a Michael Hanselmann
  def __init__(self, lock):
259 48dabc6a Michael Hanselmann
    """Initializes this class.
260 48dabc6a Michael Hanselmann

261 48dabc6a Michael Hanselmann
    """
262 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
263 48dabc6a Michael Hanselmann
    self._nwaiters = 0
264 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
265 48dabc6a Michael Hanselmann
266 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
267 48dabc6a Michael Hanselmann
    """Wait for a notification.
268 48dabc6a Michael Hanselmann

269 48dabc6a Michael Hanselmann
    @type timeout: float or None
270 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
271 48dabc6a Michael Hanselmann

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

290 48dabc6a Michael Hanselmann
    """
291 48dabc6a Michael Hanselmann
    self._check_owned()
292 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
293 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
294 48dabc6a Michael Hanselmann
295 48dabc6a Michael Hanselmann
  def has_waiting(self):
296 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
297 48dabc6a Michael Hanselmann

298 48dabc6a Michael Hanselmann
    """
299 48dabc6a Michael Hanselmann
    self._check_owned()
300 48dabc6a Michael Hanselmann
301 48dabc6a Michael Hanselmann
    return bool(self._nwaiters)
302 48dabc6a Michael Hanselmann
303 48dabc6a Michael Hanselmann
304 84e344d4 Michael Hanselmann
class _CountingCondition(object):
305 84e344d4 Michael Hanselmann
  """Wrapper for Python's built-in threading.Condition class.
306 84e344d4 Michael Hanselmann

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

310 84e344d4 Michael Hanselmann
  """
311 84e344d4 Michael Hanselmann
  __slots__ = [
312 84e344d4 Michael Hanselmann
    "_cond",
313 84e344d4 Michael Hanselmann
    "_nwaiters",
314 84e344d4 Michael Hanselmann
    ]
315 84e344d4 Michael Hanselmann
316 84e344d4 Michael Hanselmann
  def __init__(self, lock):
317 84e344d4 Michael Hanselmann
    """Initializes this class.
318 84e344d4 Michael Hanselmann

319 84e344d4 Michael Hanselmann
    """
320 84e344d4 Michael Hanselmann
    object.__init__(self)
321 84e344d4 Michael Hanselmann
    self._cond = threading.Condition(lock=lock)
322 84e344d4 Michael Hanselmann
    self._nwaiters = 0
323 84e344d4 Michael Hanselmann
324 84e344d4 Michael Hanselmann
  def notifyAll(self):
325 84e344d4 Michael Hanselmann
    """Notifies the condition.
326 84e344d4 Michael Hanselmann

327 84e344d4 Michael Hanselmann
    """
328 84e344d4 Michael Hanselmann
    return self._cond.notifyAll()
329 84e344d4 Michael Hanselmann
330 84e344d4 Michael Hanselmann
  def wait(self, timeout=None):
331 84e344d4 Michael Hanselmann
    """Waits for the condition to be notified.
332 84e344d4 Michael Hanselmann

333 84e344d4 Michael Hanselmann
    @type timeout: float or None
334 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
335 84e344d4 Michael Hanselmann

336 84e344d4 Michael Hanselmann
    """
337 84e344d4 Michael Hanselmann
    assert self._nwaiters >= 0
338 84e344d4 Michael Hanselmann
339 84e344d4 Michael Hanselmann
    self._nwaiters += 1
340 84e344d4 Michael Hanselmann
    try:
341 84e344d4 Michael Hanselmann
      return self._cond.wait(timeout=timeout)
342 84e344d4 Michael Hanselmann
    finally:
343 84e344d4 Michael Hanselmann
      self._nwaiters -= 1
344 84e344d4 Michael Hanselmann
345 84e344d4 Michael Hanselmann
  def has_waiting(self):
346 84e344d4 Michael Hanselmann
    """Returns whether there are active waiters.
347 84e344d4 Michael Hanselmann

348 84e344d4 Michael Hanselmann
    """
349 84e344d4 Michael Hanselmann
    return bool(self._nwaiters)
350 84e344d4 Michael Hanselmann
351 84e344d4 Michael Hanselmann
352 84e344d4 Michael Hanselmann
class SharedLock(object):
353 162c1c1f Guido Trotter
  """Implements a shared lock.
354 162c1c1f Guido Trotter

355 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
356 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
357 162c1c1f Guido Trotter
  can call acquire_exclusive().
358 162c1c1f Guido Trotter

359 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
360 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
361 162c1c1f Guido Trotter
  eventually do so.
362 162c1c1f Guido Trotter

363 162c1c1f Guido Trotter
  """
364 84e344d4 Michael Hanselmann
  __slots__ = [
365 84e344d4 Michael Hanselmann
    "__active_shr_c",
366 84e344d4 Michael Hanselmann
    "__inactive_shr_c",
367 84e344d4 Michael Hanselmann
    "__deleted",
368 84e344d4 Michael Hanselmann
    "__exc",
369 84e344d4 Michael Hanselmann
    "__lock",
370 84e344d4 Michael Hanselmann
    "__pending",
371 84e344d4 Michael Hanselmann
    "__shr",
372 84e344d4 Michael Hanselmann
    ]
373 84e344d4 Michael Hanselmann
374 34cb5617 Guido Trotter
  __condition_class = PipeCondition
375 84e344d4 Michael Hanselmann
376 162c1c1f Guido Trotter
  def __init__(self):
377 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
378 84e344d4 Michael Hanselmann

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

402 84e344d4 Michael Hanselmann
    """
403 84e344d4 Michael Hanselmann
    if self.__deleted:
404 84e344d4 Michael Hanselmann
      raise errors.LockError("Deleted lock")
405 84e344d4 Michael Hanselmann
406 162c1c1f Guido Trotter
  def __is_sharer(self):
407 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
408 84e344d4 Michael Hanselmann

409 84e344d4 Michael Hanselmann
    """
410 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
411 162c1c1f Guido Trotter
412 162c1c1f Guido Trotter
  def __is_exclusive(self):
413 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
414 84e344d4 Michael Hanselmann

415 84e344d4 Michael Hanselmann
    """
416 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
417 162c1c1f Guido Trotter
418 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
419 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
420 162c1c1f Guido Trotter

421 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
422 162c1c1f Guido Trotter
    the internal lock.
423 162c1c1f Guido Trotter

424 162c1c1f Guido Trotter
    """
425 162c1c1f Guido Trotter
    if shared < 0:
426 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
427 162c1c1f Guido Trotter
    elif shared:
428 162c1c1f Guido Trotter
      return self.__is_sharer()
429 162c1c1f Guido Trotter
    else:
430 162c1c1f Guido Trotter
      return self.__is_exclusive()
431 162c1c1f Guido Trotter
432 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
433 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
434 162c1c1f Guido Trotter

435 c41eea6e Iustin Pop
    @param shared:
436 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
437 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
438 c41eea6e Iustin Pop
        - > 0: check for shared ownership
439 162c1c1f Guido Trotter

440 162c1c1f Guido Trotter
    """
441 162c1c1f Guido Trotter
    self.__lock.acquire()
442 162c1c1f Guido Trotter
    try:
443 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
444 162c1c1f Guido Trotter
    finally:
445 162c1c1f Guido Trotter
      self.__lock.release()
446 162c1c1f Guido Trotter
447 84e344d4 Michael Hanselmann
  def _count_pending(self):
448 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
449 a95fd5d7 Guido Trotter

450 84e344d4 Michael Hanselmann
    @rtype: int
451 a95fd5d7 Guido Trotter

452 a95fd5d7 Guido Trotter
    """
453 84e344d4 Michael Hanselmann
    self.__lock.acquire()
454 84e344d4 Michael Hanselmann
    try:
455 84e344d4 Michael Hanselmann
      return len(self.__pending)
456 84e344d4 Michael Hanselmann
    finally:
457 84e344d4 Michael Hanselmann
      self.__lock.release()
458 a95fd5d7 Guido Trotter
459 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
460 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
461 84e344d4 Michael Hanselmann

462 84e344d4 Michael Hanselmann
    """
463 84e344d4 Michael Hanselmann
    if shared:
464 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
465 84e344d4 Michael Hanselmann
    else:
466 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
467 a95fd5d7 Guido Trotter
468 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
469 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
470 a95fd5d7 Guido Trotter

471 a95fd5d7 Guido Trotter
    """
472 84e344d4 Michael Hanselmann
    if shared:
473 84e344d4 Michael Hanselmann
      return self.__exc is None
474 84e344d4 Michael Hanselmann
    else:
475 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
476 a95fd5d7 Guido Trotter
477 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
478 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
479 a95fd5d7 Guido Trotter

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

482 84e344d4 Michael Hanselmann
    """
483 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
484 4d686df8 Guido Trotter
485 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
486 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
487 9216a9f7 Michael Hanselmann

488 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
489 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
490 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
491 9216a9f7 Michael Hanselmann

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

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

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

564 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
565 162c1c1f Guido Trotter
    before calling this function.
566 162c1c1f Guido Trotter

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

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

598 84e344d4 Michael Hanselmann
    @type timeout: float
599 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
600 a95fd5d7 Guido Trotter

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

638 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
639 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
640 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
641 aaae9bc0 Guido Trotter
  preventing deadlock.
642 aaae9bc0 Guido Trotter

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

645 aaae9bc0 Guido Trotter
  """
646 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
647 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
648 aaae9bc0 Guido Trotter

649 c41eea6e Iustin Pop
    @param members: initial members of the set
650 aaae9bc0 Guido Trotter

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

708 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
709 aaae9bc0 Guido Trotter
    result after releasing the lock.
710 aaae9bc0 Guido Trotter

711 aaae9bc0 Guido Trotter
    """
712 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
713 aaae9bc0 Guido Trotter
714 aaae9bc0 Guido Trotter
  def _names(self):
715 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
716 aaae9bc0 Guido Trotter

717 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
718 cdb08f44 Michael Hanselmann

719 aaae9bc0 Guido Trotter
    """
720 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
721 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
722 d4803c24 Guido Trotter
    release_lock = False
723 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
724 d4803c24 Guido Trotter
      release_lock = True
725 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
726 aaae9bc0 Guido Trotter
    try:
727 aaae9bc0 Guido Trotter
      result = self.__names()
728 aaae9bc0 Guido Trotter
    finally:
729 d4803c24 Guido Trotter
      if release_lock:
730 d4803c24 Guido Trotter
        self.__lock.release()
731 0cf257c5 Guido Trotter
    return set(result)
732 aaae9bc0 Guido Trotter
733 5e0a6daf Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0):
734 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
735 aaae9bc0 Guido Trotter

736 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
737 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
738 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
739 c41eea6e Iustin Pop
        exclusive lock will be acquired
740 5e0a6daf Michael Hanselmann
    @type timeout: float
741 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
742 aaae9bc0 Guido Trotter

743 c41eea6e Iustin Pop
    @return: True when all the locks are successfully acquired
744 aaae9bc0 Guido Trotter

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

749 aaae9bc0 Guido Trotter
    """
750 5e0a6daf Michael Hanselmann
    if timeout is not None:
751 aaae9bc0 Guido Trotter
      raise NotImplementedError
752 aaae9bc0 Guido Trotter
753 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
754 aaae9bc0 Guido Trotter
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
755 aaae9bc0 Guido Trotter
756 3b7ed473 Guido Trotter
    if names is None:
757 3b7ed473 Guido Trotter
      # If no names are given acquire the whole set by not letting new names
758 3b7ed473 Guido Trotter
      # being added before we release, and getting the current list of names.
759 3b7ed473 Guido Trotter
      # Some of them may then be deleted later, but we'll cope with this.
760 3b7ed473 Guido Trotter
      #
761 3b7ed473 Guido Trotter
      # We'd like to acquire this lock in a shared way, as it's nice if
762 3b7ed473 Guido Trotter
      # everybody else can use the instances at the same time. If are acquiring
763 3b7ed473 Guido Trotter
      # them exclusively though they won't be able to do this anyway, though,
764 3b7ed473 Guido Trotter
      # so we'll get the list lock exclusively as well in order to be able to
765 3b7ed473 Guido Trotter
      # do add() on the set while owning it.
766 3b7ed473 Guido Trotter
      self.__lock.acquire(shared=shared)
767 b2dabfd6 Guido Trotter
      try:
768 b2dabfd6 Guido Trotter
        # note we own the set-lock
769 b2dabfd6 Guido Trotter
        self._add_owned()
770 b2dabfd6 Guido Trotter
        names = self.__names()
771 b2dabfd6 Guido Trotter
      except:
772 b2dabfd6 Guido Trotter
        # We shouldn't have problems adding the lock to the owners list, but
773 b2dabfd6 Guido Trotter
        # if we did we'll try to release this lock and re-raise exception.
774 b2dabfd6 Guido Trotter
        # Of course something is going to be really wrong, after this.
775 b2dabfd6 Guido Trotter
        self.__lock.release()
776 b2dabfd6 Guido Trotter
        raise
777 3b7ed473 Guido Trotter
778 806e20fd Guido Trotter
    try:
779 806e20fd Guido Trotter
      # Support passing in a single resource to acquire rather than many
780 806e20fd Guido Trotter
      if isinstance(names, basestring):
781 806e20fd Guido Trotter
        names = [names]
782 806e20fd Guido Trotter
      else:
783 2a21bc88 Iustin Pop
        names = sorted(names)
784 806e20fd Guido Trotter
785 806e20fd Guido Trotter
      acquire_list = []
786 806e20fd Guido Trotter
      # First we look the locks up on __lockdict. We have no way of being sure
787 806e20fd Guido Trotter
      # they will still be there after, but this makes it a lot faster should
788 806e20fd Guido Trotter
      # just one of them be the already wrong
789 34ca3914 Guido Trotter
      for lname in utils.UniqueSequence(names):
790 806e20fd Guido Trotter
        try:
791 4e07ec8c Guido Trotter
          lock = self.__lockdict[lname] # raises KeyError if lock is not there
792 806e20fd Guido Trotter
          acquire_list.append((lname, lock))
793 806e20fd Guido Trotter
        except (KeyError):
794 3b7ed473 Guido Trotter
          if self.__lock._is_owned():
795 f12eadb3 Iustin Pop
            # We are acquiring all the set, it doesn't matter if this
796 f12eadb3 Iustin Pop
            # particular element is not there anymore.
797 3b7ed473 Guido Trotter
            continue
798 3b7ed473 Guido Trotter
          else:
799 3b7ed473 Guido Trotter
            raise errors.LockError('non-existing lock in set (%s)' % lname)
800 806e20fd Guido Trotter
801 806e20fd Guido Trotter
      # This will hold the locknames we effectively acquired.
802 806e20fd Guido Trotter
      acquired = set()
803 806e20fd Guido Trotter
      # Now acquire_list contains a sorted list of resources and locks we want.
804 806e20fd Guido Trotter
      # In order to get them we loop on this (private) list and acquire() them.
805 806e20fd Guido Trotter
      # We gave no real guarantee they will still exist till this is done but
806 806e20fd Guido Trotter
      # .acquire() itself is safe and will alert us if the lock gets deleted.
807 806e20fd Guido Trotter
      for (lname, lock) in acquire_list:
808 aaae9bc0 Guido Trotter
        try:
809 806e20fd Guido Trotter
          lock.acquire(shared=shared) # raises LockError if the lock is deleted
810 ea3f80bf Guido Trotter
          # now the lock cannot be deleted, we have it!
811 b2dabfd6 Guido Trotter
          self._add_owned(name=lname)
812 ea3f80bf Guido Trotter
          acquired.add(lname)
813 806e20fd Guido Trotter
        except (errors.LockError):
814 3b7ed473 Guido Trotter
          if self.__lock._is_owned():
815 f12eadb3 Iustin Pop
            # We are acquiring all the set, it doesn't matter if this
816 f12eadb3 Iustin Pop
            # particular element is not there anymore.
817 3b7ed473 Guido Trotter
            continue
818 3b7ed473 Guido Trotter
          else:
819 3b7ed473 Guido Trotter
            name_fail = lname
820 3b7ed473 Guido Trotter
            for lname in self._list_owned():
821 3b7ed473 Guido Trotter
              self.__lockdict[lname].release()
822 b2dabfd6 Guido Trotter
              self._del_owned(name=lname)
823 3b7ed473 Guido Trotter
            raise errors.LockError('non-existing lock in set (%s)' % name_fail)
824 ea3f80bf Guido Trotter
        except:
825 ea3f80bf Guido Trotter
          # We shouldn't have problems adding the lock to the owners list, but
826 ea3f80bf Guido Trotter
          # if we did we'll try to release this lock and re-raise exception.
827 ea3f80bf Guido Trotter
          # Of course something is going to be really wrong, after this.
828 ea3f80bf Guido Trotter
          if lock._is_owned():
829 ea3f80bf Guido Trotter
            lock.release()
830 470ce2ee Michael Hanselmann
          raise
831 806e20fd Guido Trotter
832 806e20fd Guido Trotter
    except:
833 3b7ed473 Guido Trotter
      # If something went wrong and we had the set-lock let's release it...
834 3b7ed473 Guido Trotter
      if self.__lock._is_owned():
835 3b7ed473 Guido Trotter
        self.__lock.release()
836 806e20fd Guido Trotter
      raise
837 aaae9bc0 Guido Trotter
838 0cc00929 Guido Trotter
    return acquired
839 aaae9bc0 Guido Trotter
840 aaae9bc0 Guido Trotter
  def release(self, names=None):
841 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
842 aaae9bc0 Guido Trotter

843 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
844 aaae9bc0 Guido Trotter
    before releasing them.
845 aaae9bc0 Guido Trotter

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

849 aaae9bc0 Guido Trotter
    """
850 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
851 aaae9bc0 Guido Trotter
852 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
853 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
854 aaae9bc0 Guido Trotter
      names = [names]
855 aaae9bc0 Guido Trotter
856 aaae9bc0 Guido Trotter
    if names is None:
857 aaae9bc0 Guido Trotter
      names = self._list_owned()
858 aaae9bc0 Guido Trotter
    else:
859 aaae9bc0 Guido Trotter
      names = set(names)
860 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
861 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
862 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
863 aaae9bc0 Guido Trotter
864 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
865 3b7ed473 Guido Trotter
    # After this 'add' can work again
866 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
867 3b7ed473 Guido Trotter
      self.__lock.release()
868 b2dabfd6 Guido Trotter
      self._del_owned()
869 3b7ed473 Guido Trotter
870 aaae9bc0 Guido Trotter
    for lockname in names:
871 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
872 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
873 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
874 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
875 aaae9bc0 Guido Trotter
876 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
877 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
878 aaae9bc0 Guido Trotter

879 c41eea6e Iustin Pop
    @param names: names of the new elements to add
880 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
881 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
882 aaae9bc0 Guido Trotter

883 aaae9bc0 Guido Trotter
    """
884 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
885 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
886 d2aff862 Guido Trotter
      "Cannot add locks if the set is only partially owned, or shared"
887 3b7ed473 Guido Trotter
888 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
889 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
890 aaae9bc0 Guido Trotter
      names = [names]
891 aaae9bc0 Guido Trotter
892 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
893 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
894 3b7ed473 Guido Trotter
    release_lock = False
895 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
896 3b7ed473 Guido Trotter
      release_lock = True
897 3b7ed473 Guido Trotter
      self.__lock.acquire()
898 3b7ed473 Guido Trotter
899 aaae9bc0 Guido Trotter
    try:
900 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
901 aaae9bc0 Guido Trotter
      if invalid_names:
902 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
903 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
904 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
905 aaae9bc0 Guido Trotter
        raise errors.LockError("duplicate add() (%s)" % invalid_names)
906 aaae9bc0 Guido Trotter
907 aaae9bc0 Guido Trotter
      for lockname in names:
908 aaae9bc0 Guido Trotter
        lock = SharedLock()
909 aaae9bc0 Guido Trotter
910 aaae9bc0 Guido Trotter
        if acquired:
911 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
912 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
913 aaae9bc0 Guido Trotter
          try:
914 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
915 aaae9bc0 Guido Trotter
          except:
916 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
917 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
918 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
919 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
920 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
921 aaae9bc0 Guido Trotter
            # release is just a safety measure.
922 aaae9bc0 Guido Trotter
            lock.release()
923 aaae9bc0 Guido Trotter
            raise
924 aaae9bc0 Guido Trotter
925 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
926 aaae9bc0 Guido Trotter
927 aaae9bc0 Guido Trotter
    finally:
928 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
929 3b7ed473 Guido Trotter
      if release_lock:
930 3b7ed473 Guido Trotter
        self.__lock.release()
931 aaae9bc0 Guido Trotter
932 aaae9bc0 Guido Trotter
    return True
933 aaae9bc0 Guido Trotter
934 5e0a6daf Michael Hanselmann
  def remove(self, names):
935 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
936 aaae9bc0 Guido Trotter

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

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

942 c41eea6e Iustin Pop
    @return:: a list of locks which we removed; the list is always
943 c41eea6e Iustin Pop
        equal to the names list if we were holding all the locks
944 c41eea6e Iustin Pop
        exclusively
945 aaae9bc0 Guido Trotter

946 aaae9bc0 Guido Trotter
    """
947 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
948 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
949 aaae9bc0 Guido Trotter
      names = [names]
950 aaae9bc0 Guido Trotter
951 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
952 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
953 aaae9bc0 Guido Trotter
    # by the lock itself.
954 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
955 aaae9bc0 Guido Trotter
      "remove() on acquired lockset while not owning all elements")
956 aaae9bc0 Guido Trotter
957 3f404fc5 Guido Trotter
    removed = []
958 aaae9bc0 Guido Trotter
959 aaae9bc0 Guido Trotter
    for lname in names:
960 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
961 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
962 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
963 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
964 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
965 aaae9bc0 Guido Trotter
      try:
966 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
967 3f404fc5 Guido Trotter
        removed.append(lname)
968 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
969 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
970 aaae9bc0 Guido Trotter
        assert not self._is_owned(), "remove failed while holding lockset"
971 aaae9bc0 Guido Trotter
      else:
972 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
973 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
974 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
975 aaae9bc0 Guido Trotter
        # since before our call to delete()).
976 aaae9bc0 Guido Trotter
        #
977 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
978 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
979 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
980 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
981 aaae9bc0 Guido Trotter
        if self._is_owned():
982 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
983 aaae9bc0 Guido Trotter
984 3f404fc5 Guido Trotter
    return removed
985 aaae9bc0 Guido Trotter
986 7ee7c0c7 Guido Trotter
987 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
988 7ee7c0c7 Guido Trotter
# Current rules are:
989 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
990 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
991 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
992 7ee7c0c7 Guido Trotter
#   avoided.
993 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
994 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
995 7ee7c0c7 Guido Trotter
#   the same time.
996 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
997 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
998 04e1bfaf Guido Trotter
LEVEL_NODE = 2
999 7ee7c0c7 Guido Trotter
1000 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1001 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1002 04e1bfaf Guido Trotter
          LEVEL_NODE]
1003 7ee7c0c7 Guido Trotter
1004 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1005 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
1006 7ee7c0c7 Guido Trotter
1007 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1008 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1009 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1010 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1011 ea205dbc Michael Hanselmann
  }
1012 ea205dbc Michael Hanselmann
1013 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1014 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1015 7ee7c0c7 Guido Trotter
1016 7ee7c0c7 Guido Trotter
1017 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1018 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1019 7ee7c0c7 Guido Trotter

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

1025 7ee7c0c7 Guido Trotter
  """
1026 7ee7c0c7 Guido Trotter
  _instance = None
1027 7ee7c0c7 Guido Trotter
1028 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1029 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1030 7ee7c0c7 Guido Trotter

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

1034 c41eea6e Iustin Pop
    @param nodes: list of node names
1035 c41eea6e Iustin Pop
    @param instances: list of instance names
1036 7ee7c0c7 Guido Trotter

1037 7ee7c0c7 Guido Trotter
    """
1038 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1039 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1040 c41eea6e Iustin Pop
1041 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1042 7ee7c0c7 Guido Trotter
1043 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1044 7ee7c0c7 Guido Trotter
    # locking order.
1045 7ee7c0c7 Guido Trotter
    self.__keyring = {
1046 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
1047 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
1048 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
1049 7ee7c0c7 Guido Trotter
    }
1050 7ee7c0c7 Guido Trotter
1051 7ee7c0c7 Guido Trotter
  def _names(self, level):
1052 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1053 7ee7c0c7 Guido Trotter

1054 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1055 c41eea6e Iustin Pop

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

1058 7ee7c0c7 Guido Trotter
    """
1059 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1060 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1061 7ee7c0c7 Guido Trotter
1062 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1063 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1064 7ee7c0c7 Guido Trotter

1065 7ee7c0c7 Guido Trotter
    """
1066 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1067 7ee7c0c7 Guido Trotter
1068 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1069 d4f4b3e7 Guido Trotter
1070 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1071 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1072 7ee7c0c7 Guido Trotter

1073 7ee7c0c7 Guido Trotter
    """
1074 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1075 7ee7c0c7 Guido Trotter
1076 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1077 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1078 7ee7c0c7 Guido Trotter

1079 7ee7c0c7 Guido Trotter
    """
1080 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1081 7ee7c0c7 Guido Trotter
    # the test cases.
1082 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1083 7ee7c0c7 Guido Trotter
1084 7ee7c0c7 Guido Trotter
  def _BGL_owned(self):
1085 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1086 7ee7c0c7 Guido Trotter

1087 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1088 7ee7c0c7 Guido Trotter

1089 7ee7c0c7 Guido Trotter
    """
1090 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1091 7ee7c0c7 Guido Trotter
1092 7ee7c0c7 Guido Trotter
  def _contains_BGL(self, level, names):
1093 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1094 c41eea6e Iustin Pop

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

1098 7ee7c0c7 Guido Trotter
    """
1099 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1100 7ee7c0c7 Guido Trotter
1101 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1102 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1103 7ee7c0c7 Guido Trotter

1104 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be acquired;
1105 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS.
1106 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1107 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1108 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1109 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1110 5e0a6daf Michael Hanselmann
    @type timeout: float
1111 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1112 7ee7c0c7 Guido Trotter

1113 7ee7c0c7 Guido Trotter
    """
1114 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1115 7ee7c0c7 Guido Trotter
1116 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1117 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1118 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1119 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1120 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1121 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1122 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1123 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1124 7ee7c0c7 Guido Trotter
1125 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1126 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1127 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1128 7ee7c0c7 Guido Trotter
1129 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1130 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1131 7ee7c0c7 Guido Trotter
1132 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1133 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1134 7ee7c0c7 Guido Trotter

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

1138 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be released;
1139 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS
1140 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1141 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1142 7ee7c0c7 Guido Trotter

1143 7ee7c0c7 Guido Trotter
    """
1144 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1145 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1146 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1147 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1148 7ee7c0c7 Guido Trotter
            " at upper levels")
1149 7ee7c0c7 Guido Trotter
1150 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1151 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1152 7ee7c0c7 Guido Trotter
1153 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1154 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1155 7ee7c0c7 Guido Trotter

1156 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be added;
1157 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS_MOD.
1158 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1159 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1160 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1161 c41eea6e Iustin Pop

1162 7ee7c0c7 Guido Trotter
    """
1163 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1164 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1165 7ee7c0c7 Guido Trotter
           " operations")
1166 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1167 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1168 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1169 7ee7c0c7 Guido Trotter
1170 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1171 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1172 7ee7c0c7 Guido Trotter

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

1176 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be removed;
1177 c41eea6e Iustin Pop
        it must be a member of LEVELS_MOD
1178 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1179 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1180 7ee7c0c7 Guido Trotter

1181 7ee7c0c7 Guido Trotter
    """
1182 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1183 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1184 7ee7c0c7 Guido Trotter
           " operations")
1185 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1186 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1187 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1188 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1189 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1190 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1191 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)