Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 3dbe3ddf

History | View | Annotate | Download (52.5 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 errno
32 19b9ba9a Michael Hanselmann
import weakref
33 19b9ba9a Michael Hanselmann
import logging
34 887c7aa6 Michael Hanselmann
import heapq
35 24d16f76 Michael Hanselmann
import operator
36 e4e35357 Michael Hanselmann
import itertools
37 84e344d4 Michael Hanselmann
38 a95fd5d7 Guido Trotter
from ganeti import errors
39 7ee7c0c7 Guido Trotter
from ganeti import utils
40 cea881e5 Michael Hanselmann
from ganeti import compat
41 24d16f76 Michael Hanselmann
from ganeti import query
42 162c1c1f Guido Trotter
43 162c1c1f Guido Trotter
44 c31825f7 Michael Hanselmann
_EXCLUSIVE_TEXT = "exclusive"
45 c31825f7 Michael Hanselmann
_SHARED_TEXT = "shared"
46 24d16f76 Michael Hanselmann
_DELETED_TEXT = "deleted"
47 c31825f7 Michael Hanselmann
48 887c7aa6 Michael Hanselmann
_DEFAULT_PRIORITY = 0
49 887c7aa6 Michael Hanselmann
50 c31825f7 Michael Hanselmann
51 dbb11e8b Guido Trotter
def ssynchronized(mylock, shared=0):
52 42a999d1 Guido Trotter
  """Shared Synchronization decorator.
53 42a999d1 Guido Trotter

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

58 dbb11e8b Guido Trotter
  @type mylock: lockable object or string
59 dbb11e8b Guido Trotter
  @param mylock: lock to acquire or class member name of the lock to acquire
60 dbb11e8b Guido Trotter

61 42a999d1 Guido Trotter
  """
62 42a999d1 Guido Trotter
  def wrap(fn):
63 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
64 dbb11e8b Guido Trotter
      if isinstance(mylock, basestring):
65 dbb11e8b Guido Trotter
        assert args, "cannot ssynchronize on non-class method: self not found"
66 dbb11e8b Guido Trotter
        # args[0] is "self"
67 dbb11e8b Guido Trotter
        lock = getattr(args[0], mylock)
68 dbb11e8b Guido Trotter
      else:
69 dbb11e8b Guido Trotter
        lock = mylock
70 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
71 42a999d1 Guido Trotter
      try:
72 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
73 42a999d1 Guido Trotter
      finally:
74 42a999d1 Guido Trotter
        lock.release()
75 42a999d1 Guido Trotter
    return sync_function
76 42a999d1 Guido Trotter
  return wrap
77 42a999d1 Guido Trotter
78 42a999d1 Guido Trotter
79 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
80 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
81 d76167a5 Michael Hanselmann

82 d76167a5 Michael Hanselmann
  """
83 d76167a5 Michael Hanselmann
  __slots__ = [
84 d76167a5 Michael Hanselmann
    "_fd",
85 d76167a5 Michael Hanselmann
    "_poller",
86 d76167a5 Michael Hanselmann
    ]
87 d76167a5 Michael Hanselmann
88 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
89 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
90 d76167a5 Michael Hanselmann

91 d76167a5 Michael Hanselmann
    @type poller: select.poll
92 d76167a5 Michael Hanselmann
    @param poller: Poller object
93 d76167a5 Michael Hanselmann
    @type fd: int
94 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
95 d76167a5 Michael Hanselmann

96 d76167a5 Michael Hanselmann
    """
97 d76167a5 Michael Hanselmann
    object.__init__(self)
98 d76167a5 Michael Hanselmann
    self._poller = poller
99 d76167a5 Michael Hanselmann
    self._fd = fd
100 d76167a5 Michael Hanselmann
101 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
102 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
103 d76167a5 Michael Hanselmann

104 d76167a5 Michael Hanselmann
    @type timeout: float or None
105 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
106 d76167a5 Michael Hanselmann

107 d76167a5 Michael Hanselmann
    """
108 557838c1 Renรฉ Nussbaumer
    running_timeout = utils.RunningTimeout(timeout, True)
109 f4e673fb Michael Hanselmann
110 f4e673fb Michael Hanselmann
    while True:
111 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
112 f4e673fb Michael Hanselmann
113 b44b0141 Michael Hanselmann
      if remaining_time is not None:
114 b44b0141 Michael Hanselmann
        if remaining_time < 0.0:
115 b44b0141 Michael Hanselmann
          break
116 d76167a5 Michael Hanselmann
117 413b7472 Michael Hanselmann
        # Our calculation uses seconds, poll() wants milliseconds
118 b44b0141 Michael Hanselmann
        remaining_time *= 1000
119 d76167a5 Michael Hanselmann
120 d76167a5 Michael Hanselmann
      try:
121 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
122 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
123 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
124 d76167a5 Michael Hanselmann
          raise
125 d76167a5 Michael Hanselmann
        result = None
126 d76167a5 Michael Hanselmann
127 d76167a5 Michael Hanselmann
      # Check whether we were notified
128 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
129 d76167a5 Michael Hanselmann
        break
130 d76167a5 Michael Hanselmann
131 d76167a5 Michael Hanselmann
132 2419060d Guido Trotter
class _BaseCondition(object):
133 2419060d Guido Trotter
  """Base class containing common code for conditions.
134 2419060d Guido Trotter

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

137 2419060d Guido Trotter
  """
138 2419060d Guido Trotter
  __slots__ = [
139 2419060d Guido Trotter
    "_lock",
140 2419060d Guido Trotter
    "acquire",
141 2419060d Guido Trotter
    "release",
142 7f890059 Guido Trotter
    "_is_owned",
143 7f890059 Guido Trotter
    "_acquire_restore",
144 7f890059 Guido Trotter
    "_release_save",
145 2419060d Guido Trotter
    ]
146 2419060d Guido Trotter
147 2419060d Guido Trotter
  def __init__(self, lock):
148 2419060d Guido Trotter
    """Constructor for _BaseCondition.
149 2419060d Guido Trotter

150 69b99987 Michael Hanselmann
    @type lock: threading.Lock
151 2419060d Guido Trotter
    @param lock: condition base lock
152 2419060d Guido Trotter

153 2419060d Guido Trotter
    """
154 2419060d Guido Trotter
    object.__init__(self)
155 2419060d Guido Trotter
156 7f890059 Guido Trotter
    try:
157 7f890059 Guido Trotter
      self._release_save = lock._release_save
158 7f890059 Guido Trotter
    except AttributeError:
159 7f890059 Guido Trotter
      self._release_save = self._base_release_save
160 7f890059 Guido Trotter
    try:
161 7f890059 Guido Trotter
      self._acquire_restore = lock._acquire_restore
162 7f890059 Guido Trotter
    except AttributeError:
163 7f890059 Guido Trotter
      self._acquire_restore = self._base_acquire_restore
164 7f890059 Guido Trotter
    try:
165 7f890059 Guido Trotter
      self._is_owned = lock._is_owned
166 7f890059 Guido Trotter
    except AttributeError:
167 7f890059 Guido Trotter
      self._is_owned = self._base_is_owned
168 2419060d Guido Trotter
169 2419060d Guido Trotter
    self._lock = lock
170 2419060d Guido Trotter
171 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
172 2419060d Guido Trotter
    self.acquire = lock.acquire
173 2419060d Guido Trotter
    self.release = lock.release
174 2419060d Guido Trotter
175 7f890059 Guido Trotter
  def _base_is_owned(self):
176 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
177 2419060d Guido Trotter

178 2419060d Guido Trotter
    """
179 2419060d Guido Trotter
    if self._lock.acquire(0):
180 2419060d Guido Trotter
      self._lock.release()
181 2419060d Guido Trotter
      return False
182 2419060d Guido Trotter
    return True
183 2419060d Guido Trotter
184 7f890059 Guido Trotter
  def _base_release_save(self):
185 7f890059 Guido Trotter
    self._lock.release()
186 7f890059 Guido Trotter
187 7f890059 Guido Trotter
  def _base_acquire_restore(self, _):
188 7f890059 Guido Trotter
    self._lock.acquire()
189 7f890059 Guido Trotter
190 2419060d Guido Trotter
  def _check_owned(self):
191 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
192 2419060d Guido Trotter

193 2419060d Guido Trotter
    """
194 2419060d Guido Trotter
    if not self._is_owned():
195 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
196 2419060d Guido Trotter
197 2419060d Guido Trotter
198 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
199 34cb5617 Guido Trotter
  """Condition which can only be notified once.
200 d76167a5 Michael Hanselmann

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

207 d76167a5 Michael Hanselmann
  """
208 34cb5617 Guido Trotter
209 154b9580 Balazs Lecz
  __slots__ = [
210 d76167a5 Michael Hanselmann
    "_poller",
211 d76167a5 Michael Hanselmann
    "_read_fd",
212 d76167a5 Michael Hanselmann
    "_write_fd",
213 d76167a5 Michael Hanselmann
    "_nwaiters",
214 34cb5617 Guido Trotter
    "_notified",
215 d76167a5 Michael Hanselmann
    ]
216 d76167a5 Michael Hanselmann
217 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
218 d76167a5 Michael Hanselmann
219 34cb5617 Guido Trotter
  def __init__(self, lock):
220 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
221 d76167a5 Michael Hanselmann

222 d76167a5 Michael Hanselmann
    """
223 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
224 d76167a5 Michael Hanselmann
    self._nwaiters = 0
225 34cb5617 Guido Trotter
    self._notified = False
226 34cb5617 Guido Trotter
    self._read_fd = None
227 34cb5617 Guido Trotter
    self._write_fd = None
228 34cb5617 Guido Trotter
    self._poller = None
229 d76167a5 Michael Hanselmann
230 34cb5617 Guido Trotter
  def _check_unnotified(self):
231 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
232 69b99987 Michael Hanselmann

233 69b99987 Michael Hanselmann
    """
234 34cb5617 Guido Trotter
    if self._notified:
235 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
236 d76167a5 Michael Hanselmann
237 34cb5617 Guido Trotter
  def _Cleanup(self):
238 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
239 d76167a5 Michael Hanselmann

240 d76167a5 Michael Hanselmann
    """
241 34cb5617 Guido Trotter
    if self._read_fd is not None:
242 34cb5617 Guido Trotter
      os.close(self._read_fd)
243 34cb5617 Guido Trotter
      self._read_fd = None
244 d76167a5 Michael Hanselmann
245 34cb5617 Guido Trotter
    if self._write_fd is not None:
246 34cb5617 Guido Trotter
      os.close(self._write_fd)
247 34cb5617 Guido Trotter
      self._write_fd = None
248 34cb5617 Guido Trotter
    self._poller = None
249 d76167a5 Michael Hanselmann
250 83f2d5f6 Michael Hanselmann
  def wait(self, timeout):
251 34cb5617 Guido Trotter
    """Wait for a notification.
252 d76167a5 Michael Hanselmann

253 34cb5617 Guido Trotter
    @type timeout: float or None
254 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
255 d76167a5 Michael Hanselmann

256 d76167a5 Michael Hanselmann
    """
257 34cb5617 Guido Trotter
    self._check_owned()
258 34cb5617 Guido Trotter
    self._check_unnotified()
259 d76167a5 Michael Hanselmann
260 34cb5617 Guido Trotter
    self._nwaiters += 1
261 34cb5617 Guido Trotter
    try:
262 34cb5617 Guido Trotter
      if self._poller is None:
263 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
264 34cb5617 Guido Trotter
        self._poller = select.poll()
265 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
266 d76167a5 Michael Hanselmann
267 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
268 7f890059 Guido Trotter
      state = self._release_save()
269 34cb5617 Guido Trotter
      try:
270 34cb5617 Guido Trotter
        # Wait for notification
271 34cb5617 Guido Trotter
        wait_fn(timeout)
272 34cb5617 Guido Trotter
      finally:
273 34cb5617 Guido Trotter
        # Re-acquire lock
274 7f890059 Guido Trotter
        self._acquire_restore(state)
275 34cb5617 Guido Trotter
    finally:
276 34cb5617 Guido Trotter
      self._nwaiters -= 1
277 34cb5617 Guido Trotter
      if self._nwaiters == 0:
278 34cb5617 Guido Trotter
        self._Cleanup()
279 d76167a5 Michael Hanselmann
280 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
281 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
282 d76167a5 Michael Hanselmann

283 d76167a5 Michael Hanselmann
    """
284 34cb5617 Guido Trotter
    self._check_owned()
285 34cb5617 Guido Trotter
    self._check_unnotified()
286 34cb5617 Guido Trotter
    self._notified = True
287 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
288 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
289 d76167a5 Michael Hanselmann
      self._write_fd = None
290 d76167a5 Michael Hanselmann
291 d76167a5 Michael Hanselmann
292 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
293 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
294 48dabc6a Michael Hanselmann

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

301 48dabc6a Michael Hanselmann
  """
302 154b9580 Balazs Lecz
  __slots__ = [
303 c31825f7 Michael Hanselmann
    "_waiters",
304 34cb5617 Guido Trotter
    "_single_condition",
305 48dabc6a Michael Hanselmann
    ]
306 48dabc6a Michael Hanselmann
307 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
308 48dabc6a Michael Hanselmann
309 48dabc6a Michael Hanselmann
  def __init__(self, lock):
310 48dabc6a Michael Hanselmann
    """Initializes this class.
311 48dabc6a Michael Hanselmann

312 48dabc6a Michael Hanselmann
    """
313 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
314 c31825f7 Michael Hanselmann
    self._waiters = set()
315 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
316 48dabc6a Michael Hanselmann
317 83f2d5f6 Michael Hanselmann
  def wait(self, timeout):
318 48dabc6a Michael Hanselmann
    """Wait for a notification.
319 48dabc6a Michael Hanselmann

320 48dabc6a Michael Hanselmann
    @type timeout: float or None
321 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
322 48dabc6a Michael Hanselmann

323 48dabc6a Michael Hanselmann
    """
324 48dabc6a Michael Hanselmann
    self._check_owned()
325 48dabc6a Michael Hanselmann
326 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
327 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
328 c31825f7 Michael Hanselmann
    cond = self._single_condition
329 48dabc6a Michael Hanselmann
330 c31825f7 Michael Hanselmann
    self._waiters.add(threading.currentThread())
331 48dabc6a Michael Hanselmann
    try:
332 c31825f7 Michael Hanselmann
      cond.wait(timeout)
333 48dabc6a Michael Hanselmann
    finally:
334 c31825f7 Michael Hanselmann
      self._check_owned()
335 c31825f7 Michael Hanselmann
      self._waiters.remove(threading.currentThread())
336 48dabc6a Michael Hanselmann
337 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
338 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
339 48dabc6a Michael Hanselmann

340 48dabc6a Michael Hanselmann
    """
341 48dabc6a Michael Hanselmann
    self._check_owned()
342 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
343 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
344 48dabc6a Michael Hanselmann
345 c31825f7 Michael Hanselmann
  def get_waiting(self):
346 c31825f7 Michael Hanselmann
    """Returns a list of all waiting threads.
347 c31825f7 Michael Hanselmann

348 c31825f7 Michael Hanselmann
    """
349 c31825f7 Michael Hanselmann
    self._check_owned()
350 c31825f7 Michael Hanselmann
351 c31825f7 Michael Hanselmann
    return self._waiters
352 c31825f7 Michael Hanselmann
353 48dabc6a Michael Hanselmann
  def has_waiting(self):
354 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
355 48dabc6a Michael Hanselmann

356 48dabc6a Michael Hanselmann
    """
357 48dabc6a Michael Hanselmann
    self._check_owned()
358 48dabc6a Michael Hanselmann
359 c31825f7 Michael Hanselmann
    return bool(self._waiters)
360 48dabc6a Michael Hanselmann
361 48dabc6a Michael Hanselmann
362 887c7aa6 Michael Hanselmann
class _PipeConditionWithMode(PipeCondition):
363 887c7aa6 Michael Hanselmann
  __slots__ = [
364 887c7aa6 Michael Hanselmann
    "shared",
365 887c7aa6 Michael Hanselmann
    ]
366 887c7aa6 Michael Hanselmann
367 887c7aa6 Michael Hanselmann
  def __init__(self, lock, shared):
368 887c7aa6 Michael Hanselmann
    """Initializes this class.
369 887c7aa6 Michael Hanselmann

370 887c7aa6 Michael Hanselmann
    """
371 887c7aa6 Michael Hanselmann
    self.shared = shared
372 887c7aa6 Michael Hanselmann
    PipeCondition.__init__(self, lock)
373 887c7aa6 Michael Hanselmann
374 887c7aa6 Michael Hanselmann
375 84e344d4 Michael Hanselmann
class SharedLock(object):
376 162c1c1f Guido Trotter
  """Implements a shared lock.
377 162c1c1f Guido Trotter

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

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

390 7f93570a Iustin Pop
  @type name: string
391 7f93570a Iustin Pop
  @ivar name: the name of the lock
392 7f93570a Iustin Pop

393 162c1c1f Guido Trotter
  """
394 84e344d4 Michael Hanselmann
  __slots__ = [
395 19b9ba9a Michael Hanselmann
    "__weakref__",
396 84e344d4 Michael Hanselmann
    "__deleted",
397 84e344d4 Michael Hanselmann
    "__exc",
398 84e344d4 Michael Hanselmann
    "__lock",
399 84e344d4 Michael Hanselmann
    "__pending",
400 887c7aa6 Michael Hanselmann
    "__pending_by_prio",
401 887c7aa6 Michael Hanselmann
    "__pending_shared",
402 84e344d4 Michael Hanselmann
    "__shr",
403 7f93570a Iustin Pop
    "name",
404 84e344d4 Michael Hanselmann
    ]
405 84e344d4 Michael Hanselmann
406 887c7aa6 Michael Hanselmann
  __condition_class = _PipeConditionWithMode
407 84e344d4 Michael Hanselmann
408 19b9ba9a Michael Hanselmann
  def __init__(self, name, monitor=None):
409 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
410 84e344d4 Michael Hanselmann

411 7f93570a Iustin Pop
    @param name: the name of the lock
412 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
413 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register
414 7f93570a Iustin Pop

415 84e344d4 Michael Hanselmann
    """
416 84e344d4 Michael Hanselmann
    object.__init__(self)
417 84e344d4 Michael Hanselmann
418 7f93570a Iustin Pop
    self.name = name
419 7f93570a Iustin Pop
420 84e344d4 Michael Hanselmann
    # Internal lock
421 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
422 162c1c1f Guido Trotter
423 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
424 84e344d4 Michael Hanselmann
    self.__pending = []
425 887c7aa6 Michael Hanselmann
    self.__pending_by_prio = {}
426 887c7aa6 Michael Hanselmann
    self.__pending_shared = {}
427 84e344d4 Michael Hanselmann
428 84e344d4 Michael Hanselmann
    # Current lock holders
429 162c1c1f Guido Trotter
    self.__shr = set()
430 162c1c1f Guido Trotter
    self.__exc = None
431 162c1c1f Guido Trotter
432 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
433 a95fd5d7 Guido Trotter
    self.__deleted = False
434 a95fd5d7 Guido Trotter
435 19b9ba9a Michael Hanselmann
    # Register with lock monitor
436 19b9ba9a Michael Hanselmann
    if monitor:
437 19b9ba9a Michael Hanselmann
      monitor.RegisterLock(self)
438 19b9ba9a Michael Hanselmann
439 24d16f76 Michael Hanselmann
  def GetInfo(self, requested):
440 19b9ba9a Michael Hanselmann
    """Retrieves information for querying locks.
441 19b9ba9a Michael Hanselmann

442 24d16f76 Michael Hanselmann
    @type requested: set
443 24d16f76 Michael Hanselmann
    @param requested: Requested information, see C{query.LQ_*}
444 19b9ba9a Michael Hanselmann

445 19b9ba9a Michael Hanselmann
    """
446 19b9ba9a Michael Hanselmann
    self.__lock.acquire()
447 19b9ba9a Michael Hanselmann
    try:
448 19b9ba9a Michael Hanselmann
      # Note: to avoid unintentional race conditions, no references to
449 19b9ba9a Michael Hanselmann
      # modifiable objects should be returned unless they were created in this
450 19b9ba9a Michael Hanselmann
      # function.
451 24d16f76 Michael Hanselmann
      mode = None
452 24d16f76 Michael Hanselmann
      owner_names = None
453 24d16f76 Michael Hanselmann
454 24d16f76 Michael Hanselmann
      if query.LQ_MODE in requested:
455 24d16f76 Michael Hanselmann
        if self.__deleted:
456 24d16f76 Michael Hanselmann
          mode = _DELETED_TEXT
457 24d16f76 Michael Hanselmann
          assert not (self.__exc or self.__shr)
458 24d16f76 Michael Hanselmann
        elif self.__exc:
459 24d16f76 Michael Hanselmann
          mode = _EXCLUSIVE_TEXT
460 24d16f76 Michael Hanselmann
        elif self.__shr:
461 24d16f76 Michael Hanselmann
          mode = _SHARED_TEXT
462 24d16f76 Michael Hanselmann
463 24d16f76 Michael Hanselmann
      # Current owner(s) are wanted
464 24d16f76 Michael Hanselmann
      if query.LQ_OWNER in requested:
465 24d16f76 Michael Hanselmann
        if self.__exc:
466 24d16f76 Michael Hanselmann
          owner = [self.__exc]
467 19b9ba9a Michael Hanselmann
        else:
468 24d16f76 Michael Hanselmann
          owner = self.__shr
469 24d16f76 Michael Hanselmann
470 24d16f76 Michael Hanselmann
        if owner:
471 24d16f76 Michael Hanselmann
          assert not self.__deleted
472 24d16f76 Michael Hanselmann
          owner_names = [i.getName() for i in owner]
473 19b9ba9a Michael Hanselmann
474 24d16f76 Michael Hanselmann
      # Pending acquires are wanted
475 24d16f76 Michael Hanselmann
      if query.LQ_PENDING in requested:
476 24d16f76 Michael Hanselmann
        pending = []
477 24d16f76 Michael Hanselmann
478 24d16f76 Michael Hanselmann
        # Sorting instead of copying and using heaq functions for simplicity
479 24d16f76 Michael Hanselmann
        for (_, prioqueue) in sorted(self.__pending):
480 24d16f76 Michael Hanselmann
          for cond in prioqueue:
481 24d16f76 Michael Hanselmann
            if cond.shared:
482 24d16f76 Michael Hanselmann
              pendmode = _SHARED_TEXT
483 24d16f76 Michael Hanselmann
            else:
484 24d16f76 Michael Hanselmann
              pendmode = _EXCLUSIVE_TEXT
485 24d16f76 Michael Hanselmann
486 24d16f76 Michael Hanselmann
            # List of names will be sorted in L{query._GetLockPending}
487 24d16f76 Michael Hanselmann
            pending.append((pendmode, [i.getName()
488 24d16f76 Michael Hanselmann
                                       for i in cond.get_waiting()]))
489 24d16f76 Michael Hanselmann
      else:
490 24d16f76 Michael Hanselmann
        pending = None
491 24d16f76 Michael Hanselmann
492 24d16f76 Michael Hanselmann
      return (self.name, mode, owner_names, pending)
493 19b9ba9a Michael Hanselmann
    finally:
494 19b9ba9a Michael Hanselmann
      self.__lock.release()
495 19b9ba9a Michael Hanselmann
496 84e344d4 Michael Hanselmann
  def __check_deleted(self):
497 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
498 84e344d4 Michael Hanselmann

499 84e344d4 Michael Hanselmann
    """
500 84e344d4 Michael Hanselmann
    if self.__deleted:
501 7f93570a Iustin Pop
      raise errors.LockError("Deleted lock %s" % self.name)
502 84e344d4 Michael Hanselmann
503 162c1c1f Guido Trotter
  def __is_sharer(self):
504 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
505 84e344d4 Michael Hanselmann

506 84e344d4 Michael Hanselmann
    """
507 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
508 162c1c1f Guido Trotter
509 162c1c1f Guido Trotter
  def __is_exclusive(self):
510 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
511 84e344d4 Michael Hanselmann

512 84e344d4 Michael Hanselmann
    """
513 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
514 162c1c1f Guido Trotter
515 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
516 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
517 162c1c1f Guido Trotter

518 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
519 162c1c1f Guido Trotter
    the internal lock.
520 162c1c1f Guido Trotter

521 162c1c1f Guido Trotter
    """
522 162c1c1f Guido Trotter
    if shared < 0:
523 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
524 162c1c1f Guido Trotter
    elif shared:
525 162c1c1f Guido Trotter
      return self.__is_sharer()
526 162c1c1f Guido Trotter
    else:
527 162c1c1f Guido Trotter
      return self.__is_exclusive()
528 162c1c1f Guido Trotter
529 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
530 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
531 162c1c1f Guido Trotter

532 c41eea6e Iustin Pop
    @param shared:
533 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
534 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
535 c41eea6e Iustin Pop
        - > 0: check for shared ownership
536 162c1c1f Guido Trotter

537 162c1c1f Guido Trotter
    """
538 162c1c1f Guido Trotter
    self.__lock.acquire()
539 162c1c1f Guido Trotter
    try:
540 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
541 162c1c1f Guido Trotter
    finally:
542 162c1c1f Guido Trotter
      self.__lock.release()
543 162c1c1f Guido Trotter
544 84e344d4 Michael Hanselmann
  def _count_pending(self):
545 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
546 a95fd5d7 Guido Trotter

547 84e344d4 Michael Hanselmann
    @rtype: int
548 a95fd5d7 Guido Trotter

549 a95fd5d7 Guido Trotter
    """
550 84e344d4 Michael Hanselmann
    self.__lock.acquire()
551 84e344d4 Michael Hanselmann
    try:
552 887c7aa6 Michael Hanselmann
      return sum(len(prioqueue) for (_, prioqueue) in self.__pending)
553 887c7aa6 Michael Hanselmann
    finally:
554 887c7aa6 Michael Hanselmann
      self.__lock.release()
555 887c7aa6 Michael Hanselmann
556 887c7aa6 Michael Hanselmann
  def _check_empty(self):
557 887c7aa6 Michael Hanselmann
    """Checks whether there are any pending acquires.
558 887c7aa6 Michael Hanselmann

559 887c7aa6 Michael Hanselmann
    @rtype: bool
560 887c7aa6 Michael Hanselmann

561 887c7aa6 Michael Hanselmann
    """
562 887c7aa6 Michael Hanselmann
    self.__lock.acquire()
563 887c7aa6 Michael Hanselmann
    try:
564 887c7aa6 Michael Hanselmann
      # Order is important: __find_first_pending_queue modifies __pending
565 113359fe Michael Hanselmann
      (_, prioqueue) = self.__find_first_pending_queue()
566 113359fe Michael Hanselmann
567 113359fe Michael Hanselmann
      return not (prioqueue or
568 887c7aa6 Michael Hanselmann
                  self.__pending or
569 887c7aa6 Michael Hanselmann
                  self.__pending_by_prio or
570 887c7aa6 Michael Hanselmann
                  self.__pending_shared)
571 84e344d4 Michael Hanselmann
    finally:
572 84e344d4 Michael Hanselmann
      self.__lock.release()
573 a95fd5d7 Guido Trotter
574 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
575 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
576 84e344d4 Michael Hanselmann

577 84e344d4 Michael Hanselmann
    """
578 84e344d4 Michael Hanselmann
    if shared:
579 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
580 84e344d4 Michael Hanselmann
    else:
581 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
582 a95fd5d7 Guido Trotter
583 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
584 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
585 a95fd5d7 Guido Trotter

586 a95fd5d7 Guido Trotter
    """
587 84e344d4 Michael Hanselmann
    if shared:
588 84e344d4 Michael Hanselmann
      return self.__exc is None
589 84e344d4 Michael Hanselmann
    else:
590 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
591 a95fd5d7 Guido Trotter
592 887c7aa6 Michael Hanselmann
  def __find_first_pending_queue(self):
593 887c7aa6 Michael Hanselmann
    """Tries to find the topmost queued entry with pending acquires.
594 887c7aa6 Michael Hanselmann

595 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
596 887c7aa6 Michael Hanselmann

597 887c7aa6 Michael Hanselmann
    """
598 887c7aa6 Michael Hanselmann
    while self.__pending:
599 887c7aa6 Michael Hanselmann
      (priority, prioqueue) = self.__pending[0]
600 887c7aa6 Michael Hanselmann
601 887c7aa6 Michael Hanselmann
      if prioqueue:
602 113359fe Michael Hanselmann
        return (priority, prioqueue)
603 887c7aa6 Michael Hanselmann
604 113359fe Michael Hanselmann
      # Remove empty queue
605 113359fe Michael Hanselmann
      heapq.heappop(self.__pending)
606 113359fe Michael Hanselmann
      del self.__pending_by_prio[priority]
607 113359fe Michael Hanselmann
      assert priority not in self.__pending_shared
608 113359fe Michael Hanselmann
609 113359fe Michael Hanselmann
    return (None, None)
610 887c7aa6 Michael Hanselmann
611 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
612 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
613 a95fd5d7 Guido Trotter

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

616 84e344d4 Michael Hanselmann
    """
617 113359fe Michael Hanselmann
    (_, prioqueue) = self.__find_first_pending_queue()
618 113359fe Michael Hanselmann
619 113359fe Michael Hanselmann
    return cond == prioqueue[0]
620 4d686df8 Guido Trotter
621 887c7aa6 Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout, priority):
622 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
623 9216a9f7 Michael Hanselmann

624 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
625 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
626 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
627 887c7aa6 Michael Hanselmann
    @type priority: integer
628 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
629 9216a9f7 Michael Hanselmann

630 9216a9f7 Michael Hanselmann
    """
631 84e344d4 Michael Hanselmann
    self.__check_deleted()
632 9216a9f7 Michael Hanselmann
633 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
634 7f93570a Iustin Pop
    assert not self.__is_owned(), ("double acquire() on a non-recursive lock"
635 7f93570a Iustin Pop
                                   " %s" % self.name)
636 84e344d4 Michael Hanselmann
637 887c7aa6 Michael Hanselmann
    # Remove empty entries from queue
638 887c7aa6 Michael Hanselmann
    self.__find_first_pending_queue()
639 887c7aa6 Michael Hanselmann
640 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
641 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
642 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
643 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
644 84e344d4 Michael Hanselmann
      return True
645 9216a9f7 Michael Hanselmann
646 887c7aa6 Michael Hanselmann
    prioqueue = self.__pending_by_prio.get(priority, None)
647 9216a9f7 Michael Hanselmann
648 887c7aa6 Michael Hanselmann
    if shared:
649 887c7aa6 Michael Hanselmann
      # Try to re-use condition for shared acquire
650 887c7aa6 Michael Hanselmann
      wait_condition = self.__pending_shared.get(priority, None)
651 887c7aa6 Michael Hanselmann
      assert (wait_condition is None or
652 887c7aa6 Michael Hanselmann
              (wait_condition.shared and wait_condition in prioqueue))
653 84e344d4 Michael Hanselmann
    else:
654 887c7aa6 Michael Hanselmann
      wait_condition = None
655 887c7aa6 Michael Hanselmann
656 887c7aa6 Michael Hanselmann
    if wait_condition is None:
657 887c7aa6 Michael Hanselmann
      if prioqueue is None:
658 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_by_prio
659 887c7aa6 Michael Hanselmann
660 887c7aa6 Michael Hanselmann
        prioqueue = []
661 887c7aa6 Michael Hanselmann
        heapq.heappush(self.__pending, (priority, prioqueue))
662 887c7aa6 Michael Hanselmann
        self.__pending_by_prio[priority] = prioqueue
663 887c7aa6 Michael Hanselmann
664 887c7aa6 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock, shared)
665 887c7aa6 Michael Hanselmann
      prioqueue.append(wait_condition)
666 887c7aa6 Michael Hanselmann
667 887c7aa6 Michael Hanselmann
      if shared:
668 887c7aa6 Michael Hanselmann
        # Keep reference for further shared acquires on same priority. This is
669 887c7aa6 Michael Hanselmann
        # better than trying to find it in the list of pending acquires.
670 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_shared
671 887c7aa6 Michael Hanselmann
        self.__pending_shared[priority] = wait_condition
672 84e344d4 Michael Hanselmann
673 84e344d4 Michael Hanselmann
    try:
674 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
675 84e344d4 Michael Hanselmann
      # expires.
676 887c7aa6 Michael Hanselmann
      # TODO: Decrease timeout with spurious notifications
677 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
678 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
679 84e344d4 Michael Hanselmann
        # Wait for notification
680 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
681 84e344d4 Michael Hanselmann
        self.__check_deleted()
682 84e344d4 Michael Hanselmann
683 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
684 84e344d4 Michael Hanselmann
        # internally for that case.
685 84e344d4 Michael Hanselmann
        if timeout is not None:
686 84e344d4 Michael Hanselmann
          break
687 84e344d4 Michael Hanselmann
688 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
689 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
690 84e344d4 Michael Hanselmann
        return True
691 9216a9f7 Michael Hanselmann
    finally:
692 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
693 887c7aa6 Michael Hanselmann
      if not wait_condition.has_waiting():
694 887c7aa6 Michael Hanselmann
        prioqueue.remove(wait_condition)
695 887c7aa6 Michael Hanselmann
        if wait_condition.shared:
696 113359fe Michael Hanselmann
          # Remove from list of shared acquires if it wasn't while releasing
697 113359fe Michael Hanselmann
          # (e.g. on lock deletion)
698 113359fe Michael Hanselmann
          self.__pending_shared.pop(priority, None)
699 9216a9f7 Michael Hanselmann
700 84e344d4 Michael Hanselmann
    return False
701 9216a9f7 Michael Hanselmann
702 7100c2fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, priority=None,
703 887c7aa6 Michael Hanselmann
              test_notify=None):
704 162c1c1f Guido Trotter
    """Acquire a shared lock.
705 162c1c1f Guido Trotter

706 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
707 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
708 c41eea6e Iustin Pop
        exclusive lock will be acquired
709 84e344d4 Michael Hanselmann
    @type timeout: float
710 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
711 887c7aa6 Michael Hanselmann
    @type priority: integer
712 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
713 008b92fa Michael Hanselmann
    @type test_notify: callable or None
714 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
715 162c1c1f Guido Trotter

716 162c1c1f Guido Trotter
    """
717 7100c2fa Michael Hanselmann
    if priority is None:
718 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
719 7100c2fa Michael Hanselmann
720 162c1c1f Guido Trotter
    self.__lock.acquire()
721 162c1c1f Guido Trotter
    try:
722 008b92fa Michael Hanselmann
      # We already got the lock, notify now
723 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
724 008b92fa Michael Hanselmann
        test_notify()
725 008b92fa Michael Hanselmann
726 887c7aa6 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout, priority)
727 162c1c1f Guido Trotter
    finally:
728 162c1c1f Guido Trotter
      self.__lock.release()
729 162c1c1f Guido Trotter
730 3dbe3ddf Michael Hanselmann
  def downgrade(self):
731 3dbe3ddf Michael Hanselmann
    """Changes the lock mode from exclusive to shared.
732 3dbe3ddf Michael Hanselmann

733 3dbe3ddf Michael Hanselmann
    Pending acquires in shared mode on the same priority will go ahead.
734 3dbe3ddf Michael Hanselmann

735 3dbe3ddf Michael Hanselmann
    """
736 3dbe3ddf Michael Hanselmann
    self.__lock.acquire()
737 3dbe3ddf Michael Hanselmann
    try:
738 3dbe3ddf Michael Hanselmann
      assert self.__is_owned(), "Lock must be owned"
739 3dbe3ddf Michael Hanselmann
740 3dbe3ddf Michael Hanselmann
      if self.__is_exclusive():
741 3dbe3ddf Michael Hanselmann
        # Do nothing if the lock is already acquired in shared mode
742 3dbe3ddf Michael Hanselmann
        self.__exc = None
743 3dbe3ddf Michael Hanselmann
        self.__do_acquire(1)
744 3dbe3ddf Michael Hanselmann
745 3dbe3ddf Michael Hanselmann
        # Important: pending shared acquires should only jump ahead if there
746 3dbe3ddf Michael Hanselmann
        # was a transition from exclusive to shared, otherwise an owner of a
747 3dbe3ddf Michael Hanselmann
        # shared lock can keep calling this function to push incoming shared
748 3dbe3ddf Michael Hanselmann
        # acquires
749 3dbe3ddf Michael Hanselmann
        (priority, prioqueue) = self.__find_first_pending_queue()
750 3dbe3ddf Michael Hanselmann
        if prioqueue:
751 3dbe3ddf Michael Hanselmann
          # Is there a pending shared acquire on this priority?
752 3dbe3ddf Michael Hanselmann
          cond = self.__pending_shared.pop(priority, None)
753 3dbe3ddf Michael Hanselmann
          if cond:
754 3dbe3ddf Michael Hanselmann
            assert cond.shared
755 3dbe3ddf Michael Hanselmann
            assert cond in prioqueue
756 3dbe3ddf Michael Hanselmann
757 3dbe3ddf Michael Hanselmann
            # Ensure shared acquire is on top of queue
758 3dbe3ddf Michael Hanselmann
            if len(prioqueue) > 1:
759 3dbe3ddf Michael Hanselmann
              prioqueue.remove(cond)
760 3dbe3ddf Michael Hanselmann
              prioqueue.insert(0, cond)
761 3dbe3ddf Michael Hanselmann
762 3dbe3ddf Michael Hanselmann
            # Notify
763 3dbe3ddf Michael Hanselmann
            cond.notifyAll()
764 3dbe3ddf Michael Hanselmann
765 3dbe3ddf Michael Hanselmann
      assert not self.__is_exclusive()
766 3dbe3ddf Michael Hanselmann
      assert self.__is_sharer()
767 3dbe3ddf Michael Hanselmann
768 3dbe3ddf Michael Hanselmann
      return True
769 3dbe3ddf Michael Hanselmann
    finally:
770 3dbe3ddf Michael Hanselmann
      self.__lock.release()
771 3dbe3ddf Michael Hanselmann
772 162c1c1f Guido Trotter
  def release(self):
773 162c1c1f Guido Trotter
    """Release a Shared Lock.
774 162c1c1f Guido Trotter

775 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
776 162c1c1f Guido Trotter
    before calling this function.
777 162c1c1f Guido Trotter

778 162c1c1f Guido Trotter
    """
779 162c1c1f Guido Trotter
    self.__lock.acquire()
780 162c1c1f Guido Trotter
    try:
781 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
782 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
783 84e344d4 Michael Hanselmann
784 162c1c1f Guido Trotter
      # Autodetect release type
785 162c1c1f Guido Trotter
      if self.__is_exclusive():
786 162c1c1f Guido Trotter
        self.__exc = None
787 84e344d4 Michael Hanselmann
      else:
788 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
789 162c1c1f Guido Trotter
790 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
791 113359fe Michael Hanselmann
      (priority, prioqueue) = self.__find_first_pending_queue()
792 887c7aa6 Michael Hanselmann
      if prioqueue:
793 113359fe Michael Hanselmann
        cond = prioqueue[0]
794 113359fe Michael Hanselmann
        cond.notifyAll()
795 113359fe Michael Hanselmann
        if cond.shared:
796 113359fe Michael Hanselmann
          # Prevent further shared acquires from sneaking in while waiters are
797 113359fe Michael Hanselmann
          # notified
798 113359fe Michael Hanselmann
          self.__pending_shared.pop(priority, None)
799 162c1c1f Guido Trotter
800 162c1c1f Guido Trotter
    finally:
801 162c1c1f Guido Trotter
      self.__lock.release()
802 162c1c1f Guido Trotter
803 7100c2fa Michael Hanselmann
  def delete(self, timeout=None, priority=None):
804 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
805 a95fd5d7 Guido Trotter

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

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

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

868 5aab242c Michael Hanselmann
  """
869 5aab242c Michael Hanselmann
870 5aab242c Michael Hanselmann
871 aaae9bc0 Guido Trotter
class LockSet:
872 aaae9bc0 Guido Trotter
  """Implements a set of locks.
873 aaae9bc0 Guido Trotter

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

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

881 7f93570a Iustin Pop
  @type name: string
882 7f93570a Iustin Pop
  @ivar name: the name of the lockset
883 7f93570a Iustin Pop

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

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

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

923 4fb780d1 Michael Hanselmann
    """
924 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
925 4fb780d1 Michael Hanselmann
926 3dbe3ddf Michael Hanselmann
  def _get_lock(self):
927 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock.
928 3dbe3ddf Michael Hanselmann

929 3dbe3ddf Michael Hanselmann
    """
930 3dbe3ddf Michael Hanselmann
    return self.__lock
931 3dbe3ddf Michael Hanselmann
932 3dbe3ddf Michael Hanselmann
  def _get_lockdict(self):
933 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock dictionary.
934 3dbe3ddf Michael Hanselmann

935 3dbe3ddf Michael Hanselmann
    Accessing this structure is only safe in single-thread usage or when the
936 3dbe3ddf Michael Hanselmann
    lockset-internal lock is held.
937 3dbe3ddf Michael Hanselmann

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

988 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
989 aaae9bc0 Guido Trotter
    result after releasing the lock.
990 aaae9bc0 Guido Trotter

991 aaae9bc0 Guido Trotter
    """
992 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
993 aaae9bc0 Guido Trotter
994 aaae9bc0 Guido Trotter
  def _names(self):
995 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
996 aaae9bc0 Guido Trotter

997 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
998 cdb08f44 Michael Hanselmann

999 aaae9bc0 Guido Trotter
    """
1000 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
1001 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
1002 d4803c24 Guido Trotter
    release_lock = False
1003 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
1004 d4803c24 Guido Trotter
      release_lock = True
1005 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
1006 aaae9bc0 Guido Trotter
    try:
1007 aaae9bc0 Guido Trotter
      result = self.__names()
1008 aaae9bc0 Guido Trotter
    finally:
1009 d4803c24 Guido Trotter
      if release_lock:
1010 d4803c24 Guido Trotter
        self.__lock.release()
1011 0cf257c5 Guido Trotter
    return set(result)
1012 aaae9bc0 Guido Trotter
1013 7100c2fa Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, priority=None,
1014 887c7aa6 Michael Hanselmann
              test_notify=None):
1015 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
1016 aaae9bc0 Guido Trotter

1017 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1018 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1019 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1020 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1021 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
1022 c41eea6e Iustin Pop
        exclusive lock will be acquired
1023 5aab242c Michael Hanselmann
    @type timeout: float or None
1024 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1025 887c7aa6 Michael Hanselmann
    @type priority: integer
1026 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1027 5aab242c Michael Hanselmann
    @type test_notify: callable or None
1028 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1029 aaae9bc0 Guido Trotter

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

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

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

1093 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
1094 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
1095 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
1096 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
1097 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1098 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1099 76e2f08a Michael Hanselmann

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

1185 3dbe3ddf Michael Hanselmann
    The locks must have been acquired in exclusive mode.
1186 3dbe3ddf Michael Hanselmann

1187 3dbe3ddf Michael Hanselmann
    """
1188 3dbe3ddf Michael Hanselmann
    assert self._is_owned(), ("downgrade on lockset %s while not owning any"
1189 3dbe3ddf Michael Hanselmann
                              " lock" % self.name)
1190 3dbe3ddf Michael Hanselmann
1191 3dbe3ddf Michael Hanselmann
    # Support passing in a single resource to downgrade rather than many
1192 3dbe3ddf Michael Hanselmann
    if isinstance(names, basestring):
1193 3dbe3ddf Michael Hanselmann
      names = [names]
1194 3dbe3ddf Michael Hanselmann
1195 3dbe3ddf Michael Hanselmann
    owned = self._list_owned()
1196 3dbe3ddf Michael Hanselmann
1197 3dbe3ddf Michael Hanselmann
    if names is None:
1198 3dbe3ddf Michael Hanselmann
      names = owned
1199 3dbe3ddf Michael Hanselmann
    else:
1200 3dbe3ddf Michael Hanselmann
      names = set(names)
1201 3dbe3ddf Michael Hanselmann
      assert owned.issuperset(names), \
1202 3dbe3ddf Michael Hanselmann
        ("downgrade() on unheld resources %s (set %s)" %
1203 3dbe3ddf Michael Hanselmann
         (names.difference(owned), self.name))
1204 3dbe3ddf Michael Hanselmann
1205 3dbe3ddf Michael Hanselmann
    for lockname in names:
1206 3dbe3ddf Michael Hanselmann
      self.__lockdict[lockname].downgrade()
1207 3dbe3ddf Michael Hanselmann
1208 3dbe3ddf Michael Hanselmann
    # Do we own the lockset in exclusive mode?
1209 3dbe3ddf Michael Hanselmann
    if self.__lock._is_owned(shared=0):
1210 3dbe3ddf Michael Hanselmann
      # Have all locks been downgraded?
1211 3dbe3ddf Michael Hanselmann
      if not compat.any(lock._is_owned(shared=0)
1212 3dbe3ddf Michael Hanselmann
                        for lock in self.__lockdict.values()):
1213 3dbe3ddf Michael Hanselmann
        self.__lock.downgrade()
1214 3dbe3ddf Michael Hanselmann
        assert self.__lock._is_owned(shared=1)
1215 3dbe3ddf Michael Hanselmann
1216 3dbe3ddf Michael Hanselmann
    return True
1217 3dbe3ddf Michael Hanselmann
1218 aaae9bc0 Guido Trotter
  def release(self, names=None):
1219 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
1220 aaae9bc0 Guido Trotter

1221 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1222 aaae9bc0 Guido Trotter
    before releasing them.
1223 aaae9bc0 Guido Trotter

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

1228 aaae9bc0 Guido Trotter
    """
1229 7f93570a Iustin Pop
    assert self._is_owned(), ("release() on lock set %s while not owner" %
1230 7f93570a Iustin Pop
                              self.name)
1231 aaae9bc0 Guido Trotter
1232 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1233 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1234 aaae9bc0 Guido Trotter
      names = [names]
1235 aaae9bc0 Guido Trotter
1236 aaae9bc0 Guido Trotter
    if names is None:
1237 aaae9bc0 Guido Trotter
      names = self._list_owned()
1238 aaae9bc0 Guido Trotter
    else:
1239 aaae9bc0 Guido Trotter
      names = set(names)
1240 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
1241 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1242 7f93570a Iustin Pop
               (names.difference(self._list_owned()), self.name))
1243 aaae9bc0 Guido Trotter
1244 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1245 3b7ed473 Guido Trotter
    # After this 'add' can work again
1246 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
1247 3b7ed473 Guido Trotter
      self.__lock.release()
1248 b2dabfd6 Guido Trotter
      self._del_owned()
1249 3b7ed473 Guido Trotter
1250 aaae9bc0 Guido Trotter
    for lockname in names:
1251 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1252 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1253 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1254 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1255 aaae9bc0 Guido Trotter
1256 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1257 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1258 aaae9bc0 Guido Trotter

1259 ec44d893 Guido Trotter
    @type names: list of strings
1260 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1261 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1262 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1263 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1264 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1265 aaae9bc0 Guido Trotter

1266 aaae9bc0 Guido Trotter
    """
1267 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1268 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
1269 7f93570a Iustin Pop
      ("Cannot add locks if the set %s is only partially owned, or shared" %
1270 7f93570a Iustin Pop
       self.name)
1271 3b7ed473 Guido Trotter
1272 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1273 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1274 aaae9bc0 Guido Trotter
      names = [names]
1275 aaae9bc0 Guido Trotter
1276 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1277 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1278 3b7ed473 Guido Trotter
    release_lock = False
1279 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
1280 3b7ed473 Guido Trotter
      release_lock = True
1281 3b7ed473 Guido Trotter
      self.__lock.acquire()
1282 3b7ed473 Guido Trotter
1283 aaae9bc0 Guido Trotter
    try:
1284 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1285 aaae9bc0 Guido Trotter
      if invalid_names:
1286 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1287 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1288 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1289 7f93570a Iustin Pop
        raise errors.LockError("duplicate add(%s) on lockset %s" %
1290 7f93570a Iustin Pop
                               (invalid_names, self.name))
1291 aaae9bc0 Guido Trotter
1292 aaae9bc0 Guido Trotter
      for lockname in names:
1293 19b9ba9a Michael Hanselmann
        lock = SharedLock(self._GetLockName(lockname), monitor=self.__monitor)
1294 aaae9bc0 Guido Trotter
1295 aaae9bc0 Guido Trotter
        if acquired:
1296 887c7aa6 Michael Hanselmann
          # No need for priority or timeout here as this lock has just been
1297 887c7aa6 Michael Hanselmann
          # created
1298 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1299 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1300 aaae9bc0 Guido Trotter
          try:
1301 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1302 aaae9bc0 Guido Trotter
          except:
1303 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1304 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1305 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1306 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1307 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1308 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1309 aaae9bc0 Guido Trotter
            lock.release()
1310 aaae9bc0 Guido Trotter
            raise
1311 aaae9bc0 Guido Trotter
1312 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1313 aaae9bc0 Guido Trotter
1314 aaae9bc0 Guido Trotter
    finally:
1315 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1316 3b7ed473 Guido Trotter
      if release_lock:
1317 3b7ed473 Guido Trotter
        self.__lock.release()
1318 aaae9bc0 Guido Trotter
1319 aaae9bc0 Guido Trotter
    return True
1320 aaae9bc0 Guido Trotter
1321 5e0a6daf Michael Hanselmann
  def remove(self, names):
1322 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1323 aaae9bc0 Guido Trotter

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

1327 ec44d893 Guido Trotter
    @type names: list of strings
1328 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1329 aaae9bc0 Guido Trotter

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

1334 aaae9bc0 Guido Trotter
    """
1335 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1336 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1337 aaae9bc0 Guido Trotter
      names = [names]
1338 aaae9bc0 Guido Trotter
1339 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1340 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1341 aaae9bc0 Guido Trotter
    # by the lock itself.
1342 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
1343 7f93570a Iustin Pop
      "remove() on acquired lockset %s while not owning all elements" %
1344 7f93570a Iustin Pop
      self.name)
1345 aaae9bc0 Guido Trotter
1346 3f404fc5 Guido Trotter
    removed = []
1347 aaae9bc0 Guido Trotter
1348 aaae9bc0 Guido Trotter
    for lname in names:
1349 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1350 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1351 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1352 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1353 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1354 aaae9bc0 Guido Trotter
      try:
1355 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1356 3f404fc5 Guido Trotter
        removed.append(lname)
1357 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1358 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1359 7f93570a Iustin Pop
        assert not self._is_owned(), ("remove failed while holding lockset %s"
1360 7f93570a Iustin Pop
                                      % self.name)
1361 aaae9bc0 Guido Trotter
      else:
1362 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1363 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1364 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1365 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1366 aaae9bc0 Guido Trotter
        #
1367 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1368 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1369 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1370 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1371 aaae9bc0 Guido Trotter
        if self._is_owned():
1372 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1373 aaae9bc0 Guido Trotter
1374 3f404fc5 Guido Trotter
    return removed
1375 aaae9bc0 Guido Trotter
1376 7ee7c0c7 Guido Trotter
1377 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1378 7ee7c0c7 Guido Trotter
# Current rules are:
1379 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1380 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1381 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1382 7ee7c0c7 Guido Trotter
#   avoided.
1383 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1384 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1385 7ee7c0c7 Guido Trotter
#   the same time.
1386 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1387 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1388 819ca990 Guido Trotter
LEVEL_NODEGROUP = 2
1389 819ca990 Guido Trotter
LEVEL_NODE = 3
1390 7ee7c0c7 Guido Trotter
1391 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1392 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1393 819ca990 Guido Trotter
          LEVEL_NODEGROUP,
1394 04e1bfaf Guido Trotter
          LEVEL_NODE]
1395 7ee7c0c7 Guido Trotter
1396 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1397 819ca990 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_NODEGROUP, LEVEL_INSTANCE]
1398 7ee7c0c7 Guido Trotter
1399 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1400 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1401 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1402 819ca990 Guido Trotter
  LEVEL_NODEGROUP: "nodegroup",
1403 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1404 ea205dbc Michael Hanselmann
  }
1405 ea205dbc Michael Hanselmann
1406 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1407 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1408 7ee7c0c7 Guido Trotter
1409 7ee7c0c7 Guido Trotter
1410 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1411 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1412 7ee7c0c7 Guido Trotter

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

1418 7ee7c0c7 Guido Trotter
  """
1419 7ee7c0c7 Guido Trotter
  _instance = None
1420 7ee7c0c7 Guido Trotter
1421 819ca990 Guido Trotter
  def __init__(self, nodes, nodegroups, instances):
1422 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1423 7ee7c0c7 Guido Trotter

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

1427 c41eea6e Iustin Pop
    @param nodes: list of node names
1428 819ca990 Guido Trotter
    @param nodegroups: list of nodegroup uuids
1429 c41eea6e Iustin Pop
    @param instances: list of instance names
1430 7ee7c0c7 Guido Trotter

1431 7ee7c0c7 Guido Trotter
    """
1432 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1433 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1434 c41eea6e Iustin Pop
1435 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1436 7ee7c0c7 Guido Trotter
1437 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1438 19b9ba9a Michael Hanselmann
1439 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1440 7ee7c0c7 Guido Trotter
    # locking order.
1441 7ee7c0c7 Guido Trotter
    self.__keyring = {
1442 19b9ba9a Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "BGL", monitor=self._monitor),
1443 19b9ba9a Michael Hanselmann
      LEVEL_NODE: LockSet(nodes, "nodes", monitor=self._monitor),
1444 819ca990 Guido Trotter
      LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroups", monitor=self._monitor),
1445 19b9ba9a Michael Hanselmann
      LEVEL_INSTANCE: LockSet(instances, "instances",
1446 19b9ba9a Michael Hanselmann
                              monitor=self._monitor),
1447 19b9ba9a Michael Hanselmann
      }
1448 19b9ba9a Michael Hanselmann
1449 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1450 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1451 19b9ba9a Michael Hanselmann

1452 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1453 19b9ba9a Michael Hanselmann

1454 19b9ba9a Michael Hanselmann
    """
1455 24d16f76 Michael Hanselmann
    return self._monitor.QueryLocks(fields)
1456 24d16f76 Michael Hanselmann
1457 24d16f76 Michael Hanselmann
  def OldStyleQueryLocks(self, fields):
1458 24d16f76 Michael Hanselmann
    """Queries information from all locks, returning old-style data.
1459 24d16f76 Michael Hanselmann

1460 24d16f76 Michael Hanselmann
    See L{LockMonitor.OldStyleQueryLocks}.
1461 24d16f76 Michael Hanselmann

1462 24d16f76 Michael Hanselmann
    """
1463 24d16f76 Michael Hanselmann
    return self._monitor.OldStyleQueryLocks(fields)
1464 7ee7c0c7 Guido Trotter
1465 7ee7c0c7 Guido Trotter
  def _names(self, level):
1466 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1467 7ee7c0c7 Guido Trotter

1468 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1469 c41eea6e Iustin Pop

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

1472 7ee7c0c7 Guido Trotter
    """
1473 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1474 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1475 7ee7c0c7 Guido Trotter
1476 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1477 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1478 7ee7c0c7 Guido Trotter

1479 7ee7c0c7 Guido Trotter
    """
1480 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1481 7ee7c0c7 Guido Trotter
1482 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1483 d4f4b3e7 Guido Trotter
1484 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1485 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1486 7ee7c0c7 Guido Trotter

1487 7ee7c0c7 Guido Trotter
    """
1488 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1489 7ee7c0c7 Guido Trotter
1490 07cba1bc Michael Hanselmann
  list_owned = _list_owned
1491 07cba1bc Michael Hanselmann
1492 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1493 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1494 7ee7c0c7 Guido Trotter

1495 7ee7c0c7 Guido Trotter
    """
1496 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1497 7ee7c0c7 Guido Trotter
    # the test cases.
1498 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1499 7ee7c0c7 Guido Trotter
1500 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1501 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1502 7ee7c0c7 Guido Trotter

1503 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1504 7ee7c0c7 Guido Trotter

1505 7ee7c0c7 Guido Trotter
    """
1506 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1507 7ee7c0c7 Guido Trotter
1508 c70d2d9b Iustin Pop
  @staticmethod
1509 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1510 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1511 c41eea6e Iustin Pop

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

1515 7ee7c0c7 Guido Trotter
    """
1516 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1517 7ee7c0c7 Guido Trotter
1518 b30d95b6 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None):
1519 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1520 7ee7c0c7 Guido Trotter

1521 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1522 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1523 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1524 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1525 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1526 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1527 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1528 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1529 5e0a6daf Michael Hanselmann
    @type timeout: float
1530 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1531 b30d95b6 Michael Hanselmann
    @type priority: integer
1532 b30d95b6 Michael Hanselmann
    @param priority: Priority for acquiring lock
1533 7ee7c0c7 Guido Trotter

1534 7ee7c0c7 Guido Trotter
    """
1535 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1536 7ee7c0c7 Guido Trotter
1537 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1538 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1539 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1540 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1541 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1542 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1543 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1544 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1545 7ee7c0c7 Guido Trotter
1546 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1547 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1548 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1549 7ee7c0c7 Guido Trotter
1550 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1551 b30d95b6 Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout,
1552 b30d95b6 Michael Hanselmann
                                         priority=priority)
1553 7ee7c0c7 Guido Trotter
1554 3dbe3ddf Michael Hanselmann
  def downgrade(self, level, names=None):
1555 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1556 3dbe3ddf Michael Hanselmann

1557 3dbe3ddf Michael Hanselmann
    You must have acquired the locks in exclusive mode.
1558 3dbe3ddf Michael Hanselmann

1559 3dbe3ddf Michael Hanselmann
    @type level: member of locking.LEVELS
1560 3dbe3ddf Michael Hanselmann
    @param level: the level at which the locks shall be downgraded
1561 3dbe3ddf Michael Hanselmann
    @type names: list of strings, or None
1562 3dbe3ddf Michael Hanselmann
    @param names: the names of the locks which shall be downgraded
1563 3dbe3ddf Michael Hanselmann
        (defaults to all the locks acquired at the level)
1564 3dbe3ddf Michael Hanselmann

1565 3dbe3ddf Michael Hanselmann
    """
1566 3dbe3ddf Michael Hanselmann
    assert level in LEVELS, "Invalid locking level %s" % level
1567 3dbe3ddf Michael Hanselmann
1568 3dbe3ddf Michael Hanselmann
    return self.__keyring[level].downgrade(names=names)
1569 3dbe3ddf Michael Hanselmann
1570 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1571 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1572 7ee7c0c7 Guido Trotter

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

1576 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1577 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1578 ec44d893 Guido Trotter
    @type names: list of strings, or None
1579 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1580 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1581 7ee7c0c7 Guido Trotter

1582 7ee7c0c7 Guido Trotter
    """
1583 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1584 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1585 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1586 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1587 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1588 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1589 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1590 7ee7c0c7 Guido Trotter
1591 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1592 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1593 7ee7c0c7 Guido Trotter
1594 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1595 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1596 7ee7c0c7 Guido Trotter

1597 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1598 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1599 ec44d893 Guido Trotter
    @type names: list of strings
1600 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1601 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1602 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1603 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1604 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1605 c41eea6e Iustin Pop

1606 7ee7c0c7 Guido Trotter
    """
1607 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1608 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1609 7ee7c0c7 Guido Trotter
           " operations")
1610 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1611 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1612 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1613 7ee7c0c7 Guido Trotter
1614 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1615 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1616 7ee7c0c7 Guido Trotter

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

1620 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1621 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1622 ec44d893 Guido Trotter
    @type names: list of strings
1623 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1624 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1625 7ee7c0c7 Guido Trotter

1626 7ee7c0c7 Guido Trotter
    """
1627 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1628 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1629 7ee7c0c7 Guido Trotter
           " operations")
1630 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1631 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1632 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1633 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1634 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1635 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1636 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1637 19b9ba9a Michael Hanselmann
1638 19b9ba9a Michael Hanselmann
1639 e4e35357 Michael Hanselmann
def _MonitorSortKey((num, item)):
1640 e4e35357 Michael Hanselmann
  """Sorting key function.
1641 e4e35357 Michael Hanselmann

1642 e4e35357 Michael Hanselmann
  Sort by name, then by incoming order.
1643 e4e35357 Michael Hanselmann

1644 e4e35357 Michael Hanselmann
  """
1645 e4e35357 Michael Hanselmann
  (name, _, _, _) = item
1646 e4e35357 Michael Hanselmann
1647 e4e35357 Michael Hanselmann
  return (utils.NiceSortKey(name), num)
1648 e4e35357 Michael Hanselmann
1649 e4e35357 Michael Hanselmann
1650 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1651 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1652 19b9ba9a Michael Hanselmann
1653 19b9ba9a Michael Hanselmann
  def __init__(self):
1654 19b9ba9a Michael Hanselmann
    """Initializes this class.
1655 19b9ba9a Michael Hanselmann

1656 19b9ba9a Michael Hanselmann
    """
1657 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1658 19b9ba9a Michael Hanselmann
1659 e4e35357 Michael Hanselmann
    # Counter for stable sorting
1660 e4e35357 Michael Hanselmann
    self._counter = itertools.count(0)
1661 e4e35357 Michael Hanselmann
1662 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1663 19b9ba9a Michael Hanselmann
    # references and deletion.
1664 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1665 19b9ba9a Michael Hanselmann
1666 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1667 19b9ba9a Michael Hanselmann
  def RegisterLock(self, lock):
1668 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1669 19b9ba9a Michael Hanselmann

1670 19b9ba9a Michael Hanselmann
    """
1671 19b9ba9a Michael Hanselmann
    logging.debug("Registering lock %s", lock.name)
1672 19b9ba9a Michael Hanselmann
    assert lock not in self._locks, "Duplicate lock registration"
1673 e4e35357 Michael Hanselmann
1674 e4e35357 Michael Hanselmann
    # There used to be a check for duplicate names here. As it turned out, when
1675 e4e35357 Michael Hanselmann
    # a lock is re-created with the same name in a very short timeframe, the
1676 e4e35357 Michael Hanselmann
    # previous instance might not yet be removed from the weakref dictionary.
1677 e4e35357 Michael Hanselmann
    # By keeping track of the order of incoming registrations, a stable sort
1678 e4e35357 Michael Hanselmann
    # ordering can still be guaranteed.
1679 e4e35357 Michael Hanselmann
1680 e4e35357 Michael Hanselmann
    self._locks[lock] = self._counter.next()
1681 19b9ba9a Michael Hanselmann
1682 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1683 24d16f76 Michael Hanselmann
  def _GetLockInfo(self, requested):
1684 19b9ba9a Michael Hanselmann
    """Get information from all locks while the monitor lock is held.
1685 19b9ba9a Michael Hanselmann

1686 19b9ba9a Michael Hanselmann
    """
1687 e4e35357 Michael Hanselmann
    return [(num, lock.GetInfo(requested)) for lock, num in self._locks.items()]
1688 19b9ba9a Michael Hanselmann
1689 24d16f76 Michael Hanselmann
  def _Query(self, fields):
1690 24d16f76 Michael Hanselmann
    """Queries information from all locks.
1691 19b9ba9a Michael Hanselmann

1692 24d16f76 Michael Hanselmann
    @type fields: list of strings
1693 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1694 24d16f76 Michael Hanselmann

1695 24d16f76 Michael Hanselmann
    """
1696 24d16f76 Michael Hanselmann
    qobj = query.Query(query.LOCK_FIELDS, fields)
1697 24d16f76 Michael Hanselmann
1698 e4e35357 Michael Hanselmann
    # Get all data with internal lock held and then sort by name and incoming
1699 e4e35357 Michael Hanselmann
    # order
1700 e4e35357 Michael Hanselmann
    lockinfo = sorted(self._GetLockInfo(qobj.RequestedData()),
1701 e4e35357 Michael Hanselmann
                      key=_MonitorSortKey)
1702 24d16f76 Michael Hanselmann
1703 e4e35357 Michael Hanselmann
    # Extract lock information and build query data
1704 e4e35357 Michael Hanselmann
    return (qobj, query.LockQueryData(map(operator.itemgetter(1), lockinfo)))
1705 19b9ba9a Michael Hanselmann
1706 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1707 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1708 19b9ba9a Michael Hanselmann

1709 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1710 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1711 19b9ba9a Michael Hanselmann

1712 19b9ba9a Michael Hanselmann
    """
1713 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1714 19b9ba9a Michael Hanselmann
1715 24d16f76 Michael Hanselmann
    # Prepare query response
1716 24d16f76 Michael Hanselmann
    return query.GetQueryResponse(qobj, ctx)
1717 24d16f76 Michael Hanselmann
1718 24d16f76 Michael Hanselmann
  def OldStyleQueryLocks(self, fields):
1719 24d16f76 Michael Hanselmann
    """Queries information from all locks, returning old-style data.
1720 24d16f76 Michael Hanselmann

1721 24d16f76 Michael Hanselmann
    @type fields: list of strings
1722 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1723 24d16f76 Michael Hanselmann

1724 24d16f76 Michael Hanselmann
    """
1725 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1726 19b9ba9a Michael Hanselmann
1727 24d16f76 Michael Hanselmann
    return qobj.OldStyleQuery(ctx)