Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 2d48a3a2

History | View | Annotate | Download (48.7 kB)

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

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

55 dbb11e8b Guido Trotter
  @type mylock: lockable object or string
56 dbb11e8b Guido Trotter
  @param mylock: lock to acquire or class member name of the lock to acquire
57 dbb11e8b Guido Trotter

58 42a999d1 Guido Trotter
  """
59 42a999d1 Guido Trotter
  def wrap(fn):
60 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
61 dbb11e8b Guido Trotter
      if isinstance(mylock, basestring):
62 dbb11e8b Guido Trotter
        assert args, "cannot ssynchronize on non-class method: self not found"
63 dbb11e8b Guido Trotter
        # args[0] is "self"
64 dbb11e8b Guido Trotter
        lock = getattr(args[0], mylock)
65 dbb11e8b Guido Trotter
      else:
66 dbb11e8b Guido Trotter
        lock = mylock
67 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
68 42a999d1 Guido Trotter
      try:
69 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
70 42a999d1 Guido Trotter
      finally:
71 42a999d1 Guido Trotter
        lock.release()
72 42a999d1 Guido Trotter
    return sync_function
73 42a999d1 Guido Trotter
  return wrap
74 42a999d1 Guido Trotter
75 42a999d1 Guido Trotter
76 7e8841bd Michael Hanselmann
class RunningTimeout(object):
77 7e8841bd Michael Hanselmann
  """Class to calculate remaining timeout when doing several operations.
78 7e8841bd Michael Hanselmann

79 7e8841bd Michael Hanselmann
  """
80 7e8841bd Michael Hanselmann
  __slots__ = [
81 7e8841bd Michael Hanselmann
    "_allow_negative",
82 7e8841bd Michael Hanselmann
    "_start_time",
83 7e8841bd Michael Hanselmann
    "_time_fn",
84 7e8841bd Michael Hanselmann
    "_timeout",
85 7e8841bd Michael Hanselmann
    ]
86 7e8841bd Michael Hanselmann
87 7e8841bd Michael Hanselmann
  def __init__(self, timeout, allow_negative, _time_fn=time.time):
88 7e8841bd Michael Hanselmann
    """Initializes this class.
89 7e8841bd Michael Hanselmann

90 7e8841bd Michael Hanselmann
    @type timeout: float
91 7e8841bd Michael Hanselmann
    @param timeout: Timeout duration
92 7e8841bd Michael Hanselmann
    @type allow_negative: bool
93 7e8841bd Michael Hanselmann
    @param allow_negative: Whether to return values below zero
94 7e8841bd Michael Hanselmann
    @param _time_fn: Time function for unittests
95 7e8841bd Michael Hanselmann

96 7e8841bd Michael Hanselmann
    """
97 7e8841bd Michael Hanselmann
    object.__init__(self)
98 7e8841bd Michael Hanselmann
99 7e8841bd Michael Hanselmann
    if timeout is not None and timeout < 0.0:
100 7e8841bd Michael Hanselmann
      raise ValueError("Timeout must not be negative")
101 7e8841bd Michael Hanselmann
102 7e8841bd Michael Hanselmann
    self._timeout = timeout
103 7e8841bd Michael Hanselmann
    self._allow_negative = allow_negative
104 7e8841bd Michael Hanselmann
    self._time_fn = _time_fn
105 7e8841bd Michael Hanselmann
106 7e8841bd Michael Hanselmann
    self._start_time = None
107 7e8841bd Michael Hanselmann
108 7e8841bd Michael Hanselmann
  def Remaining(self):
109 7e8841bd Michael Hanselmann
    """Returns the remaining timeout.
110 7e8841bd Michael Hanselmann

111 7e8841bd Michael Hanselmann
    """
112 7e8841bd Michael Hanselmann
    if self._timeout is None:
113 7e8841bd Michael Hanselmann
      return None
114 7e8841bd Michael Hanselmann
115 7e8841bd Michael Hanselmann
    # Get start time on first calculation
116 7e8841bd Michael Hanselmann
    if self._start_time is None:
117 7e8841bd Michael Hanselmann
      self._start_time = self._time_fn()
118 7e8841bd Michael Hanselmann
119 7e8841bd Michael Hanselmann
    # Calculate remaining time
120 7e8841bd Michael Hanselmann
    remaining_timeout = self._start_time + self._timeout - self._time_fn()
121 7e8841bd Michael Hanselmann
122 7e8841bd Michael Hanselmann
    if not self._allow_negative:
123 7e8841bd Michael Hanselmann
      # Ensure timeout is always >= 0
124 7e8841bd Michael Hanselmann
      return max(0.0, remaining_timeout)
125 7e8841bd Michael Hanselmann
126 7e8841bd Michael Hanselmann
    return remaining_timeout
127 7e8841bd Michael Hanselmann
128 7e8841bd Michael Hanselmann
129 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
130 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
131 d76167a5 Michael Hanselmann

132 d76167a5 Michael Hanselmann
  """
133 d76167a5 Michael Hanselmann
  __slots__ = [
134 d76167a5 Michael Hanselmann
    "_fd",
135 d76167a5 Michael Hanselmann
    "_poller",
136 d76167a5 Michael Hanselmann
    ]
137 d76167a5 Michael Hanselmann
138 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
139 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
140 d76167a5 Michael Hanselmann

141 d76167a5 Michael Hanselmann
    @type poller: select.poll
142 d76167a5 Michael Hanselmann
    @param poller: Poller object
143 d76167a5 Michael Hanselmann
    @type fd: int
144 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
145 d76167a5 Michael Hanselmann

146 d76167a5 Michael Hanselmann
    """
147 d76167a5 Michael Hanselmann
    object.__init__(self)
148 d76167a5 Michael Hanselmann
    self._poller = poller
149 d76167a5 Michael Hanselmann
    self._fd = fd
150 d76167a5 Michael Hanselmann
151 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
152 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
153 d76167a5 Michael Hanselmann

154 d76167a5 Michael Hanselmann
    @type timeout: float or None
155 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
156 d76167a5 Michael Hanselmann

157 d76167a5 Michael Hanselmann
    """
158 f4e673fb Michael Hanselmann
    running_timeout = RunningTimeout(timeout, True)
159 f4e673fb Michael Hanselmann
160 f4e673fb Michael Hanselmann
    while True:
161 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
162 f4e673fb Michael Hanselmann
163 b44b0141 Michael Hanselmann
      if remaining_time is not None:
164 b44b0141 Michael Hanselmann
        if remaining_time < 0.0:
165 b44b0141 Michael Hanselmann
          break
166 d76167a5 Michael Hanselmann
167 413b7472 Michael Hanselmann
        # Our calculation uses seconds, poll() wants milliseconds
168 b44b0141 Michael Hanselmann
        remaining_time *= 1000
169 d76167a5 Michael Hanselmann
170 d76167a5 Michael Hanselmann
      try:
171 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
172 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
173 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
174 d76167a5 Michael Hanselmann
          raise
175 d76167a5 Michael Hanselmann
        result = None
176 d76167a5 Michael Hanselmann
177 d76167a5 Michael Hanselmann
      # Check whether we were notified
178 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
179 d76167a5 Michael Hanselmann
        break
180 d76167a5 Michael Hanselmann
181 d76167a5 Michael Hanselmann
182 2419060d Guido Trotter
class _BaseCondition(object):
183 2419060d Guido Trotter
  """Base class containing common code for conditions.
184 2419060d Guido Trotter

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

187 2419060d Guido Trotter
  """
188 2419060d Guido Trotter
  __slots__ = [
189 2419060d Guido Trotter
    "_lock",
190 2419060d Guido Trotter
    "acquire",
191 2419060d Guido Trotter
    "release",
192 7f890059 Guido Trotter
    "_is_owned",
193 7f890059 Guido Trotter
    "_acquire_restore",
194 7f890059 Guido Trotter
    "_release_save",
195 2419060d Guido Trotter
    ]
196 2419060d Guido Trotter
197 2419060d Guido Trotter
  def __init__(self, lock):
198 2419060d Guido Trotter
    """Constructor for _BaseCondition.
199 2419060d Guido Trotter

200 69b99987 Michael Hanselmann
    @type lock: threading.Lock
201 2419060d Guido Trotter
    @param lock: condition base lock
202 2419060d Guido Trotter

203 2419060d Guido Trotter
    """
204 2419060d Guido Trotter
    object.__init__(self)
205 2419060d Guido Trotter
206 7f890059 Guido Trotter
    try:
207 7f890059 Guido Trotter
      self._release_save = lock._release_save
208 7f890059 Guido Trotter
    except AttributeError:
209 7f890059 Guido Trotter
      self._release_save = self._base_release_save
210 7f890059 Guido Trotter
    try:
211 7f890059 Guido Trotter
      self._acquire_restore = lock._acquire_restore
212 7f890059 Guido Trotter
    except AttributeError:
213 7f890059 Guido Trotter
      self._acquire_restore = self._base_acquire_restore
214 7f890059 Guido Trotter
    try:
215 7f890059 Guido Trotter
      self._is_owned = lock._is_owned
216 7f890059 Guido Trotter
    except AttributeError:
217 7f890059 Guido Trotter
      self._is_owned = self._base_is_owned
218 2419060d Guido Trotter
219 2419060d Guido Trotter
    self._lock = lock
220 2419060d Guido Trotter
221 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
222 2419060d Guido Trotter
    self.acquire = lock.acquire
223 2419060d Guido Trotter
    self.release = lock.release
224 2419060d Guido Trotter
225 7f890059 Guido Trotter
  def _base_is_owned(self):
226 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
227 2419060d Guido Trotter

228 2419060d Guido Trotter
    """
229 2419060d Guido Trotter
    if self._lock.acquire(0):
230 2419060d Guido Trotter
      self._lock.release()
231 2419060d Guido Trotter
      return False
232 2419060d Guido Trotter
    return True
233 2419060d Guido Trotter
234 7f890059 Guido Trotter
  def _base_release_save(self):
235 7f890059 Guido Trotter
    self._lock.release()
236 7f890059 Guido Trotter
237 7f890059 Guido Trotter
  def _base_acquire_restore(self, _):
238 7f890059 Guido Trotter
    self._lock.acquire()
239 7f890059 Guido Trotter
240 2419060d Guido Trotter
  def _check_owned(self):
241 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
242 2419060d Guido Trotter

243 2419060d Guido Trotter
    """
244 2419060d Guido Trotter
    if not self._is_owned():
245 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
246 2419060d Guido Trotter
247 2419060d Guido Trotter
248 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
249 34cb5617 Guido Trotter
  """Condition which can only be notified once.
250 d76167a5 Michael Hanselmann

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

257 d76167a5 Michael Hanselmann
  """
258 34cb5617 Guido Trotter
259 154b9580 Balazs Lecz
  __slots__ = [
260 d76167a5 Michael Hanselmann
    "_poller",
261 d76167a5 Michael Hanselmann
    "_read_fd",
262 d76167a5 Michael Hanselmann
    "_write_fd",
263 d76167a5 Michael Hanselmann
    "_nwaiters",
264 34cb5617 Guido Trotter
    "_notified",
265 d76167a5 Michael Hanselmann
    ]
266 d76167a5 Michael Hanselmann
267 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
268 d76167a5 Michael Hanselmann
269 34cb5617 Guido Trotter
  def __init__(self, lock):
270 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
271 d76167a5 Michael Hanselmann

272 d76167a5 Michael Hanselmann
    """
273 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
274 d76167a5 Michael Hanselmann
    self._nwaiters = 0
275 34cb5617 Guido Trotter
    self._notified = False
276 34cb5617 Guido Trotter
    self._read_fd = None
277 34cb5617 Guido Trotter
    self._write_fd = None
278 34cb5617 Guido Trotter
    self._poller = None
279 d76167a5 Michael Hanselmann
280 34cb5617 Guido Trotter
  def _check_unnotified(self):
281 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
282 69b99987 Michael Hanselmann

283 69b99987 Michael Hanselmann
    """
284 34cb5617 Guido Trotter
    if self._notified:
285 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
286 d76167a5 Michael Hanselmann
287 34cb5617 Guido Trotter
  def _Cleanup(self):
288 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
289 d76167a5 Michael Hanselmann

290 d76167a5 Michael Hanselmann
    """
291 34cb5617 Guido Trotter
    if self._read_fd is not None:
292 34cb5617 Guido Trotter
      os.close(self._read_fd)
293 34cb5617 Guido Trotter
      self._read_fd = None
294 d76167a5 Michael Hanselmann
295 34cb5617 Guido Trotter
    if self._write_fd is not None:
296 34cb5617 Guido Trotter
      os.close(self._write_fd)
297 34cb5617 Guido Trotter
      self._write_fd = None
298 34cb5617 Guido Trotter
    self._poller = None
299 d76167a5 Michael Hanselmann
300 34cb5617 Guido Trotter
  def wait(self, timeout=None):
301 34cb5617 Guido Trotter
    """Wait for a notification.
302 d76167a5 Michael Hanselmann

303 34cb5617 Guido Trotter
    @type timeout: float or None
304 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
305 d76167a5 Michael Hanselmann

306 d76167a5 Michael Hanselmann
    """
307 34cb5617 Guido Trotter
    self._check_owned()
308 34cb5617 Guido Trotter
    self._check_unnotified()
309 d76167a5 Michael Hanselmann
310 34cb5617 Guido Trotter
    self._nwaiters += 1
311 34cb5617 Guido Trotter
    try:
312 34cb5617 Guido Trotter
      if self._poller is None:
313 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
314 34cb5617 Guido Trotter
        self._poller = select.poll()
315 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
316 d76167a5 Michael Hanselmann
317 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
318 7f890059 Guido Trotter
      state = self._release_save()
319 34cb5617 Guido Trotter
      try:
320 34cb5617 Guido Trotter
        # Wait for notification
321 34cb5617 Guido Trotter
        wait_fn(timeout)
322 34cb5617 Guido Trotter
      finally:
323 34cb5617 Guido Trotter
        # Re-acquire lock
324 7f890059 Guido Trotter
        self._acquire_restore(state)
325 34cb5617 Guido Trotter
    finally:
326 34cb5617 Guido Trotter
      self._nwaiters -= 1
327 34cb5617 Guido Trotter
      if self._nwaiters == 0:
328 34cb5617 Guido Trotter
        self._Cleanup()
329 d76167a5 Michael Hanselmann
330 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
331 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
332 d76167a5 Michael Hanselmann

333 d76167a5 Michael Hanselmann
    """
334 34cb5617 Guido Trotter
    self._check_owned()
335 34cb5617 Guido Trotter
    self._check_unnotified()
336 34cb5617 Guido Trotter
    self._notified = True
337 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
338 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
339 d76167a5 Michael Hanselmann
      self._write_fd = None
340 d76167a5 Michael Hanselmann
341 d76167a5 Michael Hanselmann
342 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
343 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
344 48dabc6a Michael Hanselmann

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

351 48dabc6a Michael Hanselmann
  """
352 154b9580 Balazs Lecz
  __slots__ = [
353 c31825f7 Michael Hanselmann
    "_waiters",
354 34cb5617 Guido Trotter
    "_single_condition",
355 48dabc6a Michael Hanselmann
    ]
356 48dabc6a Michael Hanselmann
357 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
358 48dabc6a Michael Hanselmann
359 48dabc6a Michael Hanselmann
  def __init__(self, lock):
360 48dabc6a Michael Hanselmann
    """Initializes this class.
361 48dabc6a Michael Hanselmann

362 48dabc6a Michael Hanselmann
    """
363 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
364 c31825f7 Michael Hanselmann
    self._waiters = set()
365 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
366 48dabc6a Michael Hanselmann
367 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
368 48dabc6a Michael Hanselmann
    """Wait for a notification.
369 48dabc6a Michael Hanselmann

370 48dabc6a Michael Hanselmann
    @type timeout: float or None
371 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
372 48dabc6a Michael Hanselmann

373 48dabc6a Michael Hanselmann
    """
374 48dabc6a Michael Hanselmann
    self._check_owned()
375 48dabc6a Michael Hanselmann
376 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
377 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
378 c31825f7 Michael Hanselmann
    cond = self._single_condition
379 48dabc6a Michael Hanselmann
380 c31825f7 Michael Hanselmann
    self._waiters.add(threading.currentThread())
381 48dabc6a Michael Hanselmann
    try:
382 c31825f7 Michael Hanselmann
      cond.wait(timeout)
383 48dabc6a Michael Hanselmann
    finally:
384 c31825f7 Michael Hanselmann
      self._check_owned()
385 c31825f7 Michael Hanselmann
      self._waiters.remove(threading.currentThread())
386 48dabc6a Michael Hanselmann
387 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
388 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
389 48dabc6a Michael Hanselmann

390 48dabc6a Michael Hanselmann
    """
391 48dabc6a Michael Hanselmann
    self._check_owned()
392 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
393 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
394 48dabc6a Michael Hanselmann
395 c31825f7 Michael Hanselmann
  def get_waiting(self):
396 c31825f7 Michael Hanselmann
    """Returns a list of all waiting threads.
397 c31825f7 Michael Hanselmann

398 c31825f7 Michael Hanselmann
    """
399 c31825f7 Michael Hanselmann
    self._check_owned()
400 c31825f7 Michael Hanselmann
401 c31825f7 Michael Hanselmann
    return self._waiters
402 c31825f7 Michael Hanselmann
403 48dabc6a Michael Hanselmann
  def has_waiting(self):
404 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
405 48dabc6a Michael Hanselmann

406 48dabc6a Michael Hanselmann
    """
407 48dabc6a Michael Hanselmann
    self._check_owned()
408 48dabc6a Michael Hanselmann
409 c31825f7 Michael Hanselmann
    return bool(self._waiters)
410 48dabc6a Michael Hanselmann
411 48dabc6a Michael Hanselmann
412 887c7aa6 Michael Hanselmann
class _PipeConditionWithMode(PipeCondition):
413 887c7aa6 Michael Hanselmann
  __slots__ = [
414 887c7aa6 Michael Hanselmann
    "shared",
415 887c7aa6 Michael Hanselmann
    ]
416 887c7aa6 Michael Hanselmann
417 887c7aa6 Michael Hanselmann
  def __init__(self, lock, shared):
418 887c7aa6 Michael Hanselmann
    """Initializes this class.
419 887c7aa6 Michael Hanselmann

420 887c7aa6 Michael Hanselmann
    """
421 887c7aa6 Michael Hanselmann
    self.shared = shared
422 887c7aa6 Michael Hanselmann
    PipeCondition.__init__(self, lock)
423 887c7aa6 Michael Hanselmann
424 887c7aa6 Michael Hanselmann
425 84e344d4 Michael Hanselmann
class SharedLock(object):
426 162c1c1f Guido Trotter
  """Implements a shared lock.
427 162c1c1f Guido Trotter

428 05ad571c Michael Hanselmann
  Multiple threads can acquire the lock in a shared way by calling
429 05ad571c Michael Hanselmann
  C{acquire(shared=1)}. In order to acquire the lock in an exclusive way
430 05ad571c Michael Hanselmann
  threads can call C{acquire(shared=0)}.
431 162c1c1f Guido Trotter

432 887c7aa6 Michael Hanselmann
  Notes on data structures: C{__pending} contains a priority queue (heapq) of
433 887c7aa6 Michael Hanselmann
  all pending acquires: C{[(priority1: prioqueue1), (priority2: prioqueue2),
434 887c7aa6 Michael Hanselmann
  ...]}. Each per-priority queue contains a normal in-order list of conditions
435 887c7aa6 Michael Hanselmann
  to be notified when the lock can be acquired. Shared locks are grouped
436 887c7aa6 Michael Hanselmann
  together by priority and the condition for them is stored in
437 887c7aa6 Michael Hanselmann
  C{__pending_shared} if it already exists. C{__pending_by_prio} keeps
438 887c7aa6 Michael Hanselmann
  references for the per-priority queues indexed by priority for faster access.
439 162c1c1f Guido Trotter

440 7f93570a Iustin Pop
  @type name: string
441 7f93570a Iustin Pop
  @ivar name: the name of the lock
442 7f93570a Iustin Pop

443 162c1c1f Guido Trotter
  """
444 84e344d4 Michael Hanselmann
  __slots__ = [
445 19b9ba9a Michael Hanselmann
    "__weakref__",
446 84e344d4 Michael Hanselmann
    "__deleted",
447 84e344d4 Michael Hanselmann
    "__exc",
448 84e344d4 Michael Hanselmann
    "__lock",
449 84e344d4 Michael Hanselmann
    "__pending",
450 887c7aa6 Michael Hanselmann
    "__pending_by_prio",
451 887c7aa6 Michael Hanselmann
    "__pending_shared",
452 84e344d4 Michael Hanselmann
    "__shr",
453 7f93570a Iustin Pop
    "name",
454 84e344d4 Michael Hanselmann
    ]
455 84e344d4 Michael Hanselmann
456 887c7aa6 Michael Hanselmann
  __condition_class = _PipeConditionWithMode
457 84e344d4 Michael Hanselmann
458 19b9ba9a Michael Hanselmann
  def __init__(self, name, monitor=None):
459 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
460 84e344d4 Michael Hanselmann

461 7f93570a Iustin Pop
    @param name: the name of the lock
462 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
463 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register
464 7f93570a Iustin Pop

465 84e344d4 Michael Hanselmann
    """
466 84e344d4 Michael Hanselmann
    object.__init__(self)
467 84e344d4 Michael Hanselmann
468 7f93570a Iustin Pop
    self.name = name
469 7f93570a Iustin Pop
470 84e344d4 Michael Hanselmann
    # Internal lock
471 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
472 162c1c1f Guido Trotter
473 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
474 84e344d4 Michael Hanselmann
    self.__pending = []
475 887c7aa6 Michael Hanselmann
    self.__pending_by_prio = {}
476 887c7aa6 Michael Hanselmann
    self.__pending_shared = {}
477 84e344d4 Michael Hanselmann
478 84e344d4 Michael Hanselmann
    # Current lock holders
479 162c1c1f Guido Trotter
    self.__shr = set()
480 162c1c1f Guido Trotter
    self.__exc = None
481 162c1c1f Guido Trotter
482 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
483 a95fd5d7 Guido Trotter
    self.__deleted = False
484 a95fd5d7 Guido Trotter
485 19b9ba9a Michael Hanselmann
    # Register with lock monitor
486 19b9ba9a Michael Hanselmann
    if monitor:
487 19b9ba9a Michael Hanselmann
      monitor.RegisterLock(self)
488 19b9ba9a Michael Hanselmann
489 19b9ba9a Michael Hanselmann
  def GetInfo(self, fields):
490 19b9ba9a Michael Hanselmann
    """Retrieves information for querying locks.
491 19b9ba9a Michael Hanselmann

492 19b9ba9a Michael Hanselmann
    @type fields: list of strings
493 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
494 19b9ba9a Michael Hanselmann

495 19b9ba9a Michael Hanselmann
    """
496 19b9ba9a Michael Hanselmann
    self.__lock.acquire()
497 19b9ba9a Michael Hanselmann
    try:
498 19b9ba9a Michael Hanselmann
      info = []
499 19b9ba9a Michael Hanselmann
500 19b9ba9a Michael Hanselmann
      # Note: to avoid unintentional race conditions, no references to
501 19b9ba9a Michael Hanselmann
      # modifiable objects should be returned unless they were created in this
502 19b9ba9a Michael Hanselmann
      # function.
503 19b9ba9a Michael Hanselmann
      for fname in fields:
504 19b9ba9a Michael Hanselmann
        if fname == "name":
505 19b9ba9a Michael Hanselmann
          info.append(self.name)
506 19b9ba9a Michael Hanselmann
        elif fname == "mode":
507 19b9ba9a Michael Hanselmann
          if self.__deleted:
508 19b9ba9a Michael Hanselmann
            info.append("deleted")
509 19b9ba9a Michael Hanselmann
            assert not (self.__exc or self.__shr)
510 19b9ba9a Michael Hanselmann
          elif self.__exc:
511 c31825f7 Michael Hanselmann
            info.append(_EXCLUSIVE_TEXT)
512 19b9ba9a Michael Hanselmann
          elif self.__shr:
513 c31825f7 Michael Hanselmann
            info.append(_SHARED_TEXT)
514 19b9ba9a Michael Hanselmann
          else:
515 19b9ba9a Michael Hanselmann
            info.append(None)
516 19b9ba9a Michael Hanselmann
        elif fname == "owner":
517 19b9ba9a Michael Hanselmann
          if self.__exc:
518 19b9ba9a Michael Hanselmann
            owner = [self.__exc]
519 19b9ba9a Michael Hanselmann
          else:
520 19b9ba9a Michael Hanselmann
            owner = self.__shr
521 19b9ba9a Michael Hanselmann
522 19b9ba9a Michael Hanselmann
          if owner:
523 19b9ba9a Michael Hanselmann
            assert not self.__deleted
524 19b9ba9a Michael Hanselmann
            info.append([i.getName() for i in owner])
525 19b9ba9a Michael Hanselmann
          else:
526 19b9ba9a Michael Hanselmann
            info.append(None)
527 c31825f7 Michael Hanselmann
        elif fname == "pending":
528 c31825f7 Michael Hanselmann
          data = []
529 c31825f7 Michael Hanselmann
530 887c7aa6 Michael Hanselmann
          # Sorting instead of copying and using heaq functions for simplicity
531 887c7aa6 Michael Hanselmann
          for (_, prioqueue) in sorted(self.__pending):
532 887c7aa6 Michael Hanselmann
            for cond in prioqueue:
533 887c7aa6 Michael Hanselmann
              if cond.shared:
534 887c7aa6 Michael Hanselmann
                mode = _SHARED_TEXT
535 887c7aa6 Michael Hanselmann
              else:
536 887c7aa6 Michael Hanselmann
                mode = _EXCLUSIVE_TEXT
537 c31825f7 Michael Hanselmann
538 887c7aa6 Michael Hanselmann
              # This function should be fast as it runs with the lock held.
539 887c7aa6 Michael Hanselmann
              # Hence not using utils.NiceSort.
540 887c7aa6 Michael Hanselmann
              data.append((mode, sorted(i.getName()
541 887c7aa6 Michael Hanselmann
                                        for i in cond.get_waiting())))
542 c31825f7 Michael Hanselmann
543 c31825f7 Michael Hanselmann
          info.append(data)
544 19b9ba9a Michael Hanselmann
        else:
545 19b9ba9a Michael Hanselmann
          raise errors.OpExecError("Invalid query field '%s'" % fname)
546 19b9ba9a Michael Hanselmann
547 19b9ba9a Michael Hanselmann
      return info
548 19b9ba9a Michael Hanselmann
    finally:
549 19b9ba9a Michael Hanselmann
      self.__lock.release()
550 19b9ba9a Michael Hanselmann
551 84e344d4 Michael Hanselmann
  def __check_deleted(self):
552 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
553 84e344d4 Michael Hanselmann

554 84e344d4 Michael Hanselmann
    """
555 84e344d4 Michael Hanselmann
    if self.__deleted:
556 7f93570a Iustin Pop
      raise errors.LockError("Deleted lock %s" % self.name)
557 84e344d4 Michael Hanselmann
558 162c1c1f Guido Trotter
  def __is_sharer(self):
559 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
560 84e344d4 Michael Hanselmann

561 84e344d4 Michael Hanselmann
    """
562 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
563 162c1c1f Guido Trotter
564 162c1c1f Guido Trotter
  def __is_exclusive(self):
565 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
566 84e344d4 Michael Hanselmann

567 84e344d4 Michael Hanselmann
    """
568 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
569 162c1c1f Guido Trotter
570 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
571 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
572 162c1c1f Guido Trotter

573 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
574 162c1c1f Guido Trotter
    the internal lock.
575 162c1c1f Guido Trotter

576 162c1c1f Guido Trotter
    """
577 162c1c1f Guido Trotter
    if shared < 0:
578 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
579 162c1c1f Guido Trotter
    elif shared:
580 162c1c1f Guido Trotter
      return self.__is_sharer()
581 162c1c1f Guido Trotter
    else:
582 162c1c1f Guido Trotter
      return self.__is_exclusive()
583 162c1c1f Guido Trotter
584 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
585 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
586 162c1c1f Guido Trotter

587 c41eea6e Iustin Pop
    @param shared:
588 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
589 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
590 c41eea6e Iustin Pop
        - > 0: check for shared ownership
591 162c1c1f Guido Trotter

592 162c1c1f Guido Trotter
    """
593 162c1c1f Guido Trotter
    self.__lock.acquire()
594 162c1c1f Guido Trotter
    try:
595 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
596 162c1c1f Guido Trotter
    finally:
597 162c1c1f Guido Trotter
      self.__lock.release()
598 162c1c1f Guido Trotter
599 84e344d4 Michael Hanselmann
  def _count_pending(self):
600 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
601 a95fd5d7 Guido Trotter

602 84e344d4 Michael Hanselmann
    @rtype: int
603 a95fd5d7 Guido Trotter

604 a95fd5d7 Guido Trotter
    """
605 84e344d4 Michael Hanselmann
    self.__lock.acquire()
606 84e344d4 Michael Hanselmann
    try:
607 887c7aa6 Michael Hanselmann
      return sum(len(prioqueue) for (_, prioqueue) in self.__pending)
608 887c7aa6 Michael Hanselmann
    finally:
609 887c7aa6 Michael Hanselmann
      self.__lock.release()
610 887c7aa6 Michael Hanselmann
611 887c7aa6 Michael Hanselmann
  def _check_empty(self):
612 887c7aa6 Michael Hanselmann
    """Checks whether there are any pending acquires.
613 887c7aa6 Michael Hanselmann

614 887c7aa6 Michael Hanselmann
    @rtype: bool
615 887c7aa6 Michael Hanselmann

616 887c7aa6 Michael Hanselmann
    """
617 887c7aa6 Michael Hanselmann
    self.__lock.acquire()
618 887c7aa6 Michael Hanselmann
    try:
619 887c7aa6 Michael Hanselmann
      # Order is important: __find_first_pending_queue modifies __pending
620 887c7aa6 Michael Hanselmann
      return not (self.__find_first_pending_queue() or
621 887c7aa6 Michael Hanselmann
                  self.__pending or
622 887c7aa6 Michael Hanselmann
                  self.__pending_by_prio or
623 887c7aa6 Michael Hanselmann
                  self.__pending_shared)
624 84e344d4 Michael Hanselmann
    finally:
625 84e344d4 Michael Hanselmann
      self.__lock.release()
626 a95fd5d7 Guido Trotter
627 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
628 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
629 84e344d4 Michael Hanselmann

630 84e344d4 Michael Hanselmann
    """
631 84e344d4 Michael Hanselmann
    if shared:
632 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
633 84e344d4 Michael Hanselmann
    else:
634 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
635 a95fd5d7 Guido Trotter
636 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
637 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
638 a95fd5d7 Guido Trotter

639 a95fd5d7 Guido Trotter
    """
640 84e344d4 Michael Hanselmann
    if shared:
641 84e344d4 Michael Hanselmann
      return self.__exc is None
642 84e344d4 Michael Hanselmann
    else:
643 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
644 a95fd5d7 Guido Trotter
645 887c7aa6 Michael Hanselmann
  def __find_first_pending_queue(self):
646 887c7aa6 Michael Hanselmann
    """Tries to find the topmost queued entry with pending acquires.
647 887c7aa6 Michael Hanselmann

648 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
649 887c7aa6 Michael Hanselmann

650 887c7aa6 Michael Hanselmann
    """
651 887c7aa6 Michael Hanselmann
    while self.__pending:
652 887c7aa6 Michael Hanselmann
      (priority, prioqueue) = self.__pending[0]
653 887c7aa6 Michael Hanselmann
654 887c7aa6 Michael Hanselmann
      if not prioqueue:
655 887c7aa6 Michael Hanselmann
        heapq.heappop(self.__pending)
656 887c7aa6 Michael Hanselmann
        del self.__pending_by_prio[priority]
657 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_shared
658 887c7aa6 Michael Hanselmann
        continue
659 887c7aa6 Michael Hanselmann
660 887c7aa6 Michael Hanselmann
      if prioqueue:
661 887c7aa6 Michael Hanselmann
        return prioqueue
662 887c7aa6 Michael Hanselmann
663 887c7aa6 Michael Hanselmann
    return None
664 887c7aa6 Michael Hanselmann
665 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
666 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
667 a95fd5d7 Guido Trotter

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

670 84e344d4 Michael Hanselmann
    """
671 887c7aa6 Michael Hanselmann
    return cond == self.__find_first_pending_queue()[0]
672 4d686df8 Guido Trotter
673 887c7aa6 Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout, priority):
674 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
675 9216a9f7 Michael Hanselmann

676 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
677 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
678 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
679 887c7aa6 Michael Hanselmann
    @type priority: integer
680 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
681 9216a9f7 Michael Hanselmann

682 9216a9f7 Michael Hanselmann
    """
683 84e344d4 Michael Hanselmann
    self.__check_deleted()
684 9216a9f7 Michael Hanselmann
685 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
686 7f93570a Iustin Pop
    assert not self.__is_owned(), ("double acquire() on a non-recursive lock"
687 7f93570a Iustin Pop
                                   " %s" % self.name)
688 84e344d4 Michael Hanselmann
689 887c7aa6 Michael Hanselmann
    # Remove empty entries from queue
690 887c7aa6 Michael Hanselmann
    self.__find_first_pending_queue()
691 887c7aa6 Michael Hanselmann
692 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
693 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
694 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
695 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
696 84e344d4 Michael Hanselmann
      return True
697 9216a9f7 Michael Hanselmann
698 887c7aa6 Michael Hanselmann
    prioqueue = self.__pending_by_prio.get(priority, None)
699 9216a9f7 Michael Hanselmann
700 887c7aa6 Michael Hanselmann
    if shared:
701 887c7aa6 Michael Hanselmann
      # Try to re-use condition for shared acquire
702 887c7aa6 Michael Hanselmann
      wait_condition = self.__pending_shared.get(priority, None)
703 887c7aa6 Michael Hanselmann
      assert (wait_condition is None or
704 887c7aa6 Michael Hanselmann
              (wait_condition.shared and wait_condition in prioqueue))
705 84e344d4 Michael Hanselmann
    else:
706 887c7aa6 Michael Hanselmann
      wait_condition = None
707 887c7aa6 Michael Hanselmann
708 887c7aa6 Michael Hanselmann
    if wait_condition is None:
709 887c7aa6 Michael Hanselmann
      if prioqueue is None:
710 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_by_prio
711 887c7aa6 Michael Hanselmann
712 887c7aa6 Michael Hanselmann
        prioqueue = []
713 887c7aa6 Michael Hanselmann
        heapq.heappush(self.__pending, (priority, prioqueue))
714 887c7aa6 Michael Hanselmann
        self.__pending_by_prio[priority] = prioqueue
715 887c7aa6 Michael Hanselmann
716 887c7aa6 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock, shared)
717 887c7aa6 Michael Hanselmann
      prioqueue.append(wait_condition)
718 887c7aa6 Michael Hanselmann
719 887c7aa6 Michael Hanselmann
      if shared:
720 887c7aa6 Michael Hanselmann
        # Keep reference for further shared acquires on same priority. This is
721 887c7aa6 Michael Hanselmann
        # better than trying to find it in the list of pending acquires.
722 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_shared
723 887c7aa6 Michael Hanselmann
        self.__pending_shared[priority] = wait_condition
724 84e344d4 Michael Hanselmann
725 84e344d4 Michael Hanselmann
    try:
726 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
727 84e344d4 Michael Hanselmann
      # expires.
728 887c7aa6 Michael Hanselmann
      # TODO: Decrease timeout with spurious notifications
729 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
730 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
731 84e344d4 Michael Hanselmann
        # Wait for notification
732 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
733 84e344d4 Michael Hanselmann
        self.__check_deleted()
734 84e344d4 Michael Hanselmann
735 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
736 84e344d4 Michael Hanselmann
        # internally for that case.
737 84e344d4 Michael Hanselmann
        if timeout is not None:
738 84e344d4 Michael Hanselmann
          break
739 84e344d4 Michael Hanselmann
740 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
741 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
742 84e344d4 Michael Hanselmann
        return True
743 9216a9f7 Michael Hanselmann
    finally:
744 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
745 887c7aa6 Michael Hanselmann
      if not wait_condition.has_waiting():
746 887c7aa6 Michael Hanselmann
        prioqueue.remove(wait_condition)
747 887c7aa6 Michael Hanselmann
        if wait_condition.shared:
748 887c7aa6 Michael Hanselmann
          del self.__pending_shared[priority]
749 9216a9f7 Michael Hanselmann
750 84e344d4 Michael Hanselmann
    return False
751 9216a9f7 Michael Hanselmann
752 7100c2fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, priority=None,
753 887c7aa6 Michael Hanselmann
              test_notify=None):
754 162c1c1f Guido Trotter
    """Acquire a shared lock.
755 162c1c1f Guido Trotter

756 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
757 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
758 c41eea6e Iustin Pop
        exclusive lock will be acquired
759 84e344d4 Michael Hanselmann
    @type timeout: float
760 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
761 887c7aa6 Michael Hanselmann
    @type priority: integer
762 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
763 008b92fa Michael Hanselmann
    @type test_notify: callable or None
764 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
765 162c1c1f Guido Trotter

766 162c1c1f Guido Trotter
    """
767 7100c2fa Michael Hanselmann
    if priority is None:
768 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
769 7100c2fa Michael Hanselmann
770 162c1c1f Guido Trotter
    self.__lock.acquire()
771 162c1c1f Guido Trotter
    try:
772 008b92fa Michael Hanselmann
      # We already got the lock, notify now
773 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
774 008b92fa Michael Hanselmann
        test_notify()
775 008b92fa Michael Hanselmann
776 887c7aa6 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout, priority)
777 162c1c1f Guido Trotter
    finally:
778 162c1c1f Guido Trotter
      self.__lock.release()
779 162c1c1f Guido Trotter
780 162c1c1f Guido Trotter
  def release(self):
781 162c1c1f Guido Trotter
    """Release a Shared Lock.
782 162c1c1f Guido Trotter

783 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
784 162c1c1f Guido Trotter
    before calling this function.
785 162c1c1f Guido Trotter

786 162c1c1f Guido Trotter
    """
787 162c1c1f Guido Trotter
    self.__lock.acquire()
788 162c1c1f Guido Trotter
    try:
789 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
790 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
791 84e344d4 Michael Hanselmann
792 162c1c1f Guido Trotter
      # Autodetect release type
793 162c1c1f Guido Trotter
      if self.__is_exclusive():
794 162c1c1f Guido Trotter
        self.__exc = None
795 84e344d4 Michael Hanselmann
      else:
796 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
797 162c1c1f Guido Trotter
798 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
799 887c7aa6 Michael Hanselmann
      prioqueue = self.__find_first_pending_queue()
800 887c7aa6 Michael Hanselmann
      if prioqueue:
801 887c7aa6 Michael Hanselmann
        prioqueue[0].notifyAll()
802 162c1c1f Guido Trotter
803 162c1c1f Guido Trotter
    finally:
804 162c1c1f Guido Trotter
      self.__lock.release()
805 162c1c1f Guido Trotter
806 7100c2fa Michael Hanselmann
  def delete(self, timeout=None, priority=None):
807 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
808 a95fd5d7 Guido Trotter

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

813 84e344d4 Michael Hanselmann
    @type timeout: float
814 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
815 887c7aa6 Michael Hanselmann
    @type priority: integer
816 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
817 a95fd5d7 Guido Trotter

818 a95fd5d7 Guido Trotter
    """
819 7100c2fa Michael Hanselmann
    if priority is None:
820 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
821 7100c2fa Michael Hanselmann
822 a95fd5d7 Guido Trotter
    self.__lock.acquire()
823 a95fd5d7 Guido Trotter
    try:
824 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
825 84e344d4 Michael Hanselmann
826 84e344d4 Michael Hanselmann
      self.__check_deleted()
827 a95fd5d7 Guido Trotter
828 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
829 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
830 a95fd5d7 Guido Trotter
831 84e344d4 Michael Hanselmann
      if not acquired:
832 887c7aa6 Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout, priority)
833 a66bd91b Michael Hanselmann
834 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
835 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
836 84e344d4 Michael Hanselmann
837 84e344d4 Michael Hanselmann
      if acquired:
838 84e344d4 Michael Hanselmann
        self.__deleted = True
839 84e344d4 Michael Hanselmann
        self.__exc = None
840 a95fd5d7 Guido Trotter
841 19b9ba9a Michael Hanselmann
        assert not (self.__exc or self.__shr), "Found owner during deletion"
842 19b9ba9a Michael Hanselmann
843 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
844 887c7aa6 Michael Hanselmann
        for (_, prioqueue) in self.__pending:
845 887c7aa6 Michael Hanselmann
          for cond in prioqueue:
846 887c7aa6 Michael Hanselmann
            cond.notifyAll()
847 887c7aa6 Michael Hanselmann
848 887c7aa6 Michael Hanselmann
        assert self.__deleted
849 a95fd5d7 Guido Trotter
850 84e344d4 Michael Hanselmann
      return acquired
851 a95fd5d7 Guido Trotter
    finally:
852 a95fd5d7 Guido Trotter
      self.__lock.release()
853 a95fd5d7 Guido Trotter
854 1a4e32d0 Guido Trotter
  def _release_save(self):
855 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
856 1a4e32d0 Guido Trotter
    self.release()
857 1a4e32d0 Guido Trotter
    return shared
858 1a4e32d0 Guido Trotter
859 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
860 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
861 1a4e32d0 Guido Trotter
862 aaae9bc0 Guido Trotter
863 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
864 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
865 e310b019 Guido Trotter
ALL_SET = None
866 e310b019 Guido Trotter
867 e310b019 Guido Trotter
868 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
869 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
870 5aab242c Michael Hanselmann

871 5aab242c Michael Hanselmann
  """
872 5aab242c Michael Hanselmann
873 5aab242c Michael Hanselmann
874 aaae9bc0 Guido Trotter
class LockSet:
875 aaae9bc0 Guido Trotter
  """Implements a set of locks.
876 aaae9bc0 Guido Trotter

877 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
878 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
879 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
880 aaae9bc0 Guido Trotter
  preventing deadlock.
881 aaae9bc0 Guido Trotter

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

884 7f93570a Iustin Pop
  @type name: string
885 7f93570a Iustin Pop
  @ivar name: the name of the lockset
886 7f93570a Iustin Pop

887 aaae9bc0 Guido Trotter
  """
888 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
889 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
890 aaae9bc0 Guido Trotter

891 ec44d893 Guido Trotter
    @type members: list of strings
892 c41eea6e Iustin Pop
    @param members: initial members of the set
893 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
894 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
895 aaae9bc0 Guido Trotter

896 aaae9bc0 Guido Trotter
    """
897 7f93570a Iustin Pop
    assert members is not None, "members parameter is not a list"
898 7f93570a Iustin Pop
    self.name = name
899 7f93570a Iustin Pop
900 19b9ba9a Michael Hanselmann
    # Lock monitor
901 19b9ba9a Michael Hanselmann
    self.__monitor = monitor
902 19b9ba9a Michael Hanselmann
903 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
904 7f93570a Iustin Pop
    self.__lock = SharedLock(name)
905 aaae9bc0 Guido Trotter
906 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
907 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
908 aaae9bc0 Guido Trotter
    self.__lockdict = {}
909 aaae9bc0 Guido Trotter
910 7f93570a Iustin Pop
    for mname in members:
911 19b9ba9a Michael Hanselmann
      self.__lockdict[mname] = SharedLock(self._GetLockName(mname),
912 19b9ba9a Michael Hanselmann
                                          monitor=monitor)
913 aaae9bc0 Guido Trotter
914 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
915 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
916 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
917 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
918 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
919 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
920 aaae9bc0 Guido Trotter
    # will be trouble.
921 aaae9bc0 Guido Trotter
    self.__owners = {}
922 aaae9bc0 Guido Trotter
923 4fb780d1 Michael Hanselmann
  def _GetLockName(self, mname):
924 4fb780d1 Michael Hanselmann
    """Returns the name for a member lock.
925 4fb780d1 Michael Hanselmann

926 4fb780d1 Michael Hanselmann
    """
927 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
928 4fb780d1 Michael Hanselmann
929 aaae9bc0 Guido Trotter
  def _is_owned(self):
930 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
931 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
932 aaae9bc0 Guido Trotter
933 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
934 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
935 b2dabfd6 Guido Trotter
    if name is None:
936 b2dabfd6 Guido Trotter
      if not self._is_owned():
937 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
938 aaae9bc0 Guido Trotter
    else:
939 b2dabfd6 Guido Trotter
      if self._is_owned():
940 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
941 b2dabfd6 Guido Trotter
      else:
942 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
943 b2dabfd6 Guido Trotter
944 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
945 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
946 aaae9bc0 Guido Trotter
947 e4335b5b Michael Hanselmann
    assert not (name is None and self.__lock._is_owned()), \
948 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
949 e4335b5b Michael Hanselmann
950 b2dabfd6 Guido Trotter
    if name is not None:
951 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
952 b2dabfd6 Guido Trotter
953 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
954 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
955 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
956 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
957 aaae9bc0 Guido Trotter
958 aaae9bc0 Guido Trotter
  def _list_owned(self):
959 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
960 aaae9bc0 Guido Trotter
    if self._is_owned():
961 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
962 aaae9bc0 Guido Trotter
    else:
963 aaae9bc0 Guido Trotter
      return set()
964 aaae9bc0 Guido Trotter
965 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
966 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
967 5aab242c Michael Hanselmann
    for lname in self._list_owned():
968 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
969 56452af7 Michael Hanselmann
      if lock._is_owned():
970 56452af7 Michael Hanselmann
        lock.release()
971 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
972 5aab242c Michael Hanselmann
973 aaae9bc0 Guido Trotter
  def __names(self):
974 aaae9bc0 Guido Trotter
    """Return the current set of names.
975 aaae9bc0 Guido Trotter

976 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
977 aaae9bc0 Guido Trotter
    result after releasing the lock.
978 aaae9bc0 Guido Trotter

979 aaae9bc0 Guido Trotter
    """
980 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
981 aaae9bc0 Guido Trotter
982 aaae9bc0 Guido Trotter
  def _names(self):
983 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
984 aaae9bc0 Guido Trotter

985 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
986 cdb08f44 Michael Hanselmann

987 aaae9bc0 Guido Trotter
    """
988 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
989 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
990 d4803c24 Guido Trotter
    release_lock = False
991 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
992 d4803c24 Guido Trotter
      release_lock = True
993 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
994 aaae9bc0 Guido Trotter
    try:
995 aaae9bc0 Guido Trotter
      result = self.__names()
996 aaae9bc0 Guido Trotter
    finally:
997 d4803c24 Guido Trotter
      if release_lock:
998 d4803c24 Guido Trotter
        self.__lock.release()
999 0cf257c5 Guido Trotter
    return set(result)
1000 aaae9bc0 Guido Trotter
1001 7100c2fa Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, priority=None,
1002 887c7aa6 Michael Hanselmann
              test_notify=None):
1003 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
1004 aaae9bc0 Guido Trotter

1005 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1006 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1007 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1008 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1009 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
1010 c41eea6e Iustin Pop
        exclusive lock will be acquired
1011 5aab242c Michael Hanselmann
    @type timeout: float or None
1012 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1013 887c7aa6 Michael Hanselmann
    @type priority: integer
1014 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1015 5aab242c Michael Hanselmann
    @type test_notify: callable or None
1016 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1017 aaae9bc0 Guido Trotter

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

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

1024 aaae9bc0 Guido Trotter
    """
1025 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
1026 aaae9bc0 Guido Trotter
1027 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
1028 7f93570a Iustin Pop
    assert not self._is_owned(), ("Cannot acquire locks in the same set twice"
1029 7f93570a Iustin Pop
                                  " (lockset %s)" % self.name)
1030 aaae9bc0 Guido Trotter
1031 7100c2fa Michael Hanselmann
    if priority is None:
1032 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
1033 7100c2fa Michael Hanselmann
1034 5aab242c Michael Hanselmann
    # We need to keep track of how long we spent waiting for a lock. The
1035 5aab242c Michael Hanselmann
    # timeout passed to this function is over all lock acquires.
1036 7e8841bd Michael Hanselmann
    running_timeout = RunningTimeout(timeout, False)
1037 5aab242c Michael Hanselmann
1038 806e20fd Guido Trotter
    try:
1039 76e2f08a Michael Hanselmann
      if names is not None:
1040 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
1041 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
1042 5aab242c Michael Hanselmann
          names = [names]
1043 5aab242c Michael Hanselmann
1044 887c7aa6 Michael Hanselmann
        return self.__acquire_inner(names, False, shared, priority,
1045 7e8841bd Michael Hanselmann
                                    running_timeout.Remaining, test_notify)
1046 76e2f08a Michael Hanselmann
1047 76e2f08a Michael Hanselmann
      else:
1048 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
1049 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
1050 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
1051 76e2f08a Michael Hanselmann
        #
1052 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
1053 887c7aa6 Michael Hanselmann
        # everybody else can use the instances at the same time. If we are
1054 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
1055 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
1056 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
1057 887c7aa6 Michael Hanselmann
        if not self.__lock.acquire(shared=shared, priority=priority,
1058 7e8841bd Michael Hanselmann
                                   timeout=running_timeout.Remaining()):
1059 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1060 76e2f08a Michael Hanselmann
        try:
1061 76e2f08a Michael Hanselmann
          # note we own the set-lock
1062 76e2f08a Michael Hanselmann
          self._add_owned()
1063 76e2f08a Michael Hanselmann
1064 887c7aa6 Michael Hanselmann
          return self.__acquire_inner(self.__names(), True, shared, priority,
1065 7e8841bd Michael Hanselmann
                                      running_timeout.Remaining, test_notify)
1066 76e2f08a Michael Hanselmann
        except:
1067 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1068 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1069 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
1070 5aab242c Michael Hanselmann
          self.__lock.release()
1071 76e2f08a Michael Hanselmann
          self._del_owned()
1072 76e2f08a Michael Hanselmann
          raise
1073 5aab242c Michael Hanselmann
1074 5aab242c Michael Hanselmann
    except _AcquireTimeout:
1075 5aab242c Michael Hanselmann
      return None
1076 aaae9bc0 Guido Trotter
1077 887c7aa6 Michael Hanselmann
  def __acquire_inner(self, names, want_all, shared, priority,
1078 887c7aa6 Michael Hanselmann
                      timeout_fn, test_notify):
1079 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
1080 7e8841bd Michael Hanselmann

1081 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
1082 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
1083 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
1084 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
1085 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1086 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1087 76e2f08a Michael Hanselmann

1088 76e2f08a Michael Hanselmann
    """
1089 76e2f08a Michael Hanselmann
    acquire_list = []
1090 76e2f08a Michael Hanselmann
1091 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
1092 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
1093 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
1094 71e1863e Michael Hanselmann
    # deadlocks.
1095 71e1863e Michael Hanselmann
    for lname in sorted(utils.UniqueSequence(names)):
1096 76e2f08a Michael Hanselmann
      try:
1097 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
1098 76e2f08a Michael Hanselmann
      except KeyError:
1099 76e2f08a Michael Hanselmann
        if want_all:
1100 76e2f08a Michael Hanselmann
          # We are acquiring all the set, it doesn't matter if this particular
1101 76e2f08a Michael Hanselmann
          # element is not there anymore.
1102 76e2f08a Michael Hanselmann
          continue
1103 76e2f08a Michael Hanselmann
1104 7f93570a Iustin Pop
        raise errors.LockError("Non-existing lock %s in set %s" %
1105 7f93570a Iustin Pop
                               (lname, self.name))
1106 76e2f08a Michael Hanselmann
1107 9b154270 Michael Hanselmann
      acquire_list.append((lname, lock))
1108 9b154270 Michael Hanselmann
1109 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
1110 76e2f08a Michael Hanselmann
    acquired = set()
1111 76e2f08a Michael Hanselmann
1112 76e2f08a Michael Hanselmann
    try:
1113 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
1114 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
1115 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
1116 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
1117 76e2f08a Michael Hanselmann
      # lock gets deleted.
1118 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
1119 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
1120 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
1121 76e2f08a Michael Hanselmann
        else:
1122 76e2f08a Michael Hanselmann
          test_notify_fn = None
1123 76e2f08a Michael Hanselmann
1124 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
1125 76e2f08a Michael Hanselmann
1126 76e2f08a Michael Hanselmann
        try:
1127 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
1128 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
1129 887c7aa6 Michael Hanselmann
                                     priority=priority,
1130 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
1131 76e2f08a Michael Hanselmann
        except errors.LockError:
1132 76e2f08a Michael Hanselmann
          if want_all:
1133 76e2f08a Michael Hanselmann
            # We are acquiring all the set, it doesn't matter if this
1134 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
1135 76e2f08a Michael Hanselmann
            continue
1136 76e2f08a Michael Hanselmann
1137 7f93570a Iustin Pop
          raise errors.LockError("Non-existing lock %s in set %s" %
1138 7f93570a Iustin Pop
                                 (lname, self.name))
1139 76e2f08a Michael Hanselmann
1140 76e2f08a Michael Hanselmann
        if not acq_success:
1141 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
1142 76e2f08a Michael Hanselmann
          if timeout is None:
1143 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
1144 76e2f08a Michael Hanselmann
            # blocking.
1145 7f93570a Iustin Pop
            raise errors.LockError("Failed to get lock %s (set %s)" %
1146 7f93570a Iustin Pop
                                   (lname, self.name))
1147 76e2f08a Michael Hanselmann
1148 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1149 76e2f08a Michael Hanselmann
1150 76e2f08a Michael Hanselmann
        try:
1151 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
1152 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
1153 76e2f08a Michael Hanselmann
          acquired.add(lname)
1154 76e2f08a Michael Hanselmann
1155 76e2f08a Michael Hanselmann
        except:
1156 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1157 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1158 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
1159 76e2f08a Michael Hanselmann
          if lock._is_owned():
1160 76e2f08a Michael Hanselmann
            lock.release()
1161 76e2f08a Michael Hanselmann
          raise
1162 76e2f08a Michael Hanselmann
1163 76e2f08a Michael Hanselmann
    except:
1164 76e2f08a Michael Hanselmann
      # Release all owned locks
1165 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
1166 76e2f08a Michael Hanselmann
      raise
1167 76e2f08a Michael Hanselmann
1168 0cc00929 Guido Trotter
    return acquired
1169 aaae9bc0 Guido Trotter
1170 aaae9bc0 Guido Trotter
  def release(self, names=None):
1171 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
1172 aaae9bc0 Guido Trotter

1173 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1174 aaae9bc0 Guido Trotter
    before releasing them.
1175 aaae9bc0 Guido Trotter

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

1180 aaae9bc0 Guido Trotter
    """
1181 7f93570a Iustin Pop
    assert self._is_owned(), ("release() on lock set %s while not owner" %
1182 7f93570a Iustin Pop
                              self.name)
1183 aaae9bc0 Guido Trotter
1184 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1185 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1186 aaae9bc0 Guido Trotter
      names = [names]
1187 aaae9bc0 Guido Trotter
1188 aaae9bc0 Guido Trotter
    if names is None:
1189 aaae9bc0 Guido Trotter
      names = self._list_owned()
1190 aaae9bc0 Guido Trotter
    else:
1191 aaae9bc0 Guido Trotter
      names = set(names)
1192 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
1193 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1194 7f93570a Iustin Pop
               (names.difference(self._list_owned()), self.name))
1195 aaae9bc0 Guido Trotter
1196 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1197 3b7ed473 Guido Trotter
    # After this 'add' can work again
1198 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
1199 3b7ed473 Guido Trotter
      self.__lock.release()
1200 b2dabfd6 Guido Trotter
      self._del_owned()
1201 3b7ed473 Guido Trotter
1202 aaae9bc0 Guido Trotter
    for lockname in names:
1203 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1204 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1205 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1206 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1207 aaae9bc0 Guido Trotter
1208 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1209 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1210 aaae9bc0 Guido Trotter

1211 ec44d893 Guido Trotter
    @type names: list of strings
1212 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1213 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1214 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1215 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1216 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1217 aaae9bc0 Guido Trotter

1218 aaae9bc0 Guido Trotter
    """
1219 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1220 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
1221 7f93570a Iustin Pop
      ("Cannot add locks if the set %s is only partially owned, or shared" %
1222 7f93570a Iustin Pop
       self.name)
1223 3b7ed473 Guido Trotter
1224 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1225 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1226 aaae9bc0 Guido Trotter
      names = [names]
1227 aaae9bc0 Guido Trotter
1228 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1229 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1230 3b7ed473 Guido Trotter
    release_lock = False
1231 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
1232 3b7ed473 Guido Trotter
      release_lock = True
1233 3b7ed473 Guido Trotter
      self.__lock.acquire()
1234 3b7ed473 Guido Trotter
1235 aaae9bc0 Guido Trotter
    try:
1236 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1237 aaae9bc0 Guido Trotter
      if invalid_names:
1238 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1239 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1240 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1241 7f93570a Iustin Pop
        raise errors.LockError("duplicate add(%s) on lockset %s" %
1242 7f93570a Iustin Pop
                               (invalid_names, self.name))
1243 aaae9bc0 Guido Trotter
1244 aaae9bc0 Guido Trotter
      for lockname in names:
1245 19b9ba9a Michael Hanselmann
        lock = SharedLock(self._GetLockName(lockname), monitor=self.__monitor)
1246 aaae9bc0 Guido Trotter
1247 aaae9bc0 Guido Trotter
        if acquired:
1248 887c7aa6 Michael Hanselmann
          # No need for priority or timeout here as this lock has just been
1249 887c7aa6 Michael Hanselmann
          # created
1250 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1251 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1252 aaae9bc0 Guido Trotter
          try:
1253 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1254 aaae9bc0 Guido Trotter
          except:
1255 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1256 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1257 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1258 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1259 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1260 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1261 aaae9bc0 Guido Trotter
            lock.release()
1262 aaae9bc0 Guido Trotter
            raise
1263 aaae9bc0 Guido Trotter
1264 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1265 aaae9bc0 Guido Trotter
1266 aaae9bc0 Guido Trotter
    finally:
1267 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1268 3b7ed473 Guido Trotter
      if release_lock:
1269 3b7ed473 Guido Trotter
        self.__lock.release()
1270 aaae9bc0 Guido Trotter
1271 aaae9bc0 Guido Trotter
    return True
1272 aaae9bc0 Guido Trotter
1273 5e0a6daf Michael Hanselmann
  def remove(self, names):
1274 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1275 aaae9bc0 Guido Trotter

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

1279 ec44d893 Guido Trotter
    @type names: list of strings
1280 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1281 aaae9bc0 Guido Trotter

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

1286 aaae9bc0 Guido Trotter
    """
1287 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1288 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1289 aaae9bc0 Guido Trotter
      names = [names]
1290 aaae9bc0 Guido Trotter
1291 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1292 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1293 aaae9bc0 Guido Trotter
    # by the lock itself.
1294 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
1295 7f93570a Iustin Pop
      "remove() on acquired lockset %s while not owning all elements" %
1296 7f93570a Iustin Pop
      self.name)
1297 aaae9bc0 Guido Trotter
1298 3f404fc5 Guido Trotter
    removed = []
1299 aaae9bc0 Guido Trotter
1300 aaae9bc0 Guido Trotter
    for lname in names:
1301 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1302 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1303 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1304 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1305 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1306 aaae9bc0 Guido Trotter
      try:
1307 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1308 3f404fc5 Guido Trotter
        removed.append(lname)
1309 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1310 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1311 7f93570a Iustin Pop
        assert not self._is_owned(), ("remove failed while holding lockset %s"
1312 7f93570a Iustin Pop
                                      % self.name)
1313 aaae9bc0 Guido Trotter
      else:
1314 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1315 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1316 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1317 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1318 aaae9bc0 Guido Trotter
        #
1319 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1320 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1321 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1322 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1323 aaae9bc0 Guido Trotter
        if self._is_owned():
1324 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1325 aaae9bc0 Guido Trotter
1326 3f404fc5 Guido Trotter
    return removed
1327 aaae9bc0 Guido Trotter
1328 7ee7c0c7 Guido Trotter
1329 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1330 7ee7c0c7 Guido Trotter
# Current rules are:
1331 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1332 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1333 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1334 7ee7c0c7 Guido Trotter
#   avoided.
1335 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1336 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1337 7ee7c0c7 Guido Trotter
#   the same time.
1338 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1339 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1340 04e1bfaf Guido Trotter
LEVEL_NODE = 2
1341 7ee7c0c7 Guido Trotter
1342 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1343 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1344 04e1bfaf Guido Trotter
          LEVEL_NODE]
1345 7ee7c0c7 Guido Trotter
1346 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1347 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
1348 7ee7c0c7 Guido Trotter
1349 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1350 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1351 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1352 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1353 ea205dbc Michael Hanselmann
  }
1354 ea205dbc Michael Hanselmann
1355 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1356 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1357 7ee7c0c7 Guido Trotter
1358 7ee7c0c7 Guido Trotter
1359 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1360 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1361 7ee7c0c7 Guido Trotter

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

1367 7ee7c0c7 Guido Trotter
  """
1368 7ee7c0c7 Guido Trotter
  _instance = None
1369 7ee7c0c7 Guido Trotter
1370 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1371 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1372 7ee7c0c7 Guido Trotter

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

1376 c41eea6e Iustin Pop
    @param nodes: list of node names
1377 c41eea6e Iustin Pop
    @param instances: list of instance names
1378 7ee7c0c7 Guido Trotter

1379 7ee7c0c7 Guido Trotter
    """
1380 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1381 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1382 c41eea6e Iustin Pop
1383 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1384 7ee7c0c7 Guido Trotter
1385 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1386 19b9ba9a Michael Hanselmann
1387 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1388 7ee7c0c7 Guido Trotter
    # locking order.
1389 7ee7c0c7 Guido Trotter
    self.__keyring = {
1390 19b9ba9a Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "BGL", monitor=self._monitor),
1391 19b9ba9a Michael Hanselmann
      LEVEL_NODE: LockSet(nodes, "nodes", monitor=self._monitor),
1392 19b9ba9a Michael Hanselmann
      LEVEL_INSTANCE: LockSet(instances, "instances",
1393 19b9ba9a Michael Hanselmann
                              monitor=self._monitor),
1394 19b9ba9a Michael Hanselmann
      }
1395 19b9ba9a Michael Hanselmann
1396 19b9ba9a Michael Hanselmann
  def QueryLocks(self, fields, sync):
1397 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1398 19b9ba9a Michael Hanselmann

1399 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1400 19b9ba9a Michael Hanselmann

1401 19b9ba9a Michael Hanselmann
    """
1402 19b9ba9a Michael Hanselmann
    return self._monitor.QueryLocks(fields, sync)
1403 7ee7c0c7 Guido Trotter
1404 7ee7c0c7 Guido Trotter
  def _names(self, level):
1405 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1406 7ee7c0c7 Guido Trotter

1407 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1408 c41eea6e Iustin Pop

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

1411 7ee7c0c7 Guido Trotter
    """
1412 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1413 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1414 7ee7c0c7 Guido Trotter
1415 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1416 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1417 7ee7c0c7 Guido Trotter

1418 7ee7c0c7 Guido Trotter
    """
1419 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1420 7ee7c0c7 Guido Trotter
1421 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1422 d4f4b3e7 Guido Trotter
1423 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1424 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1425 7ee7c0c7 Guido Trotter

1426 7ee7c0c7 Guido Trotter
    """
1427 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1428 7ee7c0c7 Guido Trotter
1429 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1430 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1431 7ee7c0c7 Guido Trotter

1432 7ee7c0c7 Guido Trotter
    """
1433 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1434 7ee7c0c7 Guido Trotter
    # the test cases.
1435 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1436 7ee7c0c7 Guido Trotter
1437 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1438 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1439 7ee7c0c7 Guido Trotter

1440 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1441 7ee7c0c7 Guido Trotter

1442 7ee7c0c7 Guido Trotter
    """
1443 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1444 7ee7c0c7 Guido Trotter
1445 c70d2d9b Iustin Pop
  @staticmethod
1446 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1447 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1448 c41eea6e Iustin Pop

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

1452 7ee7c0c7 Guido Trotter
    """
1453 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1454 7ee7c0c7 Guido Trotter
1455 b30d95b6 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None):
1456 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1457 7ee7c0c7 Guido Trotter

1458 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1459 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1460 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1461 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1462 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1463 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1464 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1465 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1466 5e0a6daf Michael Hanselmann
    @type timeout: float
1467 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1468 b30d95b6 Michael Hanselmann
    @type priority: integer
1469 b30d95b6 Michael Hanselmann
    @param priority: Priority for acquiring lock
1470 7ee7c0c7 Guido Trotter

1471 7ee7c0c7 Guido Trotter
    """
1472 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1473 7ee7c0c7 Guido Trotter
1474 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1475 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1476 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1477 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1478 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1479 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1480 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1481 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1482 7ee7c0c7 Guido Trotter
1483 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1484 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1485 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1486 7ee7c0c7 Guido Trotter
1487 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1488 b30d95b6 Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout,
1489 b30d95b6 Michael Hanselmann
                                         priority=priority)
1490 7ee7c0c7 Guido Trotter
1491 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1492 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1493 7ee7c0c7 Guido Trotter

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

1497 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1498 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1499 ec44d893 Guido Trotter
    @type names: list of strings, or None
1500 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1501 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1502 7ee7c0c7 Guido Trotter

1503 7ee7c0c7 Guido Trotter
    """
1504 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1505 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1506 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1507 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1508 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1509 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1510 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1511 7ee7c0c7 Guido Trotter
1512 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1513 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1514 7ee7c0c7 Guido Trotter
1515 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1516 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1517 7ee7c0c7 Guido Trotter

1518 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1519 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1520 ec44d893 Guido Trotter
    @type names: list of strings
1521 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1522 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1523 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1524 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1525 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1526 c41eea6e Iustin Pop

1527 7ee7c0c7 Guido Trotter
    """
1528 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1529 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1530 7ee7c0c7 Guido Trotter
           " operations")
1531 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1532 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1533 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1534 7ee7c0c7 Guido Trotter
1535 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1536 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1537 7ee7c0c7 Guido Trotter

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

1541 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1542 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1543 ec44d893 Guido Trotter
    @type names: list of strings
1544 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1545 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1546 7ee7c0c7 Guido Trotter

1547 7ee7c0c7 Guido Trotter
    """
1548 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1549 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1550 7ee7c0c7 Guido Trotter
           " operations")
1551 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1552 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1553 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1554 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1555 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1556 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1557 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1558 19b9ba9a Michael Hanselmann
1559 19b9ba9a Michael Hanselmann
1560 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1561 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1562 19b9ba9a Michael Hanselmann
1563 19b9ba9a Michael Hanselmann
  def __init__(self):
1564 19b9ba9a Michael Hanselmann
    """Initializes this class.
1565 19b9ba9a Michael Hanselmann

1566 19b9ba9a Michael Hanselmann
    """
1567 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1568 19b9ba9a Michael Hanselmann
1569 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1570 19b9ba9a Michael Hanselmann
    # references and deletion.
1571 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1572 19b9ba9a Michael Hanselmann
1573 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1574 19b9ba9a Michael Hanselmann
  def RegisterLock(self, lock):
1575 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1576 19b9ba9a Michael Hanselmann

1577 19b9ba9a Michael Hanselmann
    """
1578 19b9ba9a Michael Hanselmann
    logging.debug("Registering lock %s", lock.name)
1579 19b9ba9a Michael Hanselmann
    assert lock not in self._locks, "Duplicate lock registration"
1580 19b9ba9a Michael Hanselmann
    assert not compat.any(lock.name == i.name for i in self._locks.keys()), \
1581 19b9ba9a Michael Hanselmann
           "Found duplicate lock name"
1582 19b9ba9a Michael Hanselmann
    self._locks[lock] = None
1583 19b9ba9a Michael Hanselmann
1584 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1585 19b9ba9a Michael Hanselmann
  def _GetLockInfo(self, fields):
1586 19b9ba9a Michael Hanselmann
    """Get information from all locks while the monitor lock is held.
1587 19b9ba9a Michael Hanselmann

1588 19b9ba9a Michael Hanselmann
    """
1589 19b9ba9a Michael Hanselmann
    result = {}
1590 19b9ba9a Michael Hanselmann
1591 19b9ba9a Michael Hanselmann
    for lock in self._locks.keys():
1592 19b9ba9a Michael Hanselmann
      assert lock.name not in result, "Found duplicate lock name"
1593 19b9ba9a Michael Hanselmann
      result[lock.name] = lock.GetInfo(fields)
1594 19b9ba9a Michael Hanselmann
1595 19b9ba9a Michael Hanselmann
    return result
1596 19b9ba9a Michael Hanselmann
1597 19b9ba9a Michael Hanselmann
  def QueryLocks(self, fields, sync):
1598 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1599 19b9ba9a Michael Hanselmann

1600 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1601 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1602 19b9ba9a Michael Hanselmann
    @type sync: boolean
1603 19b9ba9a Michael Hanselmann
    @param sync: Whether to operate in synchronous mode
1604 19b9ba9a Michael Hanselmann

1605 19b9ba9a Michael Hanselmann
    """
1606 19b9ba9a Michael Hanselmann
    if sync:
1607 19b9ba9a Michael Hanselmann
      raise NotImplementedError("Synchronous queries are not implemented")
1608 19b9ba9a Michael Hanselmann
1609 19b9ba9a Michael Hanselmann
    # Get all data without sorting
1610 19b9ba9a Michael Hanselmann
    result = self._GetLockInfo(fields)
1611 19b9ba9a Michael Hanselmann
1612 19b9ba9a Michael Hanselmann
    # Sort by name
1613 19b9ba9a Michael Hanselmann
    return [result[name] for name in utils.NiceSort(result.keys())]