Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 185192f2

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 87ed6b79 Klaus Aehlig
LOCKSET_NAME = "[lockset]"
920 87ed6b79 Klaus Aehlig
921 e310b019 Guido Trotter
922 a95c53ea Michael Hanselmann
def _TimeoutZero():
923 a95c53ea Michael Hanselmann
  """Returns the number zero.
924 a95c53ea Michael Hanselmann

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

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

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

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

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

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

984 7f93570a Iustin Pop
  @type name: string
985 7f93570a Iustin Pop
  @ivar name: the name of the lockset
986 7f93570a Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

1091 8c811986 Michael Hanselmann
    @rtype: boolean
1092 8c811986 Michael Hanselmann

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

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

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

1148 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
1149 cdb08f44 Michael Hanselmann

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

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

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

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

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

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

1261 a95c53ea Michael Hanselmann
    Acquisition modes:
1262 a95c53ea Michael Hanselmann

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

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

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

1370 3dbe3ddf Michael Hanselmann
    The locks must have been acquired in exclusive mode.
1371 3dbe3ddf Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1672 4c03b2b5 Michael Hanselmann
    See L{LockMonitor.RegisterLock}.
1673 4c03b2b5 Michael Hanselmann

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

1680 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1681 19b9ba9a Michael Hanselmann

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

1688 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1689 c41eea6e Iustin Pop

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

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

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

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

1711 c6a622cf Michael Hanselmann
    @see: L{LockSet.check_owned}
1712 c6a622cf Michael Hanselmann

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

1719 8c811986 Michael Hanselmann
    @see: L{LockSet.owning_all}
1720 8c811986 Michael Hanselmann

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

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

1735 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1736 7ee7c0c7 Guido Trotter

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

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

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

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

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

1794 3dbe3ddf Michael Hanselmann
    You must have acquired the locks in exclusive mode.
1795 3dbe3ddf Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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