Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 93f1e606

History | View | Annotate | Download (60.9 kB)

1 162c1c1f Guido Trotter
#
2 162c1c1f Guido Trotter
#
3 162c1c1f Guido Trotter
4 5ae4945a Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 b459a848 Andrea Spadaccini
# pylint: disable=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 e4e35357 Michael Hanselmann
import itertools
36 8d7d8b57 Michael Hanselmann
import time
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 03c5291c Michael Hanselmann
#: Minimum timeout required to consider scheduling a pending acquisition
51 03c5291c Michael Hanselmann
#: (seconds)
52 03c5291c Michael Hanselmann
_LOCK_ACQUIRE_MIN_TIMEOUT = (1.0 / 1000)
53 03c5291c Michael Hanselmann
54 621b43ed Michael Hanselmann
# Internal lock acquisition modes for L{LockSet}
55 621b43ed Michael Hanselmann
(_LS_ACQUIRE_EXACT,
56 a95c53ea Michael Hanselmann
 _LS_ACQUIRE_ALL,
57 a95c53ea Michael Hanselmann
 _LS_ACQUIRE_OPPORTUNISTIC) = range(1, 4)
58 a95c53ea Michael Hanselmann
59 b8028dcf Michael Hanselmann
_LS_ACQUIRE_MODES = compat.UniqueFrozenset([
60 a95c53ea Michael Hanselmann
  _LS_ACQUIRE_EXACT,
61 a95c53ea Michael Hanselmann
  _LS_ACQUIRE_ALL,
62 a95c53ea Michael Hanselmann
  _LS_ACQUIRE_OPPORTUNISTIC,
63 a95c53ea Michael Hanselmann
  ])
64 621b43ed Michael Hanselmann
65 c31825f7 Michael Hanselmann
66 dbb11e8b Guido Trotter
def ssynchronized(mylock, shared=0):
67 42a999d1 Guido Trotter
  """Shared Synchronization decorator.
68 42a999d1 Guido Trotter

69 42a999d1 Guido Trotter
  Calls the function holding the given lock, either in exclusive or shared
70 42a999d1 Guido Trotter
  mode. It requires the passed lock to be a SharedLock (or support its
71 42a999d1 Guido Trotter
  semantics).
72 42a999d1 Guido Trotter

73 dbb11e8b Guido Trotter
  @type mylock: lockable object or string
74 dbb11e8b Guido Trotter
  @param mylock: lock to acquire or class member name of the lock to acquire
75 dbb11e8b Guido Trotter

76 42a999d1 Guido Trotter
  """
77 42a999d1 Guido Trotter
  def wrap(fn):
78 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
79 dbb11e8b Guido Trotter
      if isinstance(mylock, basestring):
80 dbb11e8b Guido Trotter
        assert args, "cannot ssynchronize on non-class method: self not found"
81 dbb11e8b Guido Trotter
        # args[0] is "self"
82 dbb11e8b Guido Trotter
        lock = getattr(args[0], mylock)
83 dbb11e8b Guido Trotter
      else:
84 dbb11e8b Guido Trotter
        lock = mylock
85 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
86 42a999d1 Guido Trotter
      try:
87 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
88 42a999d1 Guido Trotter
      finally:
89 42a999d1 Guido Trotter
        lock.release()
90 42a999d1 Guido Trotter
    return sync_function
91 42a999d1 Guido Trotter
  return wrap
92 42a999d1 Guido Trotter
93 42a999d1 Guido Trotter
94 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
95 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
96 d76167a5 Michael Hanselmann

97 d76167a5 Michael Hanselmann
  """
98 d76167a5 Michael Hanselmann
  __slots__ = [
99 d76167a5 Michael Hanselmann
    "_fd",
100 d76167a5 Michael Hanselmann
    ]
101 d76167a5 Michael Hanselmann
102 546c5100 Guido Trotter
  def __init__(self, fd):
103 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
104 d76167a5 Michael Hanselmann

105 d76167a5 Michael Hanselmann
    @type fd: int
106 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
107 d76167a5 Michael Hanselmann

108 d76167a5 Michael Hanselmann
    """
109 d76167a5 Michael Hanselmann
    object.__init__(self)
110 d76167a5 Michael Hanselmann
    self._fd = fd
111 d76167a5 Michael Hanselmann
112 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
113 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
114 d76167a5 Michael Hanselmann

115 d76167a5 Michael Hanselmann
    @type timeout: float or None
116 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
117 d76167a5 Michael Hanselmann

118 d76167a5 Michael Hanselmann
    """
119 557838c1 Renรฉ Nussbaumer
    running_timeout = utils.RunningTimeout(timeout, True)
120 546c5100 Guido Trotter
    poller = select.poll()
121 546c5100 Guido Trotter
    poller.register(self._fd, select.POLLHUP)
122 f4e673fb Michael Hanselmann
123 f4e673fb Michael Hanselmann
    while True:
124 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
125 f4e673fb Michael Hanselmann
126 b44b0141 Michael Hanselmann
      if remaining_time is not None:
127 b44b0141 Michael Hanselmann
        if remaining_time < 0.0:
128 b44b0141 Michael Hanselmann
          break
129 d76167a5 Michael Hanselmann
130 413b7472 Michael Hanselmann
        # Our calculation uses seconds, poll() wants milliseconds
131 b44b0141 Michael Hanselmann
        remaining_time *= 1000
132 d76167a5 Michael Hanselmann
133 d76167a5 Michael Hanselmann
      try:
134 546c5100 Guido Trotter
        result = poller.poll(remaining_time)
135 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
136 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
137 d76167a5 Michael Hanselmann
          raise
138 d76167a5 Michael Hanselmann
        result = None
139 d76167a5 Michael Hanselmann
140 d76167a5 Michael Hanselmann
      # Check whether we were notified
141 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
142 d76167a5 Michael Hanselmann
        break
143 d76167a5 Michael Hanselmann
144 d76167a5 Michael Hanselmann
145 2419060d Guido Trotter
class _BaseCondition(object):
146 2419060d Guido Trotter
  """Base class containing common code for conditions.
147 2419060d Guido Trotter

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

150 2419060d Guido Trotter
  """
151 2419060d Guido Trotter
  __slots__ = [
152 2419060d Guido Trotter
    "_lock",
153 2419060d Guido Trotter
    "acquire",
154 2419060d Guido Trotter
    "release",
155 7f890059 Guido Trotter
    "_is_owned",
156 7f890059 Guido Trotter
    "_acquire_restore",
157 7f890059 Guido Trotter
    "_release_save",
158 2419060d Guido Trotter
    ]
159 2419060d Guido Trotter
160 2419060d Guido Trotter
  def __init__(self, lock):
161 2419060d Guido Trotter
    """Constructor for _BaseCondition.
162 2419060d Guido Trotter

163 69b99987 Michael Hanselmann
    @type lock: threading.Lock
164 2419060d Guido Trotter
    @param lock: condition base lock
165 2419060d Guido Trotter

166 2419060d Guido Trotter
    """
167 2419060d Guido Trotter
    object.__init__(self)
168 2419060d Guido Trotter
169 7f890059 Guido Trotter
    try:
170 7f890059 Guido Trotter
      self._release_save = lock._release_save
171 7f890059 Guido Trotter
    except AttributeError:
172 7f890059 Guido Trotter
      self._release_save = self._base_release_save
173 7f890059 Guido Trotter
    try:
174 7f890059 Guido Trotter
      self._acquire_restore = lock._acquire_restore
175 7f890059 Guido Trotter
    except AttributeError:
176 7f890059 Guido Trotter
      self._acquire_restore = self._base_acquire_restore
177 7f890059 Guido Trotter
    try:
178 ee2b99e3 Michael Hanselmann
      self._is_owned = lock.is_owned
179 7f890059 Guido Trotter
    except AttributeError:
180 7f890059 Guido Trotter
      self._is_owned = self._base_is_owned
181 2419060d Guido Trotter
182 2419060d Guido Trotter
    self._lock = lock
183 2419060d Guido Trotter
184 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
185 2419060d Guido Trotter
    self.acquire = lock.acquire
186 2419060d Guido Trotter
    self.release = lock.release
187 2419060d Guido Trotter
188 7f890059 Guido Trotter
  def _base_is_owned(self):
189 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
190 2419060d Guido Trotter

191 2419060d Guido Trotter
    """
192 2419060d Guido Trotter
    if self._lock.acquire(0):
193 2419060d Guido Trotter
      self._lock.release()
194 2419060d Guido Trotter
      return False
195 2419060d Guido Trotter
    return True
196 2419060d Guido Trotter
197 7f890059 Guido Trotter
  def _base_release_save(self):
198 7f890059 Guido Trotter
    self._lock.release()
199 7f890059 Guido Trotter
200 7f890059 Guido Trotter
  def _base_acquire_restore(self, _):
201 7f890059 Guido Trotter
    self._lock.acquire()
202 7f890059 Guido Trotter
203 2419060d Guido Trotter
  def _check_owned(self):
204 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
205 2419060d Guido Trotter

206 2419060d Guido Trotter
    """
207 2419060d Guido Trotter
    if not self._is_owned():
208 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
209 2419060d Guido Trotter
210 2419060d Guido Trotter
211 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
212 34cb5617 Guido Trotter
  """Condition which can only be notified once.
213 d76167a5 Michael Hanselmann

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

220 d76167a5 Michael Hanselmann
  """
221 34cb5617 Guido Trotter
222 154b9580 Balazs Lecz
  __slots__ = [
223 d76167a5 Michael Hanselmann
    "_read_fd",
224 d76167a5 Michael Hanselmann
    "_write_fd",
225 d76167a5 Michael Hanselmann
    "_nwaiters",
226 34cb5617 Guido Trotter
    "_notified",
227 d76167a5 Michael Hanselmann
    ]
228 d76167a5 Michael Hanselmann
229 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
230 d76167a5 Michael Hanselmann
231 34cb5617 Guido Trotter
  def __init__(self, lock):
232 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
233 d76167a5 Michael Hanselmann

234 d76167a5 Michael Hanselmann
    """
235 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
236 d76167a5 Michael Hanselmann
    self._nwaiters = 0
237 34cb5617 Guido Trotter
    self._notified = False
238 34cb5617 Guido Trotter
    self._read_fd = None
239 34cb5617 Guido Trotter
    self._write_fd = None
240 d76167a5 Michael Hanselmann
241 34cb5617 Guido Trotter
  def _check_unnotified(self):
242 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
243 69b99987 Michael Hanselmann

244 69b99987 Michael Hanselmann
    """
245 34cb5617 Guido Trotter
    if self._notified:
246 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
247 d76167a5 Michael Hanselmann
248 34cb5617 Guido Trotter
  def _Cleanup(self):
249 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
250 d76167a5 Michael Hanselmann

251 d76167a5 Michael Hanselmann
    """
252 34cb5617 Guido Trotter
    if self._read_fd is not None:
253 34cb5617 Guido Trotter
      os.close(self._read_fd)
254 34cb5617 Guido Trotter
      self._read_fd = None
255 d76167a5 Michael Hanselmann
256 34cb5617 Guido Trotter
    if self._write_fd is not None:
257 34cb5617 Guido Trotter
      os.close(self._write_fd)
258 34cb5617 Guido Trotter
      self._write_fd = None
259 d76167a5 Michael Hanselmann
260 83f2d5f6 Michael Hanselmann
  def wait(self, timeout):
261 34cb5617 Guido Trotter
    """Wait for a notification.
262 d76167a5 Michael Hanselmann

263 34cb5617 Guido Trotter
    @type timeout: float or None
264 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
265 d76167a5 Michael Hanselmann

266 d76167a5 Michael Hanselmann
    """
267 34cb5617 Guido Trotter
    self._check_owned()
268 34cb5617 Guido Trotter
    self._check_unnotified()
269 d76167a5 Michael Hanselmann
270 34cb5617 Guido Trotter
    self._nwaiters += 1
271 34cb5617 Guido Trotter
    try:
272 546c5100 Guido Trotter
      if self._read_fd is None:
273 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
274 d76167a5 Michael Hanselmann
275 546c5100 Guido Trotter
      wait_fn = self._waiter_class(self._read_fd)
276 7f890059 Guido Trotter
      state = self._release_save()
277 34cb5617 Guido Trotter
      try:
278 34cb5617 Guido Trotter
        # Wait for notification
279 34cb5617 Guido Trotter
        wait_fn(timeout)
280 34cb5617 Guido Trotter
      finally:
281 34cb5617 Guido Trotter
        # Re-acquire lock
282 7f890059 Guido Trotter
        self._acquire_restore(state)
283 34cb5617 Guido Trotter
    finally:
284 34cb5617 Guido Trotter
      self._nwaiters -= 1
285 34cb5617 Guido Trotter
      if self._nwaiters == 0:
286 34cb5617 Guido Trotter
        self._Cleanup()
287 d76167a5 Michael Hanselmann
288 b459a848 Andrea Spadaccini
  def notifyAll(self): # pylint: disable=C0103
289 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
290 d76167a5 Michael Hanselmann

291 d76167a5 Michael Hanselmann
    """
292 34cb5617 Guido Trotter
    self._check_owned()
293 34cb5617 Guido Trotter
    self._check_unnotified()
294 34cb5617 Guido Trotter
    self._notified = True
295 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
296 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
297 d76167a5 Michael Hanselmann
      self._write_fd = None
298 d76167a5 Michael Hanselmann
299 d76167a5 Michael Hanselmann
300 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
301 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
302 48dabc6a Michael Hanselmann

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

309 48dabc6a Michael Hanselmann
  """
310 154b9580 Balazs Lecz
  __slots__ = [
311 c31825f7 Michael Hanselmann
    "_waiters",
312 34cb5617 Guido Trotter
    "_single_condition",
313 48dabc6a Michael Hanselmann
    ]
314 48dabc6a Michael Hanselmann
315 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
316 48dabc6a Michael Hanselmann
317 48dabc6a Michael Hanselmann
  def __init__(self, lock):
318 48dabc6a Michael Hanselmann
    """Initializes this class.
319 48dabc6a Michael Hanselmann

320 48dabc6a Michael Hanselmann
    """
321 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
322 c31825f7 Michael Hanselmann
    self._waiters = set()
323 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
324 48dabc6a Michael Hanselmann
325 83f2d5f6 Michael Hanselmann
  def wait(self, timeout):
326 48dabc6a Michael Hanselmann
    """Wait for a notification.
327 48dabc6a Michael Hanselmann

328 48dabc6a Michael Hanselmann
    @type timeout: float or None
329 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
330 48dabc6a Michael Hanselmann

331 48dabc6a Michael Hanselmann
    """
332 48dabc6a Michael Hanselmann
    self._check_owned()
333 48dabc6a Michael Hanselmann
334 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
335 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
336 c31825f7 Michael Hanselmann
    cond = self._single_condition
337 48dabc6a Michael Hanselmann
338 c31825f7 Michael Hanselmann
    self._waiters.add(threading.currentThread())
339 48dabc6a Michael Hanselmann
    try:
340 c31825f7 Michael Hanselmann
      cond.wait(timeout)
341 48dabc6a Michael Hanselmann
    finally:
342 c31825f7 Michael Hanselmann
      self._check_owned()
343 c31825f7 Michael Hanselmann
      self._waiters.remove(threading.currentThread())
344 48dabc6a Michael Hanselmann
345 b459a848 Andrea Spadaccini
  def notifyAll(self): # pylint: disable=C0103
346 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
347 48dabc6a Michael Hanselmann

348 48dabc6a Michael Hanselmann
    """
349 48dabc6a Michael Hanselmann
    self._check_owned()
350 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
351 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
352 48dabc6a Michael Hanselmann
353 c31825f7 Michael Hanselmann
  def get_waiting(self):
354 c31825f7 Michael Hanselmann
    """Returns a list of all waiting threads.
355 c31825f7 Michael Hanselmann

356 c31825f7 Michael Hanselmann
    """
357 c31825f7 Michael Hanselmann
    self._check_owned()
358 c31825f7 Michael Hanselmann
359 c31825f7 Michael Hanselmann
    return self._waiters
360 c31825f7 Michael Hanselmann
361 48dabc6a Michael Hanselmann
  def has_waiting(self):
362 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
363 48dabc6a Michael Hanselmann

364 48dabc6a Michael Hanselmann
    """
365 48dabc6a Michael Hanselmann
    self._check_owned()
366 48dabc6a Michael Hanselmann
367 c31825f7 Michael Hanselmann
    return bool(self._waiters)
368 48dabc6a Michael Hanselmann
369 20699809 Michael Hanselmann
  def __repr__(self):
370 20699809 Michael Hanselmann
    return ("<%s.%s waiters=%s at %#x>" %
371 20699809 Michael Hanselmann
            (self.__class__.__module__, self.__class__.__name__,
372 20699809 Michael Hanselmann
             self._waiters, id(self)))
373 20699809 Michael Hanselmann
374 48dabc6a Michael Hanselmann
375 887c7aa6 Michael Hanselmann
class _PipeConditionWithMode(PipeCondition):
376 887c7aa6 Michael Hanselmann
  __slots__ = [
377 887c7aa6 Michael Hanselmann
    "shared",
378 887c7aa6 Michael Hanselmann
    ]
379 887c7aa6 Michael Hanselmann
380 887c7aa6 Michael Hanselmann
  def __init__(self, lock, shared):
381 887c7aa6 Michael Hanselmann
    """Initializes this class.
382 887c7aa6 Michael Hanselmann

383 887c7aa6 Michael Hanselmann
    """
384 887c7aa6 Michael Hanselmann
    self.shared = shared
385 887c7aa6 Michael Hanselmann
    PipeCondition.__init__(self, lock)
386 887c7aa6 Michael Hanselmann
387 887c7aa6 Michael Hanselmann
388 84e344d4 Michael Hanselmann
class SharedLock(object):
389 162c1c1f Guido Trotter
  """Implements a shared lock.
390 162c1c1f Guido Trotter

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

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

403 7f93570a Iustin Pop
  @type name: string
404 7f93570a Iustin Pop
  @ivar name: the name of the lock
405 7f93570a Iustin Pop

406 162c1c1f Guido Trotter
  """
407 84e344d4 Michael Hanselmann
  __slots__ = [
408 19b9ba9a Michael Hanselmann
    "__weakref__",
409 84e344d4 Michael Hanselmann
    "__deleted",
410 84e344d4 Michael Hanselmann
    "__exc",
411 84e344d4 Michael Hanselmann
    "__lock",
412 84e344d4 Michael Hanselmann
    "__pending",
413 887c7aa6 Michael Hanselmann
    "__pending_by_prio",
414 887c7aa6 Michael Hanselmann
    "__pending_shared",
415 84e344d4 Michael Hanselmann
    "__shr",
416 8d7d8b57 Michael Hanselmann
    "__time_fn",
417 7f93570a Iustin Pop
    "name",
418 84e344d4 Michael Hanselmann
    ]
419 84e344d4 Michael Hanselmann
420 887c7aa6 Michael Hanselmann
  __condition_class = _PipeConditionWithMode
421 84e344d4 Michael Hanselmann
422 8d7d8b57 Michael Hanselmann
  def __init__(self, name, monitor=None, _time_fn=time.time):
423 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
424 84e344d4 Michael Hanselmann

425 7f93570a Iustin Pop
    @param name: the name of the lock
426 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
427 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register
428 7f93570a Iustin Pop

429 84e344d4 Michael Hanselmann
    """
430 84e344d4 Michael Hanselmann
    object.__init__(self)
431 84e344d4 Michael Hanselmann
432 7f93570a Iustin Pop
    self.name = name
433 7f93570a Iustin Pop
434 8d7d8b57 Michael Hanselmann
    # Used for unittesting
435 8d7d8b57 Michael Hanselmann
    self.__time_fn = _time_fn
436 8d7d8b57 Michael Hanselmann
437 84e344d4 Michael Hanselmann
    # Internal lock
438 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
439 162c1c1f Guido Trotter
440 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
441 84e344d4 Michael Hanselmann
    self.__pending = []
442 887c7aa6 Michael Hanselmann
    self.__pending_by_prio = {}
443 887c7aa6 Michael Hanselmann
    self.__pending_shared = {}
444 84e344d4 Michael Hanselmann
445 84e344d4 Michael Hanselmann
    # Current lock holders
446 162c1c1f Guido Trotter
    self.__shr = set()
447 162c1c1f Guido Trotter
    self.__exc = None
448 162c1c1f Guido Trotter
449 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
450 a95fd5d7 Guido Trotter
    self.__deleted = False
451 a95fd5d7 Guido Trotter
452 19b9ba9a Michael Hanselmann
    # Register with lock monitor
453 19b9ba9a Michael Hanselmann
    if monitor:
454 44b4eddc Michael Hanselmann
      logging.debug("Adding lock %s to monitor", name)
455 19b9ba9a Michael Hanselmann
      monitor.RegisterLock(self)
456 19b9ba9a Michael Hanselmann
457 20699809 Michael Hanselmann
  def __repr__(self):
458 20699809 Michael Hanselmann
    return ("<%s.%s name=%s at %#x>" %
459 20699809 Michael Hanselmann
            (self.__class__.__module__, self.__class__.__name__,
460 20699809 Michael Hanselmann
             self.name, id(self)))
461 20699809 Michael Hanselmann
462 44b4eddc Michael Hanselmann
  def GetLockInfo(self, requested):
463 19b9ba9a Michael Hanselmann
    """Retrieves information for querying locks.
464 19b9ba9a Michael Hanselmann

465 24d16f76 Michael Hanselmann
    @type requested: set
466 24d16f76 Michael Hanselmann
    @param requested: Requested information, see C{query.LQ_*}
467 19b9ba9a Michael Hanselmann

468 19b9ba9a Michael Hanselmann
    """
469 19b9ba9a Michael Hanselmann
    self.__lock.acquire()
470 19b9ba9a Michael Hanselmann
    try:
471 19b9ba9a Michael Hanselmann
      # Note: to avoid unintentional race conditions, no references to
472 19b9ba9a Michael Hanselmann
      # modifiable objects should be returned unless they were created in this
473 19b9ba9a Michael Hanselmann
      # function.
474 24d16f76 Michael Hanselmann
      mode = None
475 24d16f76 Michael Hanselmann
      owner_names = None
476 24d16f76 Michael Hanselmann
477 24d16f76 Michael Hanselmann
      if query.LQ_MODE in requested:
478 24d16f76 Michael Hanselmann
        if self.__deleted:
479 24d16f76 Michael Hanselmann
          mode = _DELETED_TEXT
480 24d16f76 Michael Hanselmann
          assert not (self.__exc or self.__shr)
481 24d16f76 Michael Hanselmann
        elif self.__exc:
482 24d16f76 Michael Hanselmann
          mode = _EXCLUSIVE_TEXT
483 24d16f76 Michael Hanselmann
        elif self.__shr:
484 24d16f76 Michael Hanselmann
          mode = _SHARED_TEXT
485 24d16f76 Michael Hanselmann
486 24d16f76 Michael Hanselmann
      # Current owner(s) are wanted
487 24d16f76 Michael Hanselmann
      if query.LQ_OWNER in requested:
488 24d16f76 Michael Hanselmann
        if self.__exc:
489 24d16f76 Michael Hanselmann
          owner = [self.__exc]
490 19b9ba9a Michael Hanselmann
        else:
491 24d16f76 Michael Hanselmann
          owner = self.__shr
492 24d16f76 Michael Hanselmann
493 24d16f76 Michael Hanselmann
        if owner:
494 24d16f76 Michael Hanselmann
          assert not self.__deleted
495 24d16f76 Michael Hanselmann
          owner_names = [i.getName() for i in owner]
496 19b9ba9a Michael Hanselmann
497 24d16f76 Michael Hanselmann
      # Pending acquires are wanted
498 24d16f76 Michael Hanselmann
      if query.LQ_PENDING in requested:
499 24d16f76 Michael Hanselmann
        pending = []
500 24d16f76 Michael Hanselmann
501 24d16f76 Michael Hanselmann
        # Sorting instead of copying and using heaq functions for simplicity
502 24d16f76 Michael Hanselmann
        for (_, prioqueue) in sorted(self.__pending):
503 24d16f76 Michael Hanselmann
          for cond in prioqueue:
504 24d16f76 Michael Hanselmann
            if cond.shared:
505 24d16f76 Michael Hanselmann
              pendmode = _SHARED_TEXT
506 24d16f76 Michael Hanselmann
            else:
507 24d16f76 Michael Hanselmann
              pendmode = _EXCLUSIVE_TEXT
508 24d16f76 Michael Hanselmann
509 24d16f76 Michael Hanselmann
            # List of names will be sorted in L{query._GetLockPending}
510 24d16f76 Michael Hanselmann
            pending.append((pendmode, [i.getName()
511 24d16f76 Michael Hanselmann
                                       for i in cond.get_waiting()]))
512 24d16f76 Michael Hanselmann
      else:
513 24d16f76 Michael Hanselmann
        pending = None
514 24d16f76 Michael Hanselmann
515 44b4eddc Michael Hanselmann
      return [(self.name, mode, owner_names, pending)]
516 19b9ba9a Michael Hanselmann
    finally:
517 19b9ba9a Michael Hanselmann
      self.__lock.release()
518 19b9ba9a Michael Hanselmann
519 84e344d4 Michael Hanselmann
  def __check_deleted(self):
520 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
521 84e344d4 Michael Hanselmann

522 84e344d4 Michael Hanselmann
    """
523 84e344d4 Michael Hanselmann
    if self.__deleted:
524 7f93570a Iustin Pop
      raise errors.LockError("Deleted lock %s" % self.name)
525 84e344d4 Michael Hanselmann
526 162c1c1f Guido Trotter
  def __is_sharer(self):
527 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
528 84e344d4 Michael Hanselmann

529 84e344d4 Michael Hanselmann
    """
530 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
531 162c1c1f Guido Trotter
532 162c1c1f Guido Trotter
  def __is_exclusive(self):
533 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
534 84e344d4 Michael Hanselmann

535 84e344d4 Michael Hanselmann
    """
536 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
537 162c1c1f Guido Trotter
538 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
539 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
540 162c1c1f Guido Trotter

541 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
542 162c1c1f Guido Trotter
    the internal lock.
543 162c1c1f Guido Trotter

544 162c1c1f Guido Trotter
    """
545 162c1c1f Guido Trotter
    if shared < 0:
546 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
547 162c1c1f Guido Trotter
    elif shared:
548 162c1c1f Guido Trotter
      return self.__is_sharer()
549 162c1c1f Guido Trotter
    else:
550 162c1c1f Guido Trotter
      return self.__is_exclusive()
551 162c1c1f Guido Trotter
552 ee2b99e3 Michael Hanselmann
  def is_owned(self, shared=-1):
553 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
554 162c1c1f Guido Trotter

555 c41eea6e Iustin Pop
    @param shared:
556 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
557 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
558 c41eea6e Iustin Pop
        - > 0: check for shared ownership
559 162c1c1f Guido Trotter

560 162c1c1f Guido Trotter
    """
561 162c1c1f Guido Trotter
    self.__lock.acquire()
562 162c1c1f Guido Trotter
    try:
563 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
564 162c1c1f Guido Trotter
    finally:
565 162c1c1f Guido Trotter
      self.__lock.release()
566 162c1c1f Guido Trotter
567 ee2b99e3 Michael Hanselmann
  #: Necessary to remain compatible with threading.Condition, which tries to
568 ee2b99e3 Michael Hanselmann
  #: retrieve a locks' "_is_owned" attribute
569 ee2b99e3 Michael Hanselmann
  _is_owned = is_owned
570 fdfe88b1 Michael Hanselmann
571 84e344d4 Michael Hanselmann
  def _count_pending(self):
572 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
573 a95fd5d7 Guido Trotter

574 84e344d4 Michael Hanselmann
    @rtype: int
575 a95fd5d7 Guido Trotter

576 a95fd5d7 Guido Trotter
    """
577 84e344d4 Michael Hanselmann
    self.__lock.acquire()
578 84e344d4 Michael Hanselmann
    try:
579 887c7aa6 Michael Hanselmann
      return sum(len(prioqueue) for (_, prioqueue) in self.__pending)
580 887c7aa6 Michael Hanselmann
    finally:
581 887c7aa6 Michael Hanselmann
      self.__lock.release()
582 887c7aa6 Michael Hanselmann
583 887c7aa6 Michael Hanselmann
  def _check_empty(self):
584 887c7aa6 Michael Hanselmann
    """Checks whether there are any pending acquires.
585 887c7aa6 Michael Hanselmann

586 887c7aa6 Michael Hanselmann
    @rtype: bool
587 887c7aa6 Michael Hanselmann

588 887c7aa6 Michael Hanselmann
    """
589 887c7aa6 Michael Hanselmann
    self.__lock.acquire()
590 887c7aa6 Michael Hanselmann
    try:
591 887c7aa6 Michael Hanselmann
      # Order is important: __find_first_pending_queue modifies __pending
592 113359fe Michael Hanselmann
      (_, prioqueue) = self.__find_first_pending_queue()
593 113359fe Michael Hanselmann
594 113359fe Michael Hanselmann
      return not (prioqueue or
595 887c7aa6 Michael Hanselmann
                  self.__pending or
596 887c7aa6 Michael Hanselmann
                  self.__pending_by_prio or
597 887c7aa6 Michael Hanselmann
                  self.__pending_shared)
598 84e344d4 Michael Hanselmann
    finally:
599 84e344d4 Michael Hanselmann
      self.__lock.release()
600 a95fd5d7 Guido Trotter
601 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
602 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
603 84e344d4 Michael Hanselmann

604 84e344d4 Michael Hanselmann
    """
605 84e344d4 Michael Hanselmann
    if shared:
606 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
607 84e344d4 Michael Hanselmann
    else:
608 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
609 a95fd5d7 Guido Trotter
610 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
611 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
612 a95fd5d7 Guido Trotter

613 a95fd5d7 Guido Trotter
    """
614 84e344d4 Michael Hanselmann
    if shared:
615 84e344d4 Michael Hanselmann
      return self.__exc is None
616 84e344d4 Michael Hanselmann
    else:
617 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
618 a95fd5d7 Guido Trotter
619 887c7aa6 Michael Hanselmann
  def __find_first_pending_queue(self):
620 887c7aa6 Michael Hanselmann
    """Tries to find the topmost queued entry with pending acquires.
621 887c7aa6 Michael Hanselmann

622 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
623 887c7aa6 Michael Hanselmann

624 887c7aa6 Michael Hanselmann
    """
625 887c7aa6 Michael Hanselmann
    while self.__pending:
626 887c7aa6 Michael Hanselmann
      (priority, prioqueue) = self.__pending[0]
627 887c7aa6 Michael Hanselmann
628 887c7aa6 Michael Hanselmann
      if prioqueue:
629 113359fe Michael Hanselmann
        return (priority, prioqueue)
630 887c7aa6 Michael Hanselmann
631 113359fe Michael Hanselmann
      # Remove empty queue
632 113359fe Michael Hanselmann
      heapq.heappop(self.__pending)
633 113359fe Michael Hanselmann
      del self.__pending_by_prio[priority]
634 113359fe Michael Hanselmann
      assert priority not in self.__pending_shared
635 113359fe Michael Hanselmann
636 113359fe Michael Hanselmann
    return (None, None)
637 887c7aa6 Michael Hanselmann
638 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
639 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
640 a95fd5d7 Guido Trotter

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

643 84e344d4 Michael Hanselmann
    """
644 113359fe Michael Hanselmann
    (_, prioqueue) = self.__find_first_pending_queue()
645 113359fe Michael Hanselmann
646 113359fe Michael Hanselmann
    return cond == prioqueue[0]
647 4d686df8 Guido Trotter
648 887c7aa6 Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout, priority):
649 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
650 9216a9f7 Michael Hanselmann

651 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
652 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
653 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
654 887c7aa6 Michael Hanselmann
    @type priority: integer
655 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
656 9216a9f7 Michael Hanselmann

657 9216a9f7 Michael Hanselmann
    """
658 84e344d4 Michael Hanselmann
    self.__check_deleted()
659 9216a9f7 Michael Hanselmann
660 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
661 7f93570a Iustin Pop
    assert not self.__is_owned(), ("double acquire() on a non-recursive lock"
662 7f93570a Iustin Pop
                                   " %s" % self.name)
663 84e344d4 Michael Hanselmann
664 887c7aa6 Michael Hanselmann
    # Remove empty entries from queue
665 887c7aa6 Michael Hanselmann
    self.__find_first_pending_queue()
666 887c7aa6 Michael Hanselmann
667 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
668 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
669 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
670 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
671 84e344d4 Michael Hanselmann
      return True
672 9216a9f7 Michael Hanselmann
673 03c5291c Michael Hanselmann
    # The lock couldn't be acquired right away, so if a timeout is given and is
674 03c5291c Michael Hanselmann
    # considered too short, return right away as scheduling a pending
675 03c5291c Michael Hanselmann
    # acquisition is quite expensive
676 03c5291c Michael Hanselmann
    if timeout is not None and timeout < _LOCK_ACQUIRE_MIN_TIMEOUT:
677 03c5291c Michael Hanselmann
      return False
678 03c5291c Michael Hanselmann
679 887c7aa6 Michael Hanselmann
    prioqueue = self.__pending_by_prio.get(priority, None)
680 9216a9f7 Michael Hanselmann
681 887c7aa6 Michael Hanselmann
    if shared:
682 887c7aa6 Michael Hanselmann
      # Try to re-use condition for shared acquire
683 887c7aa6 Michael Hanselmann
      wait_condition = self.__pending_shared.get(priority, None)
684 887c7aa6 Michael Hanselmann
      assert (wait_condition is None or
685 887c7aa6 Michael Hanselmann
              (wait_condition.shared and wait_condition in prioqueue))
686 84e344d4 Michael Hanselmann
    else:
687 887c7aa6 Michael Hanselmann
      wait_condition = None
688 887c7aa6 Michael Hanselmann
689 887c7aa6 Michael Hanselmann
    if wait_condition is None:
690 887c7aa6 Michael Hanselmann
      if prioqueue is None:
691 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_by_prio
692 887c7aa6 Michael Hanselmann
693 887c7aa6 Michael Hanselmann
        prioqueue = []
694 887c7aa6 Michael Hanselmann
        heapq.heappush(self.__pending, (priority, prioqueue))
695 887c7aa6 Michael Hanselmann
        self.__pending_by_prio[priority] = prioqueue
696 887c7aa6 Michael Hanselmann
697 887c7aa6 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock, shared)
698 887c7aa6 Michael Hanselmann
      prioqueue.append(wait_condition)
699 887c7aa6 Michael Hanselmann
700 887c7aa6 Michael Hanselmann
      if shared:
701 887c7aa6 Michael Hanselmann
        # Keep reference for further shared acquires on same priority. This is
702 887c7aa6 Michael Hanselmann
        # better than trying to find it in the list of pending acquires.
703 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_shared
704 887c7aa6 Michael Hanselmann
        self.__pending_shared[priority] = wait_condition
705 84e344d4 Michael Hanselmann
706 8d7d8b57 Michael Hanselmann
    wait_start = self.__time_fn()
707 8d7d8b57 Michael Hanselmann
    acquired = False
708 8d7d8b57 Michael Hanselmann
709 84e344d4 Michael Hanselmann
    try:
710 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
711 84e344d4 Michael Hanselmann
      # expires.
712 8d7d8b57 Michael Hanselmann
      while True:
713 8d7d8b57 Michael Hanselmann
        if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
714 8d7d8b57 Michael Hanselmann
          self.__do_acquire(shared)
715 8d7d8b57 Michael Hanselmann
          acquired = True
716 8d7d8b57 Michael Hanselmann
          break
717 84e344d4 Michael Hanselmann
718 8d7d8b57 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed, therefore we
719 8d7d8b57 Michael Hanselmann
        # can never return False for a blocking acquire
720 8d7d8b57 Michael Hanselmann
        if (timeout is not None and
721 8d7d8b57 Michael Hanselmann
            utils.TimeoutExpired(wait_start, timeout, _time_fn=self.__time_fn)):
722 84e344d4 Michael Hanselmann
          break
723 84e344d4 Michael Hanselmann
724 8d7d8b57 Michael Hanselmann
        # Wait for notification
725 8d7d8b57 Michael Hanselmann
        wait_condition.wait(timeout)
726 8d7d8b57 Michael Hanselmann
        self.__check_deleted()
727 9216a9f7 Michael Hanselmann
    finally:
728 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
729 887c7aa6 Michael Hanselmann
      if not wait_condition.has_waiting():
730 887c7aa6 Michael Hanselmann
        prioqueue.remove(wait_condition)
731 887c7aa6 Michael Hanselmann
        if wait_condition.shared:
732 113359fe Michael Hanselmann
          # Remove from list of shared acquires if it wasn't while releasing
733 113359fe Michael Hanselmann
          # (e.g. on lock deletion)
734 113359fe Michael Hanselmann
          self.__pending_shared.pop(priority, None)
735 9216a9f7 Michael Hanselmann
736 8d7d8b57 Michael Hanselmann
    return acquired
737 9216a9f7 Michael Hanselmann
738 7100c2fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, priority=None,
739 887c7aa6 Michael Hanselmann
              test_notify=None):
740 162c1c1f Guido Trotter
    """Acquire a shared lock.
741 162c1c1f Guido Trotter

742 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
743 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
744 c41eea6e Iustin Pop
        exclusive lock will be acquired
745 84e344d4 Michael Hanselmann
    @type timeout: float
746 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
747 887c7aa6 Michael Hanselmann
    @type priority: integer
748 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
749 008b92fa Michael Hanselmann
    @type test_notify: callable or None
750 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
751 162c1c1f Guido Trotter

752 162c1c1f Guido Trotter
    """
753 7100c2fa Michael Hanselmann
    if priority is None:
754 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
755 7100c2fa Michael Hanselmann
756 162c1c1f Guido Trotter
    self.__lock.acquire()
757 162c1c1f Guido Trotter
    try:
758 008b92fa Michael Hanselmann
      # We already got the lock, notify now
759 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
760 008b92fa Michael Hanselmann
        test_notify()
761 008b92fa Michael Hanselmann
762 887c7aa6 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout, priority)
763 162c1c1f Guido Trotter
    finally:
764 162c1c1f Guido Trotter
      self.__lock.release()
765 162c1c1f Guido Trotter
766 3dbe3ddf Michael Hanselmann
  def downgrade(self):
767 3dbe3ddf Michael Hanselmann
    """Changes the lock mode from exclusive to shared.
768 3dbe3ddf Michael Hanselmann

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

771 3dbe3ddf Michael Hanselmann
    """
772 3dbe3ddf Michael Hanselmann
    self.__lock.acquire()
773 3dbe3ddf Michael Hanselmann
    try:
774 3dbe3ddf Michael Hanselmann
      assert self.__is_owned(), "Lock must be owned"
775 3dbe3ddf Michael Hanselmann
776 3dbe3ddf Michael Hanselmann
      if self.__is_exclusive():
777 3dbe3ddf Michael Hanselmann
        # Do nothing if the lock is already acquired in shared mode
778 3dbe3ddf Michael Hanselmann
        self.__exc = None
779 3dbe3ddf Michael Hanselmann
        self.__do_acquire(1)
780 3dbe3ddf Michael Hanselmann
781 3dbe3ddf Michael Hanselmann
        # Important: pending shared acquires should only jump ahead if there
782 3dbe3ddf Michael Hanselmann
        # was a transition from exclusive to shared, otherwise an owner of a
783 3dbe3ddf Michael Hanselmann
        # shared lock can keep calling this function to push incoming shared
784 3dbe3ddf Michael Hanselmann
        # acquires
785 3dbe3ddf Michael Hanselmann
        (priority, prioqueue) = self.__find_first_pending_queue()
786 3dbe3ddf Michael Hanselmann
        if prioqueue:
787 3dbe3ddf Michael Hanselmann
          # Is there a pending shared acquire on this priority?
788 3dbe3ddf Michael Hanselmann
          cond = self.__pending_shared.pop(priority, None)
789 3dbe3ddf Michael Hanselmann
          if cond:
790 3dbe3ddf Michael Hanselmann
            assert cond.shared
791 3dbe3ddf Michael Hanselmann
            assert cond in prioqueue
792 3dbe3ddf Michael Hanselmann
793 3dbe3ddf Michael Hanselmann
            # Ensure shared acquire is on top of queue
794 3dbe3ddf Michael Hanselmann
            if len(prioqueue) > 1:
795 3dbe3ddf Michael Hanselmann
              prioqueue.remove(cond)
796 3dbe3ddf Michael Hanselmann
              prioqueue.insert(0, cond)
797 3dbe3ddf Michael Hanselmann
798 3dbe3ddf Michael Hanselmann
            # Notify
799 3dbe3ddf Michael Hanselmann
            cond.notifyAll()
800 3dbe3ddf Michael Hanselmann
801 3dbe3ddf Michael Hanselmann
      assert not self.__is_exclusive()
802 3dbe3ddf Michael Hanselmann
      assert self.__is_sharer()
803 3dbe3ddf Michael Hanselmann
804 3dbe3ddf Michael Hanselmann
      return True
805 3dbe3ddf Michael Hanselmann
    finally:
806 3dbe3ddf Michael Hanselmann
      self.__lock.release()
807 3dbe3ddf Michael Hanselmann
808 162c1c1f Guido Trotter
  def release(self):
809 162c1c1f Guido Trotter
    """Release a Shared Lock.
810 162c1c1f Guido Trotter

811 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
812 162c1c1f Guido Trotter
    before calling this function.
813 162c1c1f Guido Trotter

814 162c1c1f Guido Trotter
    """
815 162c1c1f Guido Trotter
    self.__lock.acquire()
816 162c1c1f Guido Trotter
    try:
817 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
818 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
819 84e344d4 Michael Hanselmann
820 162c1c1f Guido Trotter
      # Autodetect release type
821 162c1c1f Guido Trotter
      if self.__is_exclusive():
822 162c1c1f Guido Trotter
        self.__exc = None
823 70567db0 Michael Hanselmann
        notify = True
824 84e344d4 Michael Hanselmann
      else:
825 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
826 70567db0 Michael Hanselmann
        notify = not self.__shr
827 162c1c1f Guido Trotter
828 70567db0 Michael Hanselmann
      # Notify topmost condition in queue if there are no owners left (for
829 70567db0 Michael Hanselmann
      # shared locks)
830 70567db0 Michael Hanselmann
      if notify:
831 70567db0 Michael Hanselmann
        self.__notify_topmost()
832 8d7d8b57 Michael Hanselmann
    finally:
833 8d7d8b57 Michael Hanselmann
      self.__lock.release()
834 8d7d8b57 Michael Hanselmann
835 8d7d8b57 Michael Hanselmann
  def __notify_topmost(self):
836 8d7d8b57 Michael Hanselmann
    """Notifies topmost condition in queue of pending acquires.
837 8d7d8b57 Michael Hanselmann

838 8d7d8b57 Michael Hanselmann
    """
839 8d7d8b57 Michael Hanselmann
    (priority, prioqueue) = self.__find_first_pending_queue()
840 8d7d8b57 Michael Hanselmann
    if prioqueue:
841 8d7d8b57 Michael Hanselmann
      cond = prioqueue[0]
842 8d7d8b57 Michael Hanselmann
      cond.notifyAll()
843 8d7d8b57 Michael Hanselmann
      if cond.shared:
844 8d7d8b57 Michael Hanselmann
        # Prevent further shared acquires from sneaking in while waiters are
845 8d7d8b57 Michael Hanselmann
        # notified
846 8d7d8b57 Michael Hanselmann
        self.__pending_shared.pop(priority, None)
847 8d7d8b57 Michael Hanselmann
848 8d7d8b57 Michael Hanselmann
  def _notify_topmost(self):
849 8d7d8b57 Michael Hanselmann
    """Exported version of L{__notify_topmost}.
850 162c1c1f Guido Trotter

851 8d7d8b57 Michael Hanselmann
    """
852 8d7d8b57 Michael Hanselmann
    self.__lock.acquire()
853 8d7d8b57 Michael Hanselmann
    try:
854 8d7d8b57 Michael Hanselmann
      return self.__notify_topmost()
855 162c1c1f Guido Trotter
    finally:
856 162c1c1f Guido Trotter
      self.__lock.release()
857 162c1c1f Guido Trotter
858 7100c2fa Michael Hanselmann
  def delete(self, timeout=None, priority=None):
859 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
860 a95fd5d7 Guido Trotter

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

865 84e344d4 Michael Hanselmann
    @type timeout: float
866 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
867 887c7aa6 Michael Hanselmann
    @type priority: integer
868 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
869 a95fd5d7 Guido Trotter

870 a95fd5d7 Guido Trotter
    """
871 7100c2fa Michael Hanselmann
    if priority is None:
872 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
873 7100c2fa Michael Hanselmann
874 a95fd5d7 Guido Trotter
    self.__lock.acquire()
875 a95fd5d7 Guido Trotter
    try:
876 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
877 84e344d4 Michael Hanselmann
878 84e344d4 Michael Hanselmann
      self.__check_deleted()
879 a95fd5d7 Guido Trotter
880 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
881 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
882 a95fd5d7 Guido Trotter
883 84e344d4 Michael Hanselmann
      if not acquired:
884 887c7aa6 Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout, priority)
885 a66bd91b Michael Hanselmann
886 26082b7e Michael Hanselmann
      if acquired:
887 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
888 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
889 84e344d4 Michael Hanselmann
890 84e344d4 Michael Hanselmann
        self.__deleted = True
891 84e344d4 Michael Hanselmann
        self.__exc = None
892 a95fd5d7 Guido Trotter
893 19b9ba9a Michael Hanselmann
        assert not (self.__exc or self.__shr), "Found owner during deletion"
894 19b9ba9a Michael Hanselmann
895 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
896 887c7aa6 Michael Hanselmann
        for (_, prioqueue) in self.__pending:
897 887c7aa6 Michael Hanselmann
          for cond in prioqueue:
898 887c7aa6 Michael Hanselmann
            cond.notifyAll()
899 887c7aa6 Michael Hanselmann
900 887c7aa6 Michael Hanselmann
        assert self.__deleted
901 a95fd5d7 Guido Trotter
902 84e344d4 Michael Hanselmann
      return acquired
903 a95fd5d7 Guido Trotter
    finally:
904 a95fd5d7 Guido Trotter
      self.__lock.release()
905 a95fd5d7 Guido Trotter
906 1a4e32d0 Guido Trotter
  def _release_save(self):
907 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
908 1a4e32d0 Guido Trotter
    self.release()
909 1a4e32d0 Guido Trotter
    return shared
910 1a4e32d0 Guido Trotter
911 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
912 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
913 1a4e32d0 Guido Trotter
914 aaae9bc0 Guido Trotter
915 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
916 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
917 e310b019 Guido Trotter
ALL_SET = None
918 e310b019 Guido Trotter
919 e310b019 Guido Trotter
920 a95c53ea Michael Hanselmann
def _TimeoutZero():
921 a95c53ea Michael Hanselmann
  """Returns the number zero.
922 a95c53ea Michael Hanselmann

923 a95c53ea Michael Hanselmann
  """
924 a95c53ea Michael Hanselmann
  return 0
925 a95c53ea Michael Hanselmann
926 a95c53ea Michael Hanselmann
927 a95c53ea Michael Hanselmann
def _GetLsAcquireModeAndTimeouts(want_all, timeout, opportunistic):
928 a95c53ea Michael Hanselmann
  """Determines modes and timeouts for L{LockSet.acquire}.
929 a95c53ea Michael Hanselmann

930 a95c53ea Michael Hanselmann
  @type want_all: boolean
931 a95c53ea Michael Hanselmann
  @param want_all: Whether all locks in set should be acquired
932 a95c53ea Michael Hanselmann
  @param timeout: Timeout in seconds or C{None}
933 a95c53ea Michael Hanselmann
  @param opportunistic: Whther locks should be acquired opportunistically
934 a95c53ea Michael Hanselmann
  @rtype: tuple
935 a95c53ea Michael Hanselmann
  @return: Tuple containing mode to be passed to L{LockSet.__acquire_inner}
936 a95c53ea Michael Hanselmann
    (one of L{_LS_ACQUIRE_MODES}), a function to calculate timeout for
937 a95c53ea Michael Hanselmann
    acquiring the lockset-internal lock (might be C{None}) and a function to
938 a95c53ea Michael Hanselmann
    calculate the timeout for acquiring individual locks
939 a95c53ea Michael Hanselmann

940 a95c53ea Michael Hanselmann
  """
941 a95c53ea Michael Hanselmann
  # Short circuit when no running timeout is needed
942 a95c53ea Michael Hanselmann
  if opportunistic and not want_all:
943 a95c53ea Michael Hanselmann
    assert timeout is None, "Got timeout for an opportunistic acquisition"
944 a95c53ea Michael Hanselmann
    return (_LS_ACQUIRE_OPPORTUNISTIC, None, _TimeoutZero)
945 a95c53ea Michael Hanselmann
946 a95c53ea Michael Hanselmann
  # We need to keep track of how long we spent waiting for a lock. The
947 a95c53ea Michael Hanselmann
  # timeout passed to this function is over all lock acquisitions.
948 a95c53ea Michael Hanselmann
  running_timeout = utils.RunningTimeout(timeout, False)
949 a95c53ea Michael Hanselmann
950 a95c53ea Michael Hanselmann
  if want_all:
951 a95c53ea Michael Hanselmann
    mode = _LS_ACQUIRE_ALL
952 a95c53ea Michael Hanselmann
    ls_timeout_fn = running_timeout.Remaining
953 a95c53ea Michael Hanselmann
  else:
954 a95c53ea Michael Hanselmann
    mode = _LS_ACQUIRE_EXACT
955 a95c53ea Michael Hanselmann
    ls_timeout_fn = None
956 a95c53ea Michael Hanselmann
957 a95c53ea Michael Hanselmann
  if opportunistic:
958 a95c53ea Michael Hanselmann
    mode = _LS_ACQUIRE_OPPORTUNISTIC
959 a95c53ea Michael Hanselmann
    timeout_fn = _TimeoutZero
960 a95c53ea Michael Hanselmann
  else:
961 a95c53ea Michael Hanselmann
    timeout_fn = running_timeout.Remaining
962 a95c53ea Michael Hanselmann
963 a95c53ea Michael Hanselmann
  return (mode, ls_timeout_fn, timeout_fn)
964 a95c53ea Michael Hanselmann
965 a95c53ea Michael Hanselmann
966 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
967 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
968 5aab242c Michael Hanselmann

969 5aab242c Michael Hanselmann
  """
970 5aab242c Michael Hanselmann
971 5aab242c Michael Hanselmann
972 aaae9bc0 Guido Trotter
class LockSet:
973 aaae9bc0 Guido Trotter
  """Implements a set of locks.
974 aaae9bc0 Guido Trotter

975 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
976 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
977 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
978 aaae9bc0 Guido Trotter
  preventing deadlock.
979 aaae9bc0 Guido Trotter

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

982 7f93570a Iustin Pop
  @type name: string
983 7f93570a Iustin Pop
  @ivar name: the name of the lockset
984 7f93570a Iustin Pop

985 aaae9bc0 Guido Trotter
  """
986 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
987 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
988 aaae9bc0 Guido Trotter

989 ec44d893 Guido Trotter
    @type members: list of strings
990 c41eea6e Iustin Pop
    @param members: initial members of the set
991 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
992 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
993 aaae9bc0 Guido Trotter

994 aaae9bc0 Guido Trotter
    """
995 7f93570a Iustin Pop
    assert members is not None, "members parameter is not a list"
996 7f93570a Iustin Pop
    self.name = name
997 7f93570a Iustin Pop
998 19b9ba9a Michael Hanselmann
    # Lock monitor
999 19b9ba9a Michael Hanselmann
    self.__monitor = monitor
1000 19b9ba9a Michael Hanselmann
1001 c307ee34 Michael Hanselmann
    # Used internally to guarantee coherency
1002 c307ee34 Michael Hanselmann
    self.__lock = SharedLock(self._GetLockName("[lockset]"), monitor=monitor)
1003 aaae9bc0 Guido Trotter
1004 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
1005 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
1006 aaae9bc0 Guido Trotter
    self.__lockdict = {}
1007 aaae9bc0 Guido Trotter
1008 7f93570a Iustin Pop
    for mname in members:
1009 19b9ba9a Michael Hanselmann
      self.__lockdict[mname] = SharedLock(self._GetLockName(mname),
1010 19b9ba9a Michael Hanselmann
                                          monitor=monitor)
1011 aaae9bc0 Guido Trotter
1012 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
1013 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
1014 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
1015 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
1016 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
1017 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
1018 aaae9bc0 Guido Trotter
    # will be trouble.
1019 aaae9bc0 Guido Trotter
    self.__owners = {}
1020 aaae9bc0 Guido Trotter
1021 4fb780d1 Michael Hanselmann
  def _GetLockName(self, mname):
1022 4fb780d1 Michael Hanselmann
    """Returns the name for a member lock.
1023 4fb780d1 Michael Hanselmann

1024 4fb780d1 Michael Hanselmann
    """
1025 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
1026 4fb780d1 Michael Hanselmann
1027 3dbe3ddf Michael Hanselmann
  def _get_lock(self):
1028 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock.
1029 3dbe3ddf Michael Hanselmann

1030 3dbe3ddf Michael Hanselmann
    """
1031 3dbe3ddf Michael Hanselmann
    return self.__lock
1032 3dbe3ddf Michael Hanselmann
1033 3dbe3ddf Michael Hanselmann
  def _get_lockdict(self):
1034 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock dictionary.
1035 3dbe3ddf Michael Hanselmann

1036 3dbe3ddf Michael Hanselmann
    Accessing this structure is only safe in single-thread usage or when the
1037 3dbe3ddf Michael Hanselmann
    lockset-internal lock is held.
1038 3dbe3ddf Michael Hanselmann

1039 3dbe3ddf Michael Hanselmann
    """
1040 3dbe3ddf Michael Hanselmann
    return self.__lockdict
1041 3dbe3ddf Michael Hanselmann
1042 ee2b99e3 Michael Hanselmann
  def is_owned(self):
1043 c6a622cf Michael Hanselmann
    """Is the current thread a current level owner?
1044 c6a622cf Michael Hanselmann

1045 c6a622cf Michael Hanselmann
    @note: Use L{check_owned} to check if a specific lock is held
1046 c6a622cf Michael Hanselmann

1047 c6a622cf Michael Hanselmann
    """
1048 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
1049 aaae9bc0 Guido Trotter
1050 c6a622cf Michael Hanselmann
  def check_owned(self, names, shared=-1):
1051 c6a622cf Michael Hanselmann
    """Check if locks are owned in a specific mode.
1052 c6a622cf Michael Hanselmann

1053 c6a622cf Michael Hanselmann
    @type names: sequence or string
1054 c6a622cf Michael Hanselmann
    @param names: Lock names (or a single lock name)
1055 c6a622cf Michael Hanselmann
    @param shared: See L{SharedLock.is_owned}
1056 c6a622cf Michael Hanselmann
    @rtype: bool
1057 c6a622cf Michael Hanselmann
    @note: Use L{is_owned} to check if the current thread holds I{any} lock and
1058 c6a622cf Michael Hanselmann
      L{list_owned} to get the names of all owned locks
1059 c6a622cf Michael Hanselmann

1060 c6a622cf Michael Hanselmann
    """
1061 c6a622cf Michael Hanselmann
    if isinstance(names, basestring):
1062 c6a622cf Michael Hanselmann
      names = [names]
1063 c6a622cf Michael Hanselmann
1064 c6a622cf Michael Hanselmann
    # Avoid check if no locks are owned anyway
1065 c6a622cf Michael Hanselmann
    if names and self.is_owned():
1066 c6a622cf Michael Hanselmann
      candidates = []
1067 c6a622cf Michael Hanselmann
1068 c6a622cf Michael Hanselmann
      # Gather references to all locks (in case they're deleted in the meantime)
1069 c6a622cf Michael Hanselmann
      for lname in names:
1070 c6a622cf Michael Hanselmann
        try:
1071 c6a622cf Michael Hanselmann
          lock = self.__lockdict[lname]
1072 c6a622cf Michael Hanselmann
        except KeyError:
1073 c6a622cf Michael Hanselmann
          raise errors.LockError("Non-existing lock '%s' in set '%s' (it may"
1074 c6a622cf Michael Hanselmann
                                 " have been removed)" % (lname, self.name))
1075 c6a622cf Michael Hanselmann
        else:
1076 c6a622cf Michael Hanselmann
          candidates.append(lock)
1077 c6a622cf Michael Hanselmann
1078 c6a622cf Michael Hanselmann
      return compat.all(lock.is_owned(shared=shared) for lock in candidates)
1079 c6a622cf Michael Hanselmann
    else:
1080 c6a622cf Michael Hanselmann
      return False
1081 c6a622cf Michael Hanselmann
1082 8c811986 Michael Hanselmann
  def owning_all(self):
1083 8c811986 Michael Hanselmann
    """Checks whether current thread owns internal lock.
1084 8c811986 Michael Hanselmann

1085 8c811986 Michael Hanselmann
    Holding the internal lock is equivalent with holding all locks in the set
1086 8c811986 Michael Hanselmann
    (the opposite does not necessarily hold as it can not be easily
1087 8c811986 Michael Hanselmann
    determined). L{add} and L{remove} require the internal lock.
1088 8c811986 Michael Hanselmann

1089 8c811986 Michael Hanselmann
    @rtype: boolean
1090 8c811986 Michael Hanselmann

1091 8c811986 Michael Hanselmann
    """
1092 8c811986 Michael Hanselmann
    return self.__lock.is_owned()
1093 8c811986 Michael Hanselmann
1094 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
1095 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
1096 b2dabfd6 Guido Trotter
    if name is None:
1097 ee2b99e3 Michael Hanselmann
      if not self.is_owned():
1098 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
1099 aaae9bc0 Guido Trotter
    else:
1100 ee2b99e3 Michael Hanselmann
      if self.is_owned():
1101 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
1102 b2dabfd6 Guido Trotter
      else:
1103 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
1104 b2dabfd6 Guido Trotter
1105 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
1106 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
1107 aaae9bc0 Guido Trotter
1108 ee2b99e3 Michael Hanselmann
    assert not (name is None and self.__lock.is_owned()), \
1109 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
1110 e4335b5b Michael Hanselmann
1111 b2dabfd6 Guido Trotter
    if name is not None:
1112 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
1113 b2dabfd6 Guido Trotter
1114 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
1115 dc6296ff Michael Hanselmann
    if not (self.__lock.is_owned() or
1116 dc6296ff Michael Hanselmann
            self.__owners[threading.currentThread()]):
1117 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
1118 aaae9bc0 Guido Trotter
1119 ee2b99e3 Michael Hanselmann
  def list_owned(self):
1120 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
1121 ee2b99e3 Michael Hanselmann
    if self.is_owned():
1122 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
1123 aaae9bc0 Guido Trotter
    else:
1124 aaae9bc0 Guido Trotter
      return set()
1125 aaae9bc0 Guido Trotter
1126 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
1127 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
1128 ee2b99e3 Michael Hanselmann
    for lname in self.list_owned():
1129 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
1130 ee2b99e3 Michael Hanselmann
      if lock.is_owned():
1131 56452af7 Michael Hanselmann
        lock.release()
1132 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
1133 5aab242c Michael Hanselmann
1134 aaae9bc0 Guido Trotter
  def __names(self):
1135 aaae9bc0 Guido Trotter
    """Return the current set of names.
1136 aaae9bc0 Guido Trotter

1137 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
1138 aaae9bc0 Guido Trotter
    result after releasing the lock.
1139 aaae9bc0 Guido Trotter

1140 aaae9bc0 Guido Trotter
    """
1141 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
1142 aaae9bc0 Guido Trotter
1143 aaae9bc0 Guido Trotter
  def _names(self):
1144 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
1145 aaae9bc0 Guido Trotter

1146 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
1147 cdb08f44 Michael Hanselmann

1148 aaae9bc0 Guido Trotter
    """
1149 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
1150 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
1151 d4803c24 Guido Trotter
    release_lock = False
1152 ee2b99e3 Michael Hanselmann
    if not self.__lock.is_owned():
1153 d4803c24 Guido Trotter
      release_lock = True
1154 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
1155 aaae9bc0 Guido Trotter
    try:
1156 aaae9bc0 Guido Trotter
      result = self.__names()
1157 aaae9bc0 Guido Trotter
    finally:
1158 d4803c24 Guido Trotter
      if release_lock:
1159 d4803c24 Guido Trotter
        self.__lock.release()
1160 0cf257c5 Guido Trotter
    return set(result)
1161 aaae9bc0 Guido Trotter
1162 7100c2fa Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, priority=None,
1163 a95c53ea Michael Hanselmann
              opportunistic=False, test_notify=None):
1164 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
1165 aaae9bc0 Guido Trotter

1166 a95c53ea Michael Hanselmann
    @note: When acquiring locks opportunistically, any number of locks might
1167 a95c53ea Michael Hanselmann
      actually be acquired, even zero.
1168 a95c53ea Michael Hanselmann

1169 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1170 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1171 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1172 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1173 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
1174 c41eea6e Iustin Pop
        exclusive lock will be acquired
1175 5aab242c Michael Hanselmann
    @type timeout: float or None
1176 a95c53ea Michael Hanselmann
    @param timeout: Maximum time to acquire all locks; for opportunistic
1177 a95c53ea Michael Hanselmann
      acquisitions, a timeout can only be given when C{names} is C{None}, in
1178 a95c53ea Michael Hanselmann
      which case it is exclusively used for acquiring the L{LockSet}-internal
1179 a95c53ea Michael Hanselmann
      lock; opportunistic acquisitions don't use a timeout for acquiring
1180 a95c53ea Michael Hanselmann
      individual locks
1181 887c7aa6 Michael Hanselmann
    @type priority: integer
1182 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1183 a95c53ea Michael Hanselmann
    @type opportunistic: boolean
1184 a95c53ea Michael Hanselmann
    @param opportunistic: Acquire locks opportunistically; use the return value
1185 a95c53ea Michael Hanselmann
      to determine which locks were actually acquired
1186 5aab242c Michael Hanselmann
    @type test_notify: callable or None
1187 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1188 aaae9bc0 Guido Trotter

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

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

1195 aaae9bc0 Guido Trotter
    """
1196 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
1197 aaae9bc0 Guido Trotter
1198 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
1199 ee2b99e3 Michael Hanselmann
    assert not self.is_owned(), ("Cannot acquire locks in the same set twice"
1200 ee2b99e3 Michael Hanselmann
                                 " (lockset %s)" % self.name)
1201 aaae9bc0 Guido Trotter
1202 7100c2fa Michael Hanselmann
    if priority is None:
1203 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
1204 7100c2fa Michael Hanselmann
1205 806e20fd Guido Trotter
    try:
1206 76e2f08a Michael Hanselmann
      if names is not None:
1207 a95c53ea Michael Hanselmann
        assert timeout is None or not opportunistic, \
1208 a95c53ea Michael Hanselmann
          ("Opportunistic acquisitions can only use a timeout if no"
1209 a95c53ea Michael Hanselmann
           " names are given; see docstring for details")
1210 a95c53ea Michael Hanselmann
1211 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
1212 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
1213 5aab242c Michael Hanselmann
          names = [names]
1214 5aab242c Michael Hanselmann
1215 a95c53ea Michael Hanselmann
        (mode, _, timeout_fn) = \
1216 a95c53ea Michael Hanselmann
          _GetLsAcquireModeAndTimeouts(False, timeout, opportunistic)
1217 a95c53ea Michael Hanselmann
1218 a95c53ea Michael Hanselmann
        return self.__acquire_inner(names, mode, shared, priority,
1219 a95c53ea Michael Hanselmann
                                    timeout_fn, test_notify)
1220 76e2f08a Michael Hanselmann
1221 76e2f08a Michael Hanselmann
      else:
1222 a95c53ea Michael Hanselmann
        (mode, ls_timeout_fn, timeout_fn) = \
1223 a95c53ea Michael Hanselmann
          _GetLsAcquireModeAndTimeouts(True, timeout, opportunistic)
1224 a95c53ea Michael Hanselmann
1225 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
1226 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
1227 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
1228 76e2f08a Michael Hanselmann
        #
1229 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
1230 887c7aa6 Michael Hanselmann
        # everybody else can use the instances at the same time. If we are
1231 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
1232 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
1233 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
1234 887c7aa6 Michael Hanselmann
        if not self.__lock.acquire(shared=shared, priority=priority,
1235 a95c53ea Michael Hanselmann
                                   timeout=ls_timeout_fn()):
1236 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1237 a95c53ea Michael Hanselmann
1238 76e2f08a Michael Hanselmann
        try:
1239 76e2f08a Michael Hanselmann
          # note we own the set-lock
1240 76e2f08a Michael Hanselmann
          self._add_owned()
1241 76e2f08a Michael Hanselmann
1242 a95c53ea Michael Hanselmann
          return self.__acquire_inner(self.__names(), mode, shared,
1243 a95c53ea Michael Hanselmann
                                      priority, timeout_fn, test_notify)
1244 76e2f08a Michael Hanselmann
        except:
1245 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1246 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1247 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
1248 5aab242c Michael Hanselmann
          self.__lock.release()
1249 76e2f08a Michael Hanselmann
          self._del_owned()
1250 76e2f08a Michael Hanselmann
          raise
1251 5aab242c Michael Hanselmann
1252 5aab242c Michael Hanselmann
    except _AcquireTimeout:
1253 5aab242c Michael Hanselmann
      return None
1254 aaae9bc0 Guido Trotter
1255 621b43ed Michael Hanselmann
  def __acquire_inner(self, names, mode, shared, priority,
1256 887c7aa6 Michael Hanselmann
                      timeout_fn, test_notify):
1257 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
1258 7e8841bd Michael Hanselmann

1259 a95c53ea Michael Hanselmann
    Acquisition modes:
1260 a95c53ea Michael Hanselmann

1261 a95c53ea Michael Hanselmann
      - C{_LS_ACQUIRE_ALL}: C{names} contains names of all locks in set, but
1262 a95c53ea Michael Hanselmann
        deleted locks can be ignored as the whole set is being acquired with
1263 a95c53ea Michael Hanselmann
        its internal lock held
1264 a95c53ea Michael Hanselmann
      - C{_LS_ACQUIRE_EXACT}: The names listed in C{names} must be acquired;
1265 a95c53ea Michael Hanselmann
        timeouts and deleted locks are fatal
1266 a95c53ea Michael Hanselmann
      - C{_LS_ACQUIRE_OPPORTUNISTIC}: C{names} lists names of locks (potentially
1267 a95c53ea Michael Hanselmann
        all within the set) which should be acquired opportunistically, that is
1268 a95c53ea Michael Hanselmann
        failures are ignored
1269 a95c53ea Michael Hanselmann

1270 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
1271 a95c53ea Michael Hanselmann
    @param mode: Lock acquisition mode (one of L{_LS_ACQUIRE_MODES})
1272 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
1273 a95c53ea Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout (C{None} for
1274 a95c53ea Michael Hanselmann
      opportunistic acquisitions)
1275 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1276 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1277 76e2f08a Michael Hanselmann

1278 76e2f08a Michael Hanselmann
    """
1279 a95c53ea Michael Hanselmann
    assert mode in _LS_ACQUIRE_MODES
1280 621b43ed Michael Hanselmann
1281 76e2f08a Michael Hanselmann
    acquire_list = []
1282 76e2f08a Michael Hanselmann
1283 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
1284 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
1285 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
1286 71e1863e Michael Hanselmann
    # deadlocks.
1287 a13d34a6 Michael Hanselmann
    for lname in sorted(frozenset(names)):
1288 76e2f08a Michael Hanselmann
      try:
1289 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
1290 76e2f08a Michael Hanselmann
      except KeyError:
1291 621b43ed Michael Hanselmann
        # We are acquiring the whole set, it doesn't matter if this particular
1292 621b43ed Michael Hanselmann
        # element is not there anymore. If, however, only certain names should
1293 621b43ed Michael Hanselmann
        # be acquired, not finding a lock is an error.
1294 621b43ed Michael Hanselmann
        if mode == _LS_ACQUIRE_EXACT:
1295 621b43ed Michael Hanselmann
          raise errors.LockError("Lock '%s' not found in set '%s' (it may have"
1296 621b43ed Michael Hanselmann
                                 " been removed)" % (lname, self.name))
1297 621b43ed Michael Hanselmann
      else:
1298 621b43ed Michael Hanselmann
        acquire_list.append((lname, lock))
1299 9b154270 Michael Hanselmann
1300 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
1301 76e2f08a Michael Hanselmann
    acquired = set()
1302 76e2f08a Michael Hanselmann
1303 76e2f08a Michael Hanselmann
    try:
1304 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
1305 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
1306 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
1307 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
1308 76e2f08a Michael Hanselmann
      # lock gets deleted.
1309 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
1310 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
1311 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
1312 76e2f08a Michael Hanselmann
        else:
1313 76e2f08a Michael Hanselmann
          test_notify_fn = None
1314 76e2f08a Michael Hanselmann
1315 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
1316 76e2f08a Michael Hanselmann
1317 76e2f08a Michael Hanselmann
        try:
1318 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
1319 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
1320 887c7aa6 Michael Hanselmann
                                     priority=priority,
1321 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
1322 76e2f08a Michael Hanselmann
        except errors.LockError:
1323 a95c53ea Michael Hanselmann
          if mode in (_LS_ACQUIRE_ALL, _LS_ACQUIRE_OPPORTUNISTIC):
1324 621b43ed Michael Hanselmann
            # We are acquiring the whole set, it doesn't matter if this
1325 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
1326 76e2f08a Michael Hanselmann
            continue
1327 76e2f08a Michael Hanselmann
1328 621b43ed Michael Hanselmann
          raise errors.LockError("Lock '%s' not found in set '%s' (it may have"
1329 621b43ed Michael Hanselmann
                                 " been removed)" % (lname, self.name))
1330 76e2f08a Michael Hanselmann
1331 76e2f08a Michael Hanselmann
        if not acq_success:
1332 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
1333 a95c53ea Michael Hanselmann
          if mode == _LS_ACQUIRE_OPPORTUNISTIC:
1334 a95c53ea Michael Hanselmann
            # Ignore timeouts on opportunistic acquisitions
1335 a95c53ea Michael Hanselmann
            continue
1336 a95c53ea Michael Hanselmann
1337 76e2f08a Michael Hanselmann
          if timeout is None:
1338 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
1339 76e2f08a Michael Hanselmann
            # blocking.
1340 7f93570a Iustin Pop
            raise errors.LockError("Failed to get lock %s (set %s)" %
1341 7f93570a Iustin Pop
                                   (lname, self.name))
1342 76e2f08a Michael Hanselmann
1343 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1344 76e2f08a Michael Hanselmann
1345 76e2f08a Michael Hanselmann
        try:
1346 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
1347 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
1348 76e2f08a Michael Hanselmann
          acquired.add(lname)
1349 76e2f08a Michael Hanselmann
1350 76e2f08a Michael Hanselmann
        except:
1351 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1352 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1353 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
1354 ee2b99e3 Michael Hanselmann
          if lock.is_owned():
1355 76e2f08a Michael Hanselmann
            lock.release()
1356 76e2f08a Michael Hanselmann
          raise
1357 76e2f08a Michael Hanselmann
1358 76e2f08a Michael Hanselmann
    except:
1359 76e2f08a Michael Hanselmann
      # Release all owned locks
1360 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
1361 76e2f08a Michael Hanselmann
      raise
1362 76e2f08a Michael Hanselmann
1363 0cc00929 Guido Trotter
    return acquired
1364 aaae9bc0 Guido Trotter
1365 3dbe3ddf Michael Hanselmann
  def downgrade(self, names=None):
1366 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1367 3dbe3ddf Michael Hanselmann

1368 3dbe3ddf Michael Hanselmann
    The locks must have been acquired in exclusive mode.
1369 3dbe3ddf Michael Hanselmann

1370 3dbe3ddf Michael Hanselmann
    """
1371 ee2b99e3 Michael Hanselmann
    assert self.is_owned(), ("downgrade on lockset %s while not owning any"
1372 ee2b99e3 Michael Hanselmann
                             " lock" % self.name)
1373 3dbe3ddf Michael Hanselmann
1374 3dbe3ddf Michael Hanselmann
    # Support passing in a single resource to downgrade rather than many
1375 3dbe3ddf Michael Hanselmann
    if isinstance(names, basestring):
1376 3dbe3ddf Michael Hanselmann
      names = [names]
1377 3dbe3ddf Michael Hanselmann
1378 ee2b99e3 Michael Hanselmann
    owned = self.list_owned()
1379 3dbe3ddf Michael Hanselmann
1380 3dbe3ddf Michael Hanselmann
    if names is None:
1381 3dbe3ddf Michael Hanselmann
      names = owned
1382 3dbe3ddf Michael Hanselmann
    else:
1383 3dbe3ddf Michael Hanselmann
      names = set(names)
1384 3dbe3ddf Michael Hanselmann
      assert owned.issuperset(names), \
1385 3dbe3ddf Michael Hanselmann
        ("downgrade() on unheld resources %s (set %s)" %
1386 3dbe3ddf Michael Hanselmann
         (names.difference(owned), self.name))
1387 3dbe3ddf Michael Hanselmann
1388 3dbe3ddf Michael Hanselmann
    for lockname in names:
1389 3dbe3ddf Michael Hanselmann
      self.__lockdict[lockname].downgrade()
1390 3dbe3ddf Michael Hanselmann
1391 3dbe3ddf Michael Hanselmann
    # Do we own the lockset in exclusive mode?
1392 ee2b99e3 Michael Hanselmann
    if self.__lock.is_owned(shared=0):
1393 3dbe3ddf Michael Hanselmann
      # Have all locks been downgraded?
1394 ee2b99e3 Michael Hanselmann
      if not compat.any(lock.is_owned(shared=0)
1395 3dbe3ddf Michael Hanselmann
                        for lock in self.__lockdict.values()):
1396 3dbe3ddf Michael Hanselmann
        self.__lock.downgrade()
1397 ee2b99e3 Michael Hanselmann
        assert self.__lock.is_owned(shared=1)
1398 3dbe3ddf Michael Hanselmann
1399 3dbe3ddf Michael Hanselmann
    return True
1400 3dbe3ddf Michael Hanselmann
1401 aaae9bc0 Guido Trotter
  def release(self, names=None):
1402 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
1403 aaae9bc0 Guido Trotter

1404 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1405 aaae9bc0 Guido Trotter
    before releasing them.
1406 aaae9bc0 Guido Trotter

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

1411 aaae9bc0 Guido Trotter
    """
1412 ee2b99e3 Michael Hanselmann
    assert self.is_owned(), ("release() on lock set %s while not owner" %
1413 ee2b99e3 Michael Hanselmann
                             self.name)
1414 aaae9bc0 Guido Trotter
1415 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1416 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1417 aaae9bc0 Guido Trotter
      names = [names]
1418 aaae9bc0 Guido Trotter
1419 aaae9bc0 Guido Trotter
    if names is None:
1420 ee2b99e3 Michael Hanselmann
      names = self.list_owned()
1421 aaae9bc0 Guido Trotter
    else:
1422 aaae9bc0 Guido Trotter
      names = set(names)
1423 ee2b99e3 Michael Hanselmann
      assert self.list_owned().issuperset(names), (
1424 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1425 ee2b99e3 Michael Hanselmann
               (names.difference(self.list_owned()), self.name))
1426 aaae9bc0 Guido Trotter
1427 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1428 3b7ed473 Guido Trotter
    # After this 'add' can work again
1429 ee2b99e3 Michael Hanselmann
    if self.__lock.is_owned():
1430 3b7ed473 Guido Trotter
      self.__lock.release()
1431 b2dabfd6 Guido Trotter
      self._del_owned()
1432 3b7ed473 Guido Trotter
1433 aaae9bc0 Guido Trotter
    for lockname in names:
1434 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1435 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1436 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1437 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1438 aaae9bc0 Guido Trotter
1439 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1440 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1441 aaae9bc0 Guido Trotter

1442 ec44d893 Guido Trotter
    @type names: list of strings
1443 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1444 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1445 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1446 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1447 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1448 aaae9bc0 Guido Trotter

1449 aaae9bc0 Guido Trotter
    """
1450 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1451 ee2b99e3 Michael Hanselmann
    assert not self.is_owned() or self.__lock.is_owned(shared=0), \
1452 7f93570a Iustin Pop
      ("Cannot add locks if the set %s is only partially owned, or shared" %
1453 7f93570a Iustin Pop
       self.name)
1454 3b7ed473 Guido Trotter
1455 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1456 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1457 aaae9bc0 Guido Trotter
      names = [names]
1458 aaae9bc0 Guido Trotter
1459 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1460 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1461 3b7ed473 Guido Trotter
    release_lock = False
1462 ee2b99e3 Michael Hanselmann
    if not self.__lock.is_owned():
1463 3b7ed473 Guido Trotter
      release_lock = True
1464 3b7ed473 Guido Trotter
      self.__lock.acquire()
1465 3b7ed473 Guido Trotter
1466 aaae9bc0 Guido Trotter
    try:
1467 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1468 aaae9bc0 Guido Trotter
      if invalid_names:
1469 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1470 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1471 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1472 7f93570a Iustin Pop
        raise errors.LockError("duplicate add(%s) on lockset %s" %
1473 7f93570a Iustin Pop
                               (invalid_names, self.name))
1474 aaae9bc0 Guido Trotter
1475 aaae9bc0 Guido Trotter
      for lockname in names:
1476 19b9ba9a Michael Hanselmann
        lock = SharedLock(self._GetLockName(lockname), monitor=self.__monitor)
1477 aaae9bc0 Guido Trotter
1478 aaae9bc0 Guido Trotter
        if acquired:
1479 887c7aa6 Michael Hanselmann
          # No need for priority or timeout here as this lock has just been
1480 887c7aa6 Michael Hanselmann
          # created
1481 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1482 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1483 aaae9bc0 Guido Trotter
          try:
1484 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1485 aaae9bc0 Guido Trotter
          except:
1486 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1487 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1488 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1489 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1490 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1491 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1492 aaae9bc0 Guido Trotter
            lock.release()
1493 aaae9bc0 Guido Trotter
            raise
1494 aaae9bc0 Guido Trotter
1495 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1496 aaae9bc0 Guido Trotter
1497 aaae9bc0 Guido Trotter
    finally:
1498 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1499 3b7ed473 Guido Trotter
      if release_lock:
1500 3b7ed473 Guido Trotter
        self.__lock.release()
1501 aaae9bc0 Guido Trotter
1502 aaae9bc0 Guido Trotter
    return True
1503 aaae9bc0 Guido Trotter
1504 5e0a6daf Michael Hanselmann
  def remove(self, names):
1505 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1506 aaae9bc0 Guido Trotter

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

1510 ec44d893 Guido Trotter
    @type names: list of strings
1511 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1512 aaae9bc0 Guido Trotter

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

1517 aaae9bc0 Guido Trotter
    """
1518 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1519 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1520 aaae9bc0 Guido Trotter
      names = [names]
1521 aaae9bc0 Guido Trotter
1522 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1523 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1524 aaae9bc0 Guido Trotter
    # by the lock itself.
1525 ee2b99e3 Michael Hanselmann
    assert not self.is_owned() or self.list_owned().issuperset(names), (
1526 7f93570a Iustin Pop
      "remove() on acquired lockset %s while not owning all elements" %
1527 7f93570a Iustin Pop
      self.name)
1528 aaae9bc0 Guido Trotter
1529 3f404fc5 Guido Trotter
    removed = []
1530 aaae9bc0 Guido Trotter
1531 aaae9bc0 Guido Trotter
    for lname in names:
1532 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1533 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1534 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1535 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1536 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1537 aaae9bc0 Guido Trotter
      try:
1538 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1539 3f404fc5 Guido Trotter
        removed.append(lname)
1540 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1541 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1542 ee2b99e3 Michael Hanselmann
        assert not self.is_owned(), ("remove failed while holding lockset %s" %
1543 ee2b99e3 Michael Hanselmann
                                     self.name)
1544 aaae9bc0 Guido Trotter
      else:
1545 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1546 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1547 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1548 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1549 aaae9bc0 Guido Trotter
        #
1550 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1551 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1552 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1553 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1554 ee2b99e3 Michael Hanselmann
        if self.is_owned():
1555 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1556 aaae9bc0 Guido Trotter
1557 3f404fc5 Guido Trotter
    return removed
1558 aaae9bc0 Guido Trotter
1559 7ee7c0c7 Guido Trotter
1560 8716b1db Michael Hanselmann
# Locking levels, must be acquired in increasing order. Current rules are:
1561 8716b1db Michael Hanselmann
# - At level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1562 8716b1db Michael Hanselmann
#   acquired before performing any operation, either in shared or exclusive
1563 8716b1db Michael Hanselmann
#   mode. Acquiring the BGL in exclusive mode is discouraged and should be
1564 8716b1db Michael Hanselmann
#   avoided..
1565 8716b1db Michael Hanselmann
# - At levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks. If
1566 8716b1db Michael Hanselmann
#   you need more than one node, or more than one instance, acquire them at the
1567 8716b1db Michael Hanselmann
#   same time.
1568 8716b1db Michael Hanselmann
# - LEVEL_NODE_RES is for node resources and should be used by operations with
1569 8716b1db Michael Hanselmann
#   possibly high impact on the node's disks.
1570 8716b1db Michael Hanselmann
# - LEVEL_NODE_ALLOC blocks instance allocations for the whole cluster
1571 8716b1db Michael Hanselmann
#   ("NAL" is the only lock at this level). It should be acquired in shared
1572 8716b1db Michael Hanselmann
#   mode when an opcode blocks all or a significant amount of a cluster's
1573 8716b1db Michael Hanselmann
#   locks. Opcodes doing instance allocations should acquire in exclusive mode.
1574 8716b1db Michael Hanselmann
#   Once the set of acquired locks for an opcode has been reduced to the working
1575 8716b1db Michael Hanselmann
#   set, the NAL should be released as well to allow allocations to proceed.
1576 8716b1db Michael Hanselmann
(LEVEL_CLUSTER,
1577 8716b1db Michael Hanselmann
 LEVEL_INSTANCE,
1578 48aaca91 Michael Hanselmann
 LEVEL_NODE_ALLOC,
1579 8716b1db Michael Hanselmann
 LEVEL_NODEGROUP,
1580 8716b1db Michael Hanselmann
 LEVEL_NODE,
1581 8716b1db Michael Hanselmann
 LEVEL_NODE_RES,
1582 8716b1db Michael Hanselmann
 LEVEL_NETWORK) = range(0, 7)
1583 7ee7c0c7 Guido Trotter
1584 4e070776 Michael Hanselmann
LEVELS = [
1585 4e070776 Michael Hanselmann
  LEVEL_CLUSTER,
1586 4e070776 Michael Hanselmann
  LEVEL_INSTANCE,
1587 48aaca91 Michael Hanselmann
  LEVEL_NODE_ALLOC,
1588 4e070776 Michael Hanselmann
  LEVEL_NODEGROUP,
1589 4e070776 Michael Hanselmann
  LEVEL_NODE,
1590 4e070776 Michael Hanselmann
  LEVEL_NODE_RES,
1591 6c0a75db Dimitris Aragiorgis
  LEVEL_NETWORK,
1592 4e070776 Michael Hanselmann
  ]
1593 7ee7c0c7 Guido Trotter
1594 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1595 b8028dcf Michael Hanselmann
LEVELS_MOD = compat.UniqueFrozenset([
1596 4e070776 Michael Hanselmann
  LEVEL_NODE_RES,
1597 4e070776 Michael Hanselmann
  LEVEL_NODE,
1598 4e070776 Michael Hanselmann
  LEVEL_NODEGROUP,
1599 4e070776 Michael Hanselmann
  LEVEL_INSTANCE,
1600 6c0a75db Dimitris Aragiorgis
  LEVEL_NETWORK,
1601 4e070776 Michael Hanselmann
  ])
1602 7ee7c0c7 Guido Trotter
1603 5d7a899e Michael Hanselmann
#: Lock level names (make sure to use singular form)
1604 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1605 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1606 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1607 48aaca91 Michael Hanselmann
  LEVEL_NODE_ALLOC: "node-alloc",
1608 819ca990 Guido Trotter
  LEVEL_NODEGROUP: "nodegroup",
1609 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1610 5d7a899e Michael Hanselmann
  LEVEL_NODE_RES: "node-res",
1611 6c0a75db Dimitris Aragiorgis
  LEVEL_NETWORK: "network",
1612 ea205dbc Michael Hanselmann
  }
1613 ea205dbc Michael Hanselmann
1614 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1615 3ccb3a64 Michael Hanselmann
BGL = "BGL"
1616 7ee7c0c7 Guido Trotter
1617 8716b1db Michael Hanselmann
#: Node allocation lock
1618 8716b1db Michael Hanselmann
NAL = "NAL"
1619 8716b1db Michael Hanselmann
1620 7ee7c0c7 Guido Trotter
1621 3efa7659 Thomas Thrainer
class GanetiLockManager(object):
1622 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1623 7ee7c0c7 Guido Trotter

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

1629 7ee7c0c7 Guido Trotter
  """
1630 7ee7c0c7 Guido Trotter
  _instance = None
1631 7ee7c0c7 Guido Trotter
1632 da4a52a3 Thomas Thrainer
  def __init__(self, node_uuids, nodegroups, instance_names, networks):
1633 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1634 7ee7c0c7 Guido Trotter

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

1638 da4a52a3 Thomas Thrainer
    @param node_uuids: list of node UUIDs
1639 819ca990 Guido Trotter
    @param nodegroups: list of nodegroup uuids
1640 da4a52a3 Thomas Thrainer
    @param instance_names: list of instance names
1641 7ee7c0c7 Guido Trotter

1642 7ee7c0c7 Guido Trotter
    """
1643 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1644 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1645 c41eea6e Iustin Pop
1646 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1647 7ee7c0c7 Guido Trotter
1648 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1649 19b9ba9a Michael Hanselmann
1650 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1651 7ee7c0c7 Guido Trotter
    # locking order.
1652 7ee7c0c7 Guido Trotter
    self.__keyring = {
1653 5d7a899e Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "cluster", monitor=self._monitor),
1654 da4a52a3 Thomas Thrainer
      LEVEL_NODE: LockSet(node_uuids, "node", monitor=self._monitor),
1655 da4a52a3 Thomas Thrainer
      LEVEL_NODE_RES: LockSet(node_uuids, "node-res", monitor=self._monitor),
1656 5d7a899e Michael Hanselmann
      LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroup", monitor=self._monitor),
1657 da4a52a3 Thomas Thrainer
      LEVEL_INSTANCE: LockSet(instance_names, "instance",
1658 da4a52a3 Thomas Thrainer
                              monitor=self._monitor),
1659 6c0a75db Dimitris Aragiorgis
      LEVEL_NETWORK: LockSet(networks, "network", monitor=self._monitor),
1660 8716b1db Michael Hanselmann
      LEVEL_NODE_ALLOC: LockSet([NAL], "node-alloc", monitor=self._monitor),
1661 19b9ba9a Michael Hanselmann
      }
1662 19b9ba9a Michael Hanselmann
1663 5d7a899e Michael Hanselmann
    assert compat.all(ls.name == LEVEL_NAMES[level]
1664 8716b1db Michael Hanselmann
                      for (level, ls) in self.__keyring.items()), \
1665 8716b1db Michael Hanselmann
      "Keyring name mismatch"
1666 5d7a899e Michael Hanselmann
1667 4c03b2b5 Michael Hanselmann
  def AddToLockMonitor(self, provider):
1668 4c03b2b5 Michael Hanselmann
    """Registers a new lock with the monitor.
1669 4c03b2b5 Michael Hanselmann

1670 4c03b2b5 Michael Hanselmann
    See L{LockMonitor.RegisterLock}.
1671 4c03b2b5 Michael Hanselmann

1672 4c03b2b5 Michael Hanselmann
    """
1673 4c03b2b5 Michael Hanselmann
    return self._monitor.RegisterLock(provider)
1674 4c03b2b5 Michael Hanselmann
1675 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1676 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1677 19b9ba9a Michael Hanselmann

1678 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1679 19b9ba9a Michael Hanselmann

1680 19b9ba9a Michael Hanselmann
    """
1681 24d16f76 Michael Hanselmann
    return self._monitor.QueryLocks(fields)
1682 24d16f76 Michael Hanselmann
1683 7ee7c0c7 Guido Trotter
  def _names(self, level):
1684 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1685 7ee7c0c7 Guido Trotter

1686 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1687 c41eea6e Iustin Pop

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

1690 7ee7c0c7 Guido Trotter
    """
1691 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1692 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1693 7ee7c0c7 Guido Trotter
1694 ee2b99e3 Michael Hanselmann
  def is_owned(self, level):
1695 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1696 7ee7c0c7 Guido Trotter

1697 7ee7c0c7 Guido Trotter
    """
1698 ee2b99e3 Michael Hanselmann
    return self.__keyring[level].is_owned()
1699 7ee7c0c7 Guido Trotter
1700 ee2b99e3 Michael Hanselmann
  def list_owned(self, level):
1701 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1702 7ee7c0c7 Guido Trotter

1703 7ee7c0c7 Guido Trotter
    """
1704 ee2b99e3 Michael Hanselmann
    return self.__keyring[level].list_owned()
1705 07cba1bc Michael Hanselmann
1706 c6a622cf Michael Hanselmann
  def check_owned(self, level, names, shared=-1):
1707 c6a622cf Michael Hanselmann
    """Check if locks at a certain level are owned in a specific mode.
1708 c6a622cf Michael Hanselmann

1709 c6a622cf Michael Hanselmann
    @see: L{LockSet.check_owned}
1710 c6a622cf Michael Hanselmann

1711 c6a622cf Michael Hanselmann
    """
1712 c6a622cf Michael Hanselmann
    return self.__keyring[level].check_owned(names, shared=shared)
1713 c6a622cf Michael Hanselmann
1714 8c811986 Michael Hanselmann
  def owning_all(self, level):
1715 8c811986 Michael Hanselmann
    """Checks whether current thread owns all locks at a certain level.
1716 8c811986 Michael Hanselmann

1717 8c811986 Michael Hanselmann
    @see: L{LockSet.owning_all}
1718 8c811986 Michael Hanselmann

1719 8c811986 Michael Hanselmann
    """
1720 8c811986 Michael Hanselmann
    return self.__keyring[level].owning_all()
1721 8c811986 Michael Hanselmann
1722 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1723 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1724 7ee7c0c7 Guido Trotter

1725 7ee7c0c7 Guido Trotter
    """
1726 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1727 7ee7c0c7 Guido Trotter
    # the test cases.
1728 ee2b99e3 Michael Hanselmann
    return compat.any((self.is_owned(l) for l in LEVELS[level + 1:]))
1729 7ee7c0c7 Guido Trotter
1730 b459a848 Andrea Spadaccini
  def _BGL_owned(self): # pylint: disable=C0103
1731 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1732 7ee7c0c7 Guido Trotter

1733 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1734 7ee7c0c7 Guido Trotter

1735 7ee7c0c7 Guido Trotter
    """
1736 ee2b99e3 Michael Hanselmann
    return BGL in self.__keyring[LEVEL_CLUSTER].list_owned()
1737 7ee7c0c7 Guido Trotter
1738 c70d2d9b Iustin Pop
  @staticmethod
1739 b459a848 Andrea Spadaccini
  def _contains_BGL(level, names): # pylint: disable=C0103
1740 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1741 c41eea6e Iustin Pop

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

1745 7ee7c0c7 Guido Trotter
    """
1746 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1747 7ee7c0c7 Guido Trotter
1748 07db7ed2 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None,
1749 07db7ed2 Michael Hanselmann
              opportunistic=False):
1750 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1751 7ee7c0c7 Guido Trotter

1752 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1753 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1754 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1755 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1756 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1757 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1758 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1759 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1760 5e0a6daf Michael Hanselmann
    @type timeout: float
1761 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1762 b30d95b6 Michael Hanselmann
    @type priority: integer
1763 b30d95b6 Michael Hanselmann
    @param priority: Priority for acquiring lock
1764 07db7ed2 Michael Hanselmann
    @type opportunistic: boolean
1765 07db7ed2 Michael Hanselmann
    @param opportunistic: Acquire locks opportunistically; use the return value
1766 07db7ed2 Michael Hanselmann
      to determine which locks were actually acquired
1767 7ee7c0c7 Guido Trotter

1768 7ee7c0c7 Guido Trotter
    """
1769 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1770 7ee7c0c7 Guido Trotter
1771 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1772 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1773 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1774 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1775 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1776 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1777 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1778 5ae4945a Iustin Pop
      "You must own the Big Ganeti Lock before acquiring any other")
1779 7ee7c0c7 Guido Trotter
1780 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1781 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1782 5ae4945a Iustin Pop
                                          " while owning some at a greater one")
1783 7ee7c0c7 Guido Trotter
1784 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1785 b30d95b6 Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout,
1786 07db7ed2 Michael Hanselmann
                                         priority=priority,
1787 07db7ed2 Michael Hanselmann
                                         opportunistic=opportunistic)
1788 7ee7c0c7 Guido Trotter
1789 3dbe3ddf Michael Hanselmann
  def downgrade(self, level, names=None):
1790 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1791 3dbe3ddf Michael Hanselmann

1792 3dbe3ddf Michael Hanselmann
    You must have acquired the locks in exclusive mode.
1793 3dbe3ddf Michael Hanselmann

1794 3dbe3ddf Michael Hanselmann
    @type level: member of locking.LEVELS
1795 3dbe3ddf Michael Hanselmann
    @param level: the level at which the locks shall be downgraded
1796 3dbe3ddf Michael Hanselmann
    @type names: list of strings, or None
1797 3dbe3ddf Michael Hanselmann
    @param names: the names of the locks which shall be downgraded
1798 3dbe3ddf Michael Hanselmann
        (defaults to all the locks acquired at the level)
1799 3dbe3ddf Michael Hanselmann

1800 3dbe3ddf Michael Hanselmann
    """
1801 3dbe3ddf Michael Hanselmann
    assert level in LEVELS, "Invalid locking level %s" % level
1802 3dbe3ddf Michael Hanselmann
1803 3dbe3ddf Michael Hanselmann
    return self.__keyring[level].downgrade(names=names)
1804 3dbe3ddf Michael Hanselmann
1805 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1806 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1807 7ee7c0c7 Guido Trotter

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

1811 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1812 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1813 ec44d893 Guido Trotter
    @type names: list of strings, or None
1814 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1815 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1816 7ee7c0c7 Guido Trotter

1817 7ee7c0c7 Guido Trotter
    """
1818 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1819 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1820 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1821 5ae4945a Iustin Pop
              "Cannot release the Big Ganeti Lock while holding something"
1822 5ae4945a Iustin Pop
              " at upper levels (%r)" %
1823 5ae4945a Iustin Pop
              (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self.list_owned(i))
1824 5ae4945a Iustin Pop
                                for i in self.__keyring.keys()]), ))
1825 7ee7c0c7 Guido Trotter
1826 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1827 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1828 7ee7c0c7 Guido Trotter
1829 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1830 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1831 7ee7c0c7 Guido Trotter

1832 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1833 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1834 ec44d893 Guido Trotter
    @type names: list of strings
1835 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1836 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1837 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1838 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1839 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1840 c41eea6e Iustin Pop

1841 7ee7c0c7 Guido Trotter
    """
1842 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1843 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1844 5ae4945a Iustin Pop
                               " operations")
1845 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1846 5ae4945a Iustin Pop
                                          " while owning some at a greater one")
1847 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1848 7ee7c0c7 Guido Trotter
1849 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1850 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1851 7ee7c0c7 Guido Trotter

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

1855 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1856 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1857 ec44d893 Guido Trotter
    @type names: list of strings
1858 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1859 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1860 7ee7c0c7 Guido Trotter

1861 7ee7c0c7 Guido Trotter
    """
1862 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1863 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1864 5ae4945a Iustin Pop
                               " operations")
1865 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1866 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1867 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1868 ee2b99e3 Michael Hanselmann
    assert self.is_owned(level) or not self._upper_owned(level), (
1869 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1870 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1871 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1872 19b9ba9a Michael Hanselmann
1873 19b9ba9a Michael Hanselmann
1874 44b4eddc Michael Hanselmann
def _MonitorSortKey((item, idx, num)):
1875 e4e35357 Michael Hanselmann
  """Sorting key function.
1876 e4e35357 Michael Hanselmann

1877 44b4eddc Michael Hanselmann
  Sort by name, registration order and then order of information. This provides
1878 44b4eddc Michael Hanselmann
  a stable sort order over different providers, even if they return the same
1879 44b4eddc Michael Hanselmann
  name.
1880 e4e35357 Michael Hanselmann

1881 e4e35357 Michael Hanselmann
  """
1882 e4e35357 Michael Hanselmann
  (name, _, _, _) = item
1883 e4e35357 Michael Hanselmann
1884 44b4eddc Michael Hanselmann
  return (utils.NiceSortKey(name), num, idx)
1885 e4e35357 Michael Hanselmann
1886 e4e35357 Michael Hanselmann
1887 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1888 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1889 19b9ba9a Michael Hanselmann
1890 19b9ba9a Michael Hanselmann
  def __init__(self):
1891 19b9ba9a Michael Hanselmann
    """Initializes this class.
1892 19b9ba9a Michael Hanselmann

1893 19b9ba9a Michael Hanselmann
    """
1894 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1895 19b9ba9a Michael Hanselmann
1896 e4e35357 Michael Hanselmann
    # Counter for stable sorting
1897 e4e35357 Michael Hanselmann
    self._counter = itertools.count(0)
1898 e4e35357 Michael Hanselmann
1899 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1900 19b9ba9a Michael Hanselmann
    # references and deletion.
1901 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1902 19b9ba9a Michael Hanselmann
1903 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1904 44b4eddc Michael Hanselmann
  def RegisterLock(self, provider):
1905 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1906 19b9ba9a Michael Hanselmann

1907 44b4eddc Michael Hanselmann
    @param provider: Object with a callable method named C{GetLockInfo}, taking
1908 44b4eddc Michael Hanselmann
      a single C{set} containing the requested information items
1909 44b4eddc Michael Hanselmann
    @note: It would be nicer to only receive the function generating the
1910 44b4eddc Michael Hanselmann
      requested information but, as it turns out, weak references to bound
1911 44b4eddc Michael Hanselmann
      methods (e.g. C{self.GetLockInfo}) are tricky; there are several
1912 44b4eddc Michael Hanselmann
      workarounds, but none of the ones I found works properly in combination
1913 44b4eddc Michael Hanselmann
      with a standard C{WeakKeyDictionary}
1914 44b4eddc Michael Hanselmann

1915 19b9ba9a Michael Hanselmann
    """
1916 44b4eddc Michael Hanselmann
    assert provider not in self._locks, "Duplicate registration"
1917 e4e35357 Michael Hanselmann
1918 e4e35357 Michael Hanselmann
    # There used to be a check for duplicate names here. As it turned out, when
1919 e4e35357 Michael Hanselmann
    # a lock is re-created with the same name in a very short timeframe, the
1920 e4e35357 Michael Hanselmann
    # previous instance might not yet be removed from the weakref dictionary.
1921 e4e35357 Michael Hanselmann
    # By keeping track of the order of incoming registrations, a stable sort
1922 e4e35357 Michael Hanselmann
    # ordering can still be guaranteed.
1923 e4e35357 Michael Hanselmann
1924 44b4eddc Michael Hanselmann
    self._locks[provider] = self._counter.next()
1925 19b9ba9a Michael Hanselmann
1926 24d16f76 Michael Hanselmann
  def _GetLockInfo(self, requested):
1927 44b4eddc Michael Hanselmann
    """Get information from all locks.
1928 19b9ba9a Michael Hanselmann

1929 19b9ba9a Michael Hanselmann
    """
1930 44b4eddc Michael Hanselmann
    # Must hold lock while getting consistent list of tracked items
1931 44b4eddc Michael Hanselmann
    self._lock.acquire(shared=1)
1932 44b4eddc Michael Hanselmann
    try:
1933 44b4eddc Michael Hanselmann
      items = self._locks.items()
1934 44b4eddc Michael Hanselmann
    finally:
1935 44b4eddc Michael Hanselmann
      self._lock.release()
1936 44b4eddc Michael Hanselmann
1937 44b4eddc Michael Hanselmann
    return [(info, idx, num)
1938 44b4eddc Michael Hanselmann
            for (provider, num) in items
1939 44b4eddc Michael Hanselmann
            for (idx, info) in enumerate(provider.GetLockInfo(requested))]
1940 19b9ba9a Michael Hanselmann
1941 24d16f76 Michael Hanselmann
  def _Query(self, fields):
1942 24d16f76 Michael Hanselmann
    """Queries information from all locks.
1943 19b9ba9a Michael Hanselmann

1944 24d16f76 Michael Hanselmann
    @type fields: list of strings
1945 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1946 24d16f76 Michael Hanselmann

1947 24d16f76 Michael Hanselmann
    """
1948 24d16f76 Michael Hanselmann
    qobj = query.Query(query.LOCK_FIELDS, fields)
1949 24d16f76 Michael Hanselmann
1950 e4e35357 Michael Hanselmann
    # Get all data with internal lock held and then sort by name and incoming
1951 e4e35357 Michael Hanselmann
    # order
1952 e4e35357 Michael Hanselmann
    lockinfo = sorted(self._GetLockInfo(qobj.RequestedData()),
1953 e4e35357 Michael Hanselmann
                      key=_MonitorSortKey)
1954 24d16f76 Michael Hanselmann
1955 e4e35357 Michael Hanselmann
    # Extract lock information and build query data
1956 eb62069e Iustin Pop
    return (qobj, query.LockQueryData(map(compat.fst, lockinfo)))
1957 19b9ba9a Michael Hanselmann
1958 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1959 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1960 19b9ba9a Michael Hanselmann

1961 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1962 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1963 19b9ba9a Michael Hanselmann

1964 19b9ba9a Michael Hanselmann
    """
1965 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1966 19b9ba9a Michael Hanselmann
1967 24d16f76 Michael Hanselmann
    # Prepare query response
1968 24d16f76 Michael Hanselmann
    return query.GetQueryResponse(qobj, ctx)