Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 2419060d

History | View | Annotate | Download (36.8 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 d76167a5 Michael Hanselmann
class _SingleActionPipeConditionWaiter(object):
53 d76167a5 Michael Hanselmann
  """Callable helper class for _SingleActionPipeCondition.
54 d76167a5 Michael Hanselmann

55 d76167a5 Michael Hanselmann
  """
56 d76167a5 Michael Hanselmann
  __slots__ = [
57 d76167a5 Michael Hanselmann
    "_cond",
58 d76167a5 Michael Hanselmann
    "_fd",
59 d76167a5 Michael Hanselmann
    "_poller",
60 d76167a5 Michael Hanselmann
    ]
61 d76167a5 Michael Hanselmann
62 d76167a5 Michael Hanselmann
  def __init__(self, cond, poller, fd):
63 d76167a5 Michael Hanselmann
    """Initializes this class.
64 d76167a5 Michael Hanselmann

65 d76167a5 Michael Hanselmann
    @type cond: L{_SingleActionPipeCondition}
66 d76167a5 Michael Hanselmann
    @param cond: Parent condition
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
75 d76167a5 Michael Hanselmann
    self._cond = cond
76 d76167a5 Michael Hanselmann
    self._poller = poller
77 d76167a5 Michael Hanselmann
    self._fd = fd
78 d76167a5 Michael Hanselmann
79 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
80 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
81 d76167a5 Michael Hanselmann

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

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

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

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

121 2419060d Guido Trotter
    @type lock: L{threading.Lock}
122 2419060d Guido Trotter
    @param lock: condition base lock
123 2419060d Guido Trotter

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

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

150 2419060d Guido Trotter
    """
151 2419060d Guido Trotter
    if not self._is_owned():
152 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
153 2419060d Guido Trotter
154 2419060d Guido Trotter
155 d76167a5 Michael Hanselmann
class _SingleActionPipeCondition(object):
156 d76167a5 Michael Hanselmann
  """Wrapper around a pipe for usage inside conditions.
157 d76167a5 Michael Hanselmann

158 d76167a5 Michael Hanselmann
  This class contains a POSIX pipe(2) and a poller to poll it. The pipe is
159 d76167a5 Michael Hanselmann
  always allocated when constructing the class. Extra care is taken to always
160 d76167a5 Michael Hanselmann
  close the file descriptors.
161 d76167a5 Michael Hanselmann

162 d76167a5 Michael Hanselmann
  An additional class, L{_SingleActionPipeConditionWaiter}, is used to wait for
163 d76167a5 Michael Hanselmann
  notifications.
164 d76167a5 Michael Hanselmann

165 d76167a5 Michael Hanselmann
  Warning: This class is designed to be used as the underlying component of a
166 d76167a5 Michael Hanselmann
  locking condition, but is not by itself thread safe, and needs to be
167 d76167a5 Michael Hanselmann
  protected by an external lock.
168 d76167a5 Michael Hanselmann

169 d76167a5 Michael Hanselmann
  """
170 d76167a5 Michael Hanselmann
  __slots__ = [
171 d76167a5 Michael Hanselmann
    "_poller",
172 d76167a5 Michael Hanselmann
    "_read_fd",
173 d76167a5 Michael Hanselmann
    "_write_fd",
174 d76167a5 Michael Hanselmann
    "_nwaiters",
175 d76167a5 Michael Hanselmann
    ]
176 d76167a5 Michael Hanselmann
177 d76167a5 Michael Hanselmann
  _waiter_class = _SingleActionPipeConditionWaiter
178 d76167a5 Michael Hanselmann
179 d76167a5 Michael Hanselmann
  def __init__(self):
180 d76167a5 Michael Hanselmann
    """Initializes this class.
181 d76167a5 Michael Hanselmann

182 d76167a5 Michael Hanselmann
    """
183 d76167a5 Michael Hanselmann
    object.__init__(self)
184 d76167a5 Michael Hanselmann
185 d76167a5 Michael Hanselmann
    self._nwaiters = 0
186 d76167a5 Michael Hanselmann
187 d76167a5 Michael Hanselmann
    # Just assume the unpacking is successful, otherwise error handling gets
188 d76167a5 Michael Hanselmann
    # very complicated.
189 d76167a5 Michael Hanselmann
    (self._read_fd, self._write_fd) = os.pipe()
190 d76167a5 Michael Hanselmann
    try:
191 d76167a5 Michael Hanselmann
      # The poller looks for closure of the write side
192 d76167a5 Michael Hanselmann
      poller = select.poll()
193 d76167a5 Michael Hanselmann
      poller.register(self._read_fd, select.POLLHUP)
194 d76167a5 Michael Hanselmann
195 d76167a5 Michael Hanselmann
      self._poller = poller
196 d76167a5 Michael Hanselmann
    except:
197 d76167a5 Michael Hanselmann
      if self._read_fd is not None:
198 d76167a5 Michael Hanselmann
        os.close(self._read_fd)
199 d76167a5 Michael Hanselmann
      if self._write_fd is not None:
200 d76167a5 Michael Hanselmann
        os.close(self._write_fd)
201 d76167a5 Michael Hanselmann
      raise
202 d76167a5 Michael Hanselmann
203 d76167a5 Michael Hanselmann
    # There should be no code here anymore, otherwise the pipe file descriptors
204 d76167a5 Michael Hanselmann
    # may be not be cleaned up properly in case of errors.
205 d76167a5 Michael Hanselmann
206 d76167a5 Michael Hanselmann
  def StartWaiting(self):
207 d76167a5 Michael Hanselmann
    """Return function to wait for notification.
208 d76167a5 Michael Hanselmann

209 d76167a5 Michael Hanselmann
    @rtype: L{_SingleActionPipeConditionWaiter}
210 d76167a5 Michael Hanselmann
    @return: Function to wait for notification
211 d76167a5 Michael Hanselmann

212 d76167a5 Michael Hanselmann
    """
213 d76167a5 Michael Hanselmann
    assert self._nwaiters >= 0
214 d76167a5 Michael Hanselmann
215 d76167a5 Michael Hanselmann
    if self._poller is None:
216 d76167a5 Michael Hanselmann
      raise RuntimeError("Already cleaned up")
217 d76167a5 Michael Hanselmann
218 d76167a5 Michael Hanselmann
    # Create waiter function and increase number of waiters
219 d76167a5 Michael Hanselmann
    wait_fn = self._waiter_class(self, self._poller, self._read_fd)
220 d76167a5 Michael Hanselmann
    self._nwaiters += 1
221 d76167a5 Michael Hanselmann
    return wait_fn
222 d76167a5 Michael Hanselmann
223 d76167a5 Michael Hanselmann
  def DoneWaiting(self):
224 d76167a5 Michael Hanselmann
    """Decrement number of waiters and automatic cleanup.
225 d76167a5 Michael Hanselmann

226 d76167a5 Michael Hanselmann
    Must be called after waiting for a notification.
227 d76167a5 Michael Hanselmann

228 d76167a5 Michael Hanselmann
    @rtype: bool
229 d76167a5 Michael Hanselmann
    @return: Whether this was the last waiter
230 d76167a5 Michael Hanselmann

231 d76167a5 Michael Hanselmann
    """
232 d76167a5 Michael Hanselmann
    assert self._nwaiters > 0
233 d76167a5 Michael Hanselmann
234 d76167a5 Michael Hanselmann
    self._nwaiters -= 1
235 d76167a5 Michael Hanselmann
236 d76167a5 Michael Hanselmann
    if self._nwaiters == 0:
237 d76167a5 Michael Hanselmann
      self._Cleanup()
238 d76167a5 Michael Hanselmann
      return True
239 d76167a5 Michael Hanselmann
240 d76167a5 Michael Hanselmann
    return False
241 d76167a5 Michael Hanselmann
242 d76167a5 Michael Hanselmann
  def notifyAll(self):
243 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
244 d76167a5 Michael Hanselmann

245 d76167a5 Michael Hanselmann
    """
246 d76167a5 Michael Hanselmann
    if self._write_fd is None:
247 d76167a5 Michael Hanselmann
      raise RuntimeError("Can only notify once")
248 d76167a5 Michael Hanselmann
249 d76167a5 Michael Hanselmann
    os.close(self._write_fd)
250 d76167a5 Michael Hanselmann
    self._write_fd = None
251 d76167a5 Michael Hanselmann
252 d76167a5 Michael Hanselmann
  def _Cleanup(self):
253 d76167a5 Michael Hanselmann
    """Close all file descriptors.
254 d76167a5 Michael Hanselmann

255 d76167a5 Michael Hanselmann
    """
256 d76167a5 Michael Hanselmann
    if self._read_fd is not None:
257 d76167a5 Michael Hanselmann
      os.close(self._read_fd)
258 d76167a5 Michael Hanselmann
      self._read_fd = None
259 d76167a5 Michael Hanselmann
260 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
261 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
262 d76167a5 Michael Hanselmann
      self._write_fd = None
263 d76167a5 Michael Hanselmann
264 d76167a5 Michael Hanselmann
    self._poller = None
265 d76167a5 Michael Hanselmann
266 d76167a5 Michael Hanselmann
  def __del__(self):
267 d76167a5 Michael Hanselmann
    """Called on object deletion.
268 d76167a5 Michael Hanselmann

269 d76167a5 Michael Hanselmann
    Ensure no file descriptors are left open.
270 d76167a5 Michael Hanselmann

271 d76167a5 Michael Hanselmann
    """
272 d76167a5 Michael Hanselmann
    self._Cleanup()
273 d76167a5 Michael Hanselmann
274 d76167a5 Michael Hanselmann
275 2419060d Guido Trotter
class _PipeCondition(_BaseCondition):
276 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
277 48dabc6a Michael Hanselmann

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

284 48dabc6a Michael Hanselmann
  """
285 2419060d Guido Trotter
  __slots__ = _BaseCondition.__slots__ + [
286 48dabc6a Michael Hanselmann
    "_nwaiters",
287 48dabc6a Michael Hanselmann
    "_pipe",
288 48dabc6a Michael Hanselmann
    ]
289 48dabc6a Michael Hanselmann
290 48dabc6a Michael Hanselmann
  _pipe_class = _SingleActionPipeCondition
291 48dabc6a Michael Hanselmann
292 48dabc6a Michael Hanselmann
  def __init__(self, lock):
293 48dabc6a Michael Hanselmann
    """Initializes this class.
294 48dabc6a Michael Hanselmann

295 48dabc6a Michael Hanselmann
    """
296 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
297 48dabc6a Michael Hanselmann
    self._nwaiters = 0
298 48dabc6a Michael Hanselmann
    self._pipe = None
299 48dabc6a Michael Hanselmann
300 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
301 48dabc6a Michael Hanselmann
    """Wait for a notification.
302 48dabc6a Michael Hanselmann

303 48dabc6a Michael Hanselmann
    @type timeout: float or None
304 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
305 48dabc6a Michael Hanselmann

306 48dabc6a Michael Hanselmann
    """
307 48dabc6a Michael Hanselmann
    self._check_owned()
308 48dabc6a Michael Hanselmann
309 48dabc6a Michael Hanselmann
    if not self._pipe:
310 48dabc6a Michael Hanselmann
      self._pipe = self._pipe_class()
311 48dabc6a Michael Hanselmann
312 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
313 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
314 48dabc6a Michael Hanselmann
    pipe = self._pipe
315 48dabc6a Michael Hanselmann
316 48dabc6a Michael Hanselmann
    assert self._nwaiters >= 0
317 48dabc6a Michael Hanselmann
    self._nwaiters += 1
318 48dabc6a Michael Hanselmann
    try:
319 48dabc6a Michael Hanselmann
      # Get function to wait on the pipe
320 48dabc6a Michael Hanselmann
      wait_fn = pipe.StartWaiting()
321 48dabc6a Michael Hanselmann
      try:
322 48dabc6a Michael Hanselmann
        # Release lock while waiting
323 48dabc6a Michael Hanselmann
        self.release()
324 48dabc6a Michael Hanselmann
        try:
325 48dabc6a Michael Hanselmann
          # Wait for notification
326 48dabc6a Michael Hanselmann
          wait_fn(timeout)
327 48dabc6a Michael Hanselmann
        finally:
328 48dabc6a Michael Hanselmann
          # Re-acquire lock
329 48dabc6a Michael Hanselmann
          self.acquire()
330 48dabc6a Michael Hanselmann
      finally:
331 48dabc6a Michael Hanselmann
        # Destroy pipe if this was the last waiter and the current pipe is
332 48dabc6a Michael Hanselmann
        # still the same. The same pipe cannot be reused after cleanup.
333 48dabc6a Michael Hanselmann
        if pipe.DoneWaiting() and pipe == self._pipe:
334 48dabc6a Michael Hanselmann
          self._pipe = None
335 48dabc6a Michael Hanselmann
    finally:
336 48dabc6a Michael Hanselmann
      assert self._nwaiters > 0
337 48dabc6a Michael Hanselmann
      self._nwaiters -= 1
338 48dabc6a Michael Hanselmann
339 48dabc6a Michael Hanselmann
  def notifyAll(self):
340 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
341 48dabc6a Michael Hanselmann

342 48dabc6a Michael Hanselmann
    """
343 48dabc6a Michael Hanselmann
    self._check_owned()
344 48dabc6a Michael Hanselmann
345 48dabc6a Michael Hanselmann
    # Notify and forget pipe. A new one will be created on the next call to
346 48dabc6a Michael Hanselmann
    # wait.
347 48dabc6a Michael Hanselmann
    if self._pipe is not None:
348 48dabc6a Michael Hanselmann
      self._pipe.notifyAll()
349 48dabc6a Michael Hanselmann
      self._pipe = None
350 48dabc6a Michael Hanselmann
351 48dabc6a Michael Hanselmann
  def has_waiting(self):
352 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
353 48dabc6a Michael Hanselmann

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

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

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

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

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

389 84e344d4 Michael Hanselmann
    @type timeout: float or None
390 84e344d4 Michael Hanselmann
    @param timeout: Timeout in seconds
391 84e344d4 Michael Hanselmann

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

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

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

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

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

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

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

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

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

477 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
478 162c1c1f Guido Trotter
    the internal lock.
479 162c1c1f Guido Trotter

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

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

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

506 84e344d4 Michael Hanselmann
    @rtype: int
507 a95fd5d7 Guido Trotter

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

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

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

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

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

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

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

598 84e344d4 Michael Hanselmann
    @type shared: int
599 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
600 c41eea6e Iustin Pop
        exclusive lock will be acquired
601 84e344d4 Michael Hanselmann
    @type timeout: float
602 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
603 162c1c1f Guido Trotter

604 162c1c1f Guido Trotter
    """
605 162c1c1f Guido Trotter
    self.__lock.acquire()
606 162c1c1f Guido Trotter
    try:
607 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
608 162c1c1f Guido Trotter
    finally:
609 162c1c1f Guido Trotter
      self.__lock.release()
610 162c1c1f Guido Trotter
611 162c1c1f Guido Trotter
  def release(self):
612 162c1c1f Guido Trotter
    """Release a Shared Lock.
613 162c1c1f Guido Trotter

614 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
615 162c1c1f Guido Trotter
    before calling this function.
616 162c1c1f Guido Trotter

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

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

648 84e344d4 Michael Hanselmann
    @type timeout: float
649 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
650 a95fd5d7 Guido Trotter

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

688 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
689 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
690 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
691 aaae9bc0 Guido Trotter
  preventing deadlock.
692 aaae9bc0 Guido Trotter

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

695 aaae9bc0 Guido Trotter
  """
696 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
697 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
698 aaae9bc0 Guido Trotter

699 c41eea6e Iustin Pop
    @param members: initial members of the set
700 aaae9bc0 Guido Trotter

701 aaae9bc0 Guido Trotter
    """
702 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
703 aaae9bc0 Guido Trotter
    self.__lock = SharedLock()
704 aaae9bc0 Guido Trotter
705 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
706 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
707 aaae9bc0 Guido Trotter
    self.__lockdict = {}
708 aaae9bc0 Guido Trotter
709 aaae9bc0 Guido Trotter
    if members is not None:
710 aaae9bc0 Guido Trotter
      for name in members:
711 aaae9bc0 Guido Trotter
        self.__lockdict[name] = SharedLock()
712 aaae9bc0 Guido Trotter
713 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
714 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
715 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
716 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
717 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
718 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
719 aaae9bc0 Guido Trotter
    # will be trouble.
720 aaae9bc0 Guido Trotter
    self.__owners = {}
721 aaae9bc0 Guido Trotter
722 aaae9bc0 Guido Trotter
  def _is_owned(self):
723 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
724 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
725 aaae9bc0 Guido Trotter
726 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
727 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
728 b2dabfd6 Guido Trotter
    if name is None:
729 b2dabfd6 Guido Trotter
      if not self._is_owned():
730 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
731 aaae9bc0 Guido Trotter
    else:
732 b2dabfd6 Guido Trotter
      if self._is_owned():
733 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
734 b2dabfd6 Guido Trotter
      else:
735 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
736 b2dabfd6 Guido Trotter
737 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
738 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
739 aaae9bc0 Guido Trotter
740 b2dabfd6 Guido Trotter
    if name is not None:
741 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
742 b2dabfd6 Guido Trotter
743 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
744 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
745 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
746 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
747 aaae9bc0 Guido Trotter
748 aaae9bc0 Guido Trotter
  def _list_owned(self):
749 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
750 aaae9bc0 Guido Trotter
    if self._is_owned():
751 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
752 aaae9bc0 Guido Trotter
    else:
753 aaae9bc0 Guido Trotter
      return set()
754 aaae9bc0 Guido Trotter
755 aaae9bc0 Guido Trotter
  def __names(self):
756 aaae9bc0 Guido Trotter
    """Return the current set of names.
757 aaae9bc0 Guido Trotter

758 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
759 aaae9bc0 Guido Trotter
    result after releasing the lock.
760 aaae9bc0 Guido Trotter

761 aaae9bc0 Guido Trotter
    """
762 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
763 aaae9bc0 Guido Trotter
764 aaae9bc0 Guido Trotter
  def _names(self):
765 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
766 aaae9bc0 Guido Trotter

767 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
768 cdb08f44 Michael Hanselmann

769 aaae9bc0 Guido Trotter
    """
770 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
771 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
772 d4803c24 Guido Trotter
    release_lock = False
773 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
774 d4803c24 Guido Trotter
      release_lock = True
775 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
776 aaae9bc0 Guido Trotter
    try:
777 aaae9bc0 Guido Trotter
      result = self.__names()
778 aaae9bc0 Guido Trotter
    finally:
779 d4803c24 Guido Trotter
      if release_lock:
780 d4803c24 Guido Trotter
        self.__lock.release()
781 0cf257c5 Guido Trotter
    return set(result)
782 aaae9bc0 Guido Trotter
783 5e0a6daf Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0):
784 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
785 aaae9bc0 Guido Trotter

786 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
787 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
788 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
789 c41eea6e Iustin Pop
        exclusive lock will be acquired
790 5e0a6daf Michael Hanselmann
    @type timeout: float
791 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
792 aaae9bc0 Guido Trotter

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

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

799 aaae9bc0 Guido Trotter
    """
800 5e0a6daf Michael Hanselmann
    if timeout is not None:
801 aaae9bc0 Guido Trotter
      raise NotImplementedError
802 aaae9bc0 Guido Trotter
803 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
804 aaae9bc0 Guido Trotter
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
805 aaae9bc0 Guido Trotter
806 3b7ed473 Guido Trotter
    if names is None:
807 3b7ed473 Guido Trotter
      # If no names are given acquire the whole set by not letting new names
808 3b7ed473 Guido Trotter
      # being added before we release, and getting the current list of names.
809 3b7ed473 Guido Trotter
      # Some of them may then be deleted later, but we'll cope with this.
810 3b7ed473 Guido Trotter
      #
811 3b7ed473 Guido Trotter
      # We'd like to acquire this lock in a shared way, as it's nice if
812 3b7ed473 Guido Trotter
      # everybody else can use the instances at the same time. If are acquiring
813 3b7ed473 Guido Trotter
      # them exclusively though they won't be able to do this anyway, though,
814 3b7ed473 Guido Trotter
      # so we'll get the list lock exclusively as well in order to be able to
815 3b7ed473 Guido Trotter
      # do add() on the set while owning it.
816 3b7ed473 Guido Trotter
      self.__lock.acquire(shared=shared)
817 b2dabfd6 Guido Trotter
      try:
818 b2dabfd6 Guido Trotter
        # note we own the set-lock
819 b2dabfd6 Guido Trotter
        self._add_owned()
820 b2dabfd6 Guido Trotter
        names = self.__names()
821 b2dabfd6 Guido Trotter
      except:
822 b2dabfd6 Guido Trotter
        # We shouldn't have problems adding the lock to the owners list, but
823 b2dabfd6 Guido Trotter
        # if we did we'll try to release this lock and re-raise exception.
824 b2dabfd6 Guido Trotter
        # Of course something is going to be really wrong, after this.
825 b2dabfd6 Guido Trotter
        self.__lock.release()
826 b2dabfd6 Guido Trotter
        raise
827 3b7ed473 Guido Trotter
828 806e20fd Guido Trotter
    try:
829 806e20fd Guido Trotter
      # Support passing in a single resource to acquire rather than many
830 806e20fd Guido Trotter
      if isinstance(names, basestring):
831 806e20fd Guido Trotter
        names = [names]
832 806e20fd Guido Trotter
      else:
833 2a21bc88 Iustin Pop
        names = sorted(names)
834 806e20fd Guido Trotter
835 806e20fd Guido Trotter
      acquire_list = []
836 806e20fd Guido Trotter
      # First we look the locks up on __lockdict. We have no way of being sure
837 806e20fd Guido Trotter
      # they will still be there after, but this makes it a lot faster should
838 806e20fd Guido Trotter
      # just one of them be the already wrong
839 34ca3914 Guido Trotter
      for lname in utils.UniqueSequence(names):
840 806e20fd Guido Trotter
        try:
841 4e07ec8c Guido Trotter
          lock = self.__lockdict[lname] # raises KeyError if lock is not there
842 806e20fd Guido Trotter
          acquire_list.append((lname, lock))
843 806e20fd Guido Trotter
        except (KeyError):
844 3b7ed473 Guido Trotter
          if self.__lock._is_owned():
845 f12eadb3 Iustin Pop
            # We are acquiring all the set, it doesn't matter if this
846 f12eadb3 Iustin Pop
            # particular element is not there anymore.
847 3b7ed473 Guido Trotter
            continue
848 3b7ed473 Guido Trotter
          else:
849 3b7ed473 Guido Trotter
            raise errors.LockError('non-existing lock in set (%s)' % lname)
850 806e20fd Guido Trotter
851 806e20fd Guido Trotter
      # This will hold the locknames we effectively acquired.
852 806e20fd Guido Trotter
      acquired = set()
853 806e20fd Guido Trotter
      # Now acquire_list contains a sorted list of resources and locks we want.
854 806e20fd Guido Trotter
      # In order to get them we loop on this (private) list and acquire() them.
855 806e20fd Guido Trotter
      # We gave no real guarantee they will still exist till this is done but
856 806e20fd Guido Trotter
      # .acquire() itself is safe and will alert us if the lock gets deleted.
857 806e20fd Guido Trotter
      for (lname, lock) in acquire_list:
858 aaae9bc0 Guido Trotter
        try:
859 806e20fd Guido Trotter
          lock.acquire(shared=shared) # raises LockError if the lock is deleted
860 ea3f80bf Guido Trotter
          # now the lock cannot be deleted, we have it!
861 b2dabfd6 Guido Trotter
          self._add_owned(name=lname)
862 ea3f80bf Guido Trotter
          acquired.add(lname)
863 806e20fd Guido Trotter
        except (errors.LockError):
864 3b7ed473 Guido Trotter
          if self.__lock._is_owned():
865 f12eadb3 Iustin Pop
            # We are acquiring all the set, it doesn't matter if this
866 f12eadb3 Iustin Pop
            # particular element is not there anymore.
867 3b7ed473 Guido Trotter
            continue
868 3b7ed473 Guido Trotter
          else:
869 3b7ed473 Guido Trotter
            name_fail = lname
870 3b7ed473 Guido Trotter
            for lname in self._list_owned():
871 3b7ed473 Guido Trotter
              self.__lockdict[lname].release()
872 b2dabfd6 Guido Trotter
              self._del_owned(name=lname)
873 3b7ed473 Guido Trotter
            raise errors.LockError('non-existing lock in set (%s)' % name_fail)
874 ea3f80bf Guido Trotter
        except:
875 ea3f80bf Guido Trotter
          # We shouldn't have problems adding the lock to the owners list, but
876 ea3f80bf Guido Trotter
          # if we did we'll try to release this lock and re-raise exception.
877 ea3f80bf Guido Trotter
          # Of course something is going to be really wrong, after this.
878 ea3f80bf Guido Trotter
          if lock._is_owned():
879 ea3f80bf Guido Trotter
            lock.release()
880 470ce2ee Michael Hanselmann
          raise
881 806e20fd Guido Trotter
882 806e20fd Guido Trotter
    except:
883 3b7ed473 Guido Trotter
      # If something went wrong and we had the set-lock let's release it...
884 3b7ed473 Guido Trotter
      if self.__lock._is_owned():
885 3b7ed473 Guido Trotter
        self.__lock.release()
886 806e20fd Guido Trotter
      raise
887 aaae9bc0 Guido Trotter
888 0cc00929 Guido Trotter
    return acquired
889 aaae9bc0 Guido Trotter
890 aaae9bc0 Guido Trotter
  def release(self, names=None):
891 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
892 aaae9bc0 Guido Trotter

893 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
894 aaae9bc0 Guido Trotter
    before releasing them.
895 aaae9bc0 Guido Trotter

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

899 aaae9bc0 Guido Trotter
    """
900 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
901 aaae9bc0 Guido Trotter
902 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
903 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
904 aaae9bc0 Guido Trotter
      names = [names]
905 aaae9bc0 Guido Trotter
906 aaae9bc0 Guido Trotter
    if names is None:
907 aaae9bc0 Guido Trotter
      names = self._list_owned()
908 aaae9bc0 Guido Trotter
    else:
909 aaae9bc0 Guido Trotter
      names = set(names)
910 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
911 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
912 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
913 aaae9bc0 Guido Trotter
914 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
915 3b7ed473 Guido Trotter
    # After this 'add' can work again
916 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
917 3b7ed473 Guido Trotter
      self.__lock.release()
918 b2dabfd6 Guido Trotter
      self._del_owned()
919 3b7ed473 Guido Trotter
920 aaae9bc0 Guido Trotter
    for lockname in names:
921 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
922 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
923 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
924 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
925 aaae9bc0 Guido Trotter
926 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
927 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
928 aaae9bc0 Guido Trotter

929 c41eea6e Iustin Pop
    @param names: names of the new elements to add
930 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
931 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
932 aaae9bc0 Guido Trotter

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

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

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

992 c41eea6e Iustin Pop
    @return:: a list of locks which we removed; the list is always
993 c41eea6e Iustin Pop
        equal to the names list if we were holding all the locks
994 c41eea6e Iustin Pop
        exclusively
995 aaae9bc0 Guido Trotter

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

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

1075 7ee7c0c7 Guido Trotter
  """
1076 7ee7c0c7 Guido Trotter
  _instance = None
1077 7ee7c0c7 Guido Trotter
1078 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1079 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1080 7ee7c0c7 Guido Trotter

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

1084 c41eea6e Iustin Pop
    @param nodes: list of node names
1085 c41eea6e Iustin Pop
    @param instances: list of instance names
1086 7ee7c0c7 Guido Trotter

1087 7ee7c0c7 Guido Trotter
    """
1088 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1089 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1090 c41eea6e Iustin Pop
1091 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1092 7ee7c0c7 Guido Trotter
1093 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1094 7ee7c0c7 Guido Trotter
    # locking order.
1095 7ee7c0c7 Guido Trotter
    self.__keyring = {
1096 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
1097 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
1098 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
1099 7ee7c0c7 Guido Trotter
    }
1100 7ee7c0c7 Guido Trotter
1101 7ee7c0c7 Guido Trotter
  def _names(self, level):
1102 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1103 7ee7c0c7 Guido Trotter

1104 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1105 c41eea6e Iustin Pop

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

1108 7ee7c0c7 Guido Trotter
    """
1109 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1110 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1111 7ee7c0c7 Guido Trotter
1112 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1113 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1114 7ee7c0c7 Guido Trotter

1115 7ee7c0c7 Guido Trotter
    """
1116 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1117 7ee7c0c7 Guido Trotter
1118 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1119 d4f4b3e7 Guido Trotter
1120 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1121 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1122 7ee7c0c7 Guido Trotter

1123 7ee7c0c7 Guido Trotter
    """
1124 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1125 7ee7c0c7 Guido Trotter
1126 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1127 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1128 7ee7c0c7 Guido Trotter

1129 7ee7c0c7 Guido Trotter
    """
1130 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1131 7ee7c0c7 Guido Trotter
    # the test cases.
1132 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1133 7ee7c0c7 Guido Trotter
1134 7ee7c0c7 Guido Trotter
  def _BGL_owned(self):
1135 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1136 7ee7c0c7 Guido Trotter

1137 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1138 7ee7c0c7 Guido Trotter

1139 7ee7c0c7 Guido Trotter
    """
1140 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1141 7ee7c0c7 Guido Trotter
1142 7ee7c0c7 Guido Trotter
  def _contains_BGL(self, level, names):
1143 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1144 c41eea6e Iustin Pop

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

1148 7ee7c0c7 Guido Trotter
    """
1149 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1150 7ee7c0c7 Guido Trotter
1151 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1152 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1153 7ee7c0c7 Guido Trotter

1154 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be acquired;
1155 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS.
1156 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1157 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1158 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1159 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1160 5e0a6daf Michael Hanselmann
    @type timeout: float
1161 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1162 7ee7c0c7 Guido Trotter

1163 7ee7c0c7 Guido Trotter
    """
1164 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1165 7ee7c0c7 Guido Trotter
1166 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1167 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1168 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1169 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1170 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1171 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1172 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1173 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1174 7ee7c0c7 Guido Trotter
1175 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1176 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1177 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1178 7ee7c0c7 Guido Trotter
1179 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1180 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1181 7ee7c0c7 Guido Trotter
1182 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1183 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1184 7ee7c0c7 Guido Trotter

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

1188 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be released;
1189 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS
1190 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1191 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1192 7ee7c0c7 Guido Trotter

1193 7ee7c0c7 Guido Trotter
    """
1194 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1195 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1196 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1197 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1198 7ee7c0c7 Guido Trotter
            " at upper levels")
1199 7ee7c0c7 Guido Trotter
1200 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1201 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1202 7ee7c0c7 Guido Trotter
1203 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1204 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1205 7ee7c0c7 Guido Trotter

1206 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be added;
1207 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS_MOD.
1208 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1209 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1210 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1211 c41eea6e Iustin Pop

1212 7ee7c0c7 Guido Trotter
    """
1213 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1214 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1215 7ee7c0c7 Guido Trotter
           " operations")
1216 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1217 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1218 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1219 7ee7c0c7 Guido Trotter
1220 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1221 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1222 7ee7c0c7 Guido Trotter

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

1226 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be removed;
1227 c41eea6e Iustin Pop
        it must be a member of LEVELS_MOD
1228 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1229 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1230 7ee7c0c7 Guido Trotter

1231 7ee7c0c7 Guido Trotter
    """
1232 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1233 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1234 7ee7c0c7 Guido Trotter
           " operations")
1235 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1236 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1237 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1238 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1239 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1240 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1241 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)