Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 5e12acfe

History | View | Annotate | Download (55.8 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 c31825f7 Michael Hanselmann
51 dbb11e8b Guido Trotter
def ssynchronized(mylock, shared=0):
52 42a999d1 Guido Trotter
  """Shared Synchronization decorator.
53 42a999d1 Guido Trotter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

356 48dabc6a Michael Hanselmann
    """
357 48dabc6a Michael Hanselmann
    self._check_owned()
358 48dabc6a Michael Hanselmann
359 c31825f7 Michael Hanselmann
    return bool(self._waiters)
360 48dabc6a Michael Hanselmann
361 20699809 Michael Hanselmann
  def __repr__(self):
362 20699809 Michael Hanselmann
    return ("<%s.%s waiters=%s at %#x>" %
363 20699809 Michael Hanselmann
            (self.__class__.__module__, self.__class__.__name__,
364 20699809 Michael Hanselmann
             self._waiters, id(self)))
365 20699809 Michael Hanselmann
366 48dabc6a Michael Hanselmann
367 887c7aa6 Michael Hanselmann
class _PipeConditionWithMode(PipeCondition):
368 887c7aa6 Michael Hanselmann
  __slots__ = [
369 887c7aa6 Michael Hanselmann
    "shared",
370 887c7aa6 Michael Hanselmann
    ]
371 887c7aa6 Michael Hanselmann
372 887c7aa6 Michael Hanselmann
  def __init__(self, lock, shared):
373 887c7aa6 Michael Hanselmann
    """Initializes this class.
374 887c7aa6 Michael Hanselmann

375 887c7aa6 Michael Hanselmann
    """
376 887c7aa6 Michael Hanselmann
    self.shared = shared
377 887c7aa6 Michael Hanselmann
    PipeCondition.__init__(self, lock)
378 887c7aa6 Michael Hanselmann
379 887c7aa6 Michael Hanselmann
380 84e344d4 Michael Hanselmann
class SharedLock(object):
381 162c1c1f Guido Trotter
  """Implements a shared lock.
382 162c1c1f Guido Trotter

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

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

395 7f93570a Iustin Pop
  @type name: string
396 7f93570a Iustin Pop
  @ivar name: the name of the lock
397 7f93570a Iustin Pop

398 162c1c1f Guido Trotter
  """
399 84e344d4 Michael Hanselmann
  __slots__ = [
400 19b9ba9a Michael Hanselmann
    "__weakref__",
401 84e344d4 Michael Hanselmann
    "__deleted",
402 84e344d4 Michael Hanselmann
    "__exc",
403 84e344d4 Michael Hanselmann
    "__lock",
404 84e344d4 Michael Hanselmann
    "__pending",
405 887c7aa6 Michael Hanselmann
    "__pending_by_prio",
406 887c7aa6 Michael Hanselmann
    "__pending_shared",
407 84e344d4 Michael Hanselmann
    "__shr",
408 8d7d8b57 Michael Hanselmann
    "__time_fn",
409 7f93570a Iustin Pop
    "name",
410 84e344d4 Michael Hanselmann
    ]
411 84e344d4 Michael Hanselmann
412 887c7aa6 Michael Hanselmann
  __condition_class = _PipeConditionWithMode
413 84e344d4 Michael Hanselmann
414 8d7d8b57 Michael Hanselmann
  def __init__(self, name, monitor=None, _time_fn=time.time):
415 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
416 84e344d4 Michael Hanselmann

417 7f93570a Iustin Pop
    @param name: the name of the lock
418 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
419 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register
420 7f93570a Iustin Pop

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

457 24d16f76 Michael Hanselmann
    @type requested: set
458 24d16f76 Michael Hanselmann
    @param requested: Requested information, see C{query.LQ_*}
459 19b9ba9a Michael Hanselmann

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

514 84e344d4 Michael Hanselmann
    """
515 84e344d4 Michael Hanselmann
    if self.__deleted:
516 7f93570a Iustin Pop
      raise errors.LockError("Deleted lock %s" % self.name)
517 84e344d4 Michael Hanselmann
518 162c1c1f Guido Trotter
  def __is_sharer(self):
519 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
520 84e344d4 Michael Hanselmann

521 84e344d4 Michael Hanselmann
    """
522 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
523 162c1c1f Guido Trotter
524 162c1c1f Guido Trotter
  def __is_exclusive(self):
525 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
526 84e344d4 Michael Hanselmann

527 84e344d4 Michael Hanselmann
    """
528 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
529 162c1c1f Guido Trotter
530 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
531 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
532 162c1c1f Guido Trotter

533 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
534 162c1c1f Guido Trotter
    the internal lock.
535 162c1c1f Guido Trotter

536 162c1c1f Guido Trotter
    """
537 162c1c1f Guido Trotter
    if shared < 0:
538 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
539 162c1c1f Guido Trotter
    elif shared:
540 162c1c1f Guido Trotter
      return self.__is_sharer()
541 162c1c1f Guido Trotter
    else:
542 162c1c1f Guido Trotter
      return self.__is_exclusive()
543 162c1c1f Guido Trotter
544 ee2b99e3 Michael Hanselmann
  def is_owned(self, shared=-1):
545 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
546 162c1c1f Guido Trotter

547 c41eea6e Iustin Pop
    @param shared:
548 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
549 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
550 c41eea6e Iustin Pop
        - > 0: check for shared ownership
551 162c1c1f Guido Trotter

552 162c1c1f Guido Trotter
    """
553 162c1c1f Guido Trotter
    self.__lock.acquire()
554 162c1c1f Guido Trotter
    try:
555 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
556 162c1c1f Guido Trotter
    finally:
557 162c1c1f Guido Trotter
      self.__lock.release()
558 162c1c1f Guido Trotter
559 ee2b99e3 Michael Hanselmann
  #: Necessary to remain compatible with threading.Condition, which tries to
560 ee2b99e3 Michael Hanselmann
  #: retrieve a locks' "_is_owned" attribute
561 ee2b99e3 Michael Hanselmann
  _is_owned = is_owned
562 fdfe88b1 Michael Hanselmann
563 84e344d4 Michael Hanselmann
  def _count_pending(self):
564 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
565 a95fd5d7 Guido Trotter

566 84e344d4 Michael Hanselmann
    @rtype: int
567 a95fd5d7 Guido Trotter

568 a95fd5d7 Guido Trotter
    """
569 84e344d4 Michael Hanselmann
    self.__lock.acquire()
570 84e344d4 Michael Hanselmann
    try:
571 887c7aa6 Michael Hanselmann
      return sum(len(prioqueue) for (_, prioqueue) in self.__pending)
572 887c7aa6 Michael Hanselmann
    finally:
573 887c7aa6 Michael Hanselmann
      self.__lock.release()
574 887c7aa6 Michael Hanselmann
575 887c7aa6 Michael Hanselmann
  def _check_empty(self):
576 887c7aa6 Michael Hanselmann
    """Checks whether there are any pending acquires.
577 887c7aa6 Michael Hanselmann

578 887c7aa6 Michael Hanselmann
    @rtype: bool
579 887c7aa6 Michael Hanselmann

580 887c7aa6 Michael Hanselmann
    """
581 887c7aa6 Michael Hanselmann
    self.__lock.acquire()
582 887c7aa6 Michael Hanselmann
    try:
583 887c7aa6 Michael Hanselmann
      # Order is important: __find_first_pending_queue modifies __pending
584 113359fe Michael Hanselmann
      (_, prioqueue) = self.__find_first_pending_queue()
585 113359fe Michael Hanselmann
586 113359fe Michael Hanselmann
      return not (prioqueue or
587 887c7aa6 Michael Hanselmann
                  self.__pending or
588 887c7aa6 Michael Hanselmann
                  self.__pending_by_prio or
589 887c7aa6 Michael Hanselmann
                  self.__pending_shared)
590 84e344d4 Michael Hanselmann
    finally:
591 84e344d4 Michael Hanselmann
      self.__lock.release()
592 a95fd5d7 Guido Trotter
593 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
594 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
595 84e344d4 Michael Hanselmann

596 84e344d4 Michael Hanselmann
    """
597 84e344d4 Michael Hanselmann
    if shared:
598 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
599 84e344d4 Michael Hanselmann
    else:
600 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
601 a95fd5d7 Guido Trotter
602 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
603 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
604 a95fd5d7 Guido Trotter

605 a95fd5d7 Guido Trotter
    """
606 84e344d4 Michael Hanselmann
    if shared:
607 84e344d4 Michael Hanselmann
      return self.__exc is None
608 84e344d4 Michael Hanselmann
    else:
609 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
610 a95fd5d7 Guido Trotter
611 887c7aa6 Michael Hanselmann
  def __find_first_pending_queue(self):
612 887c7aa6 Michael Hanselmann
    """Tries to find the topmost queued entry with pending acquires.
613 887c7aa6 Michael Hanselmann

614 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
615 887c7aa6 Michael Hanselmann

616 887c7aa6 Michael Hanselmann
    """
617 887c7aa6 Michael Hanselmann
    while self.__pending:
618 887c7aa6 Michael Hanselmann
      (priority, prioqueue) = self.__pending[0]
619 887c7aa6 Michael Hanselmann
620 887c7aa6 Michael Hanselmann
      if prioqueue:
621 113359fe Michael Hanselmann
        return (priority, prioqueue)
622 887c7aa6 Michael Hanselmann
623 113359fe Michael Hanselmann
      # Remove empty queue
624 113359fe Michael Hanselmann
      heapq.heappop(self.__pending)
625 113359fe Michael Hanselmann
      del self.__pending_by_prio[priority]
626 113359fe Michael Hanselmann
      assert priority not in self.__pending_shared
627 113359fe Michael Hanselmann
628 113359fe Michael Hanselmann
    return (None, None)
629 887c7aa6 Michael Hanselmann
630 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
631 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
632 a95fd5d7 Guido Trotter

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

635 84e344d4 Michael Hanselmann
    """
636 113359fe Michael Hanselmann
    (_, prioqueue) = self.__find_first_pending_queue()
637 113359fe Michael Hanselmann
638 113359fe Michael Hanselmann
    return cond == prioqueue[0]
639 4d686df8 Guido Trotter
640 887c7aa6 Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout, priority):
641 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
642 9216a9f7 Michael Hanselmann

643 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
644 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
645 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
646 887c7aa6 Michael Hanselmann
    @type priority: integer
647 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
648 9216a9f7 Michael Hanselmann

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

728 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
729 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
730 c41eea6e Iustin Pop
        exclusive lock will be acquired
731 84e344d4 Michael Hanselmann
    @type timeout: float
732 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
733 887c7aa6 Michael Hanselmann
    @type priority: integer
734 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
735 008b92fa Michael Hanselmann
    @type test_notify: callable or None
736 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
737 162c1c1f Guido Trotter

738 162c1c1f Guido Trotter
    """
739 7100c2fa Michael Hanselmann
    if priority is None:
740 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
741 7100c2fa Michael Hanselmann
742 162c1c1f Guido Trotter
    self.__lock.acquire()
743 162c1c1f Guido Trotter
    try:
744 008b92fa Michael Hanselmann
      # We already got the lock, notify now
745 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
746 008b92fa Michael Hanselmann
        test_notify()
747 008b92fa Michael Hanselmann
748 887c7aa6 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout, priority)
749 162c1c1f Guido Trotter
    finally:
750 162c1c1f Guido Trotter
      self.__lock.release()
751 162c1c1f Guido Trotter
752 3dbe3ddf Michael Hanselmann
  def downgrade(self):
753 3dbe3ddf Michael Hanselmann
    """Changes the lock mode from exclusive to shared.
754 3dbe3ddf Michael Hanselmann

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

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

797 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
798 162c1c1f Guido Trotter
    before calling this function.
799 162c1c1f Guido Trotter

800 162c1c1f Guido Trotter
    """
801 162c1c1f Guido Trotter
    self.__lock.acquire()
802 162c1c1f Guido Trotter
    try:
803 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
804 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
805 84e344d4 Michael Hanselmann
806 162c1c1f Guido Trotter
      # Autodetect release type
807 162c1c1f Guido Trotter
      if self.__is_exclusive():
808 162c1c1f Guido Trotter
        self.__exc = None
809 70567db0 Michael Hanselmann
        notify = True
810 84e344d4 Michael Hanselmann
      else:
811 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
812 70567db0 Michael Hanselmann
        notify = not self.__shr
813 162c1c1f Guido Trotter
814 70567db0 Michael Hanselmann
      # Notify topmost condition in queue if there are no owners left (for
815 70567db0 Michael Hanselmann
      # shared locks)
816 70567db0 Michael Hanselmann
      if notify:
817 70567db0 Michael Hanselmann
        self.__notify_topmost()
818 8d7d8b57 Michael Hanselmann
    finally:
819 8d7d8b57 Michael Hanselmann
      self.__lock.release()
820 8d7d8b57 Michael Hanselmann
821 8d7d8b57 Michael Hanselmann
  def __notify_topmost(self):
822 8d7d8b57 Michael Hanselmann
    """Notifies topmost condition in queue of pending acquires.
823 8d7d8b57 Michael Hanselmann

824 8d7d8b57 Michael Hanselmann
    """
825 8d7d8b57 Michael Hanselmann
    (priority, prioqueue) = self.__find_first_pending_queue()
826 8d7d8b57 Michael Hanselmann
    if prioqueue:
827 8d7d8b57 Michael Hanselmann
      cond = prioqueue[0]
828 8d7d8b57 Michael Hanselmann
      cond.notifyAll()
829 8d7d8b57 Michael Hanselmann
      if cond.shared:
830 8d7d8b57 Michael Hanselmann
        # Prevent further shared acquires from sneaking in while waiters are
831 8d7d8b57 Michael Hanselmann
        # notified
832 8d7d8b57 Michael Hanselmann
        self.__pending_shared.pop(priority, None)
833 8d7d8b57 Michael Hanselmann
834 8d7d8b57 Michael Hanselmann
  def _notify_topmost(self):
835 8d7d8b57 Michael Hanselmann
    """Exported version of L{__notify_topmost}.
836 162c1c1f Guido Trotter

837 8d7d8b57 Michael Hanselmann
    """
838 8d7d8b57 Michael Hanselmann
    self.__lock.acquire()
839 8d7d8b57 Michael Hanselmann
    try:
840 8d7d8b57 Michael Hanselmann
      return self.__notify_topmost()
841 162c1c1f Guido Trotter
    finally:
842 162c1c1f Guido Trotter
      self.__lock.release()
843 162c1c1f Guido Trotter
844 7100c2fa Michael Hanselmann
  def delete(self, timeout=None, priority=None):
845 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
846 a95fd5d7 Guido Trotter

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

851 84e344d4 Michael Hanselmann
    @type timeout: float
852 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
853 887c7aa6 Michael Hanselmann
    @type priority: integer
854 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
855 a95fd5d7 Guido Trotter

856 a95fd5d7 Guido Trotter
    """
857 7100c2fa Michael Hanselmann
    if priority is None:
858 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
859 7100c2fa Michael Hanselmann
860 a95fd5d7 Guido Trotter
    self.__lock.acquire()
861 a95fd5d7 Guido Trotter
    try:
862 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
863 84e344d4 Michael Hanselmann
864 84e344d4 Michael Hanselmann
      self.__check_deleted()
865 a95fd5d7 Guido Trotter
866 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
867 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
868 a95fd5d7 Guido Trotter
869 84e344d4 Michael Hanselmann
      if not acquired:
870 887c7aa6 Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout, priority)
871 a66bd91b Michael Hanselmann
872 26082b7e Michael Hanselmann
      if acquired:
873 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
874 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
875 84e344d4 Michael Hanselmann
876 84e344d4 Michael Hanselmann
        self.__deleted = True
877 84e344d4 Michael Hanselmann
        self.__exc = None
878 a95fd5d7 Guido Trotter
879 19b9ba9a Michael Hanselmann
        assert not (self.__exc or self.__shr), "Found owner during deletion"
880 19b9ba9a Michael Hanselmann
881 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
882 887c7aa6 Michael Hanselmann
        for (_, prioqueue) in self.__pending:
883 887c7aa6 Michael Hanselmann
          for cond in prioqueue:
884 887c7aa6 Michael Hanselmann
            cond.notifyAll()
885 887c7aa6 Michael Hanselmann
886 887c7aa6 Michael Hanselmann
        assert self.__deleted
887 a95fd5d7 Guido Trotter
888 84e344d4 Michael Hanselmann
      return acquired
889 a95fd5d7 Guido Trotter
    finally:
890 a95fd5d7 Guido Trotter
      self.__lock.release()
891 a95fd5d7 Guido Trotter
892 1a4e32d0 Guido Trotter
  def _release_save(self):
893 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
894 1a4e32d0 Guido Trotter
    self.release()
895 1a4e32d0 Guido Trotter
    return shared
896 1a4e32d0 Guido Trotter
897 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
898 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
899 1a4e32d0 Guido Trotter
900 aaae9bc0 Guido Trotter
901 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
902 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
903 e310b019 Guido Trotter
ALL_SET = None
904 e310b019 Guido Trotter
905 e310b019 Guido Trotter
906 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
907 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
908 5aab242c Michael Hanselmann

909 5aab242c Michael Hanselmann
  """
910 5aab242c Michael Hanselmann
911 5aab242c Michael Hanselmann
912 aaae9bc0 Guido Trotter
class LockSet:
913 aaae9bc0 Guido Trotter
  """Implements a set of locks.
914 aaae9bc0 Guido Trotter

915 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
916 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
917 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
918 aaae9bc0 Guido Trotter
  preventing deadlock.
919 aaae9bc0 Guido Trotter

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

922 7f93570a Iustin Pop
  @type name: string
923 7f93570a Iustin Pop
  @ivar name: the name of the lockset
924 7f93570a Iustin Pop

925 aaae9bc0 Guido Trotter
  """
926 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
927 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
928 aaae9bc0 Guido Trotter

929 ec44d893 Guido Trotter
    @type members: list of strings
930 c41eea6e Iustin Pop
    @param members: initial members of the set
931 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
932 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
933 aaae9bc0 Guido Trotter

934 aaae9bc0 Guido Trotter
    """
935 7f93570a Iustin Pop
    assert members is not None, "members parameter is not a list"
936 7f93570a Iustin Pop
    self.name = name
937 7f93570a Iustin Pop
938 19b9ba9a Michael Hanselmann
    # Lock monitor
939 19b9ba9a Michael Hanselmann
    self.__monitor = monitor
940 19b9ba9a Michael Hanselmann
941 c307ee34 Michael Hanselmann
    # Used internally to guarantee coherency
942 c307ee34 Michael Hanselmann
    self.__lock = SharedLock(self._GetLockName("[lockset]"), monitor=monitor)
943 aaae9bc0 Guido Trotter
944 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
945 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
946 aaae9bc0 Guido Trotter
    self.__lockdict = {}
947 aaae9bc0 Guido Trotter
948 7f93570a Iustin Pop
    for mname in members:
949 19b9ba9a Michael Hanselmann
      self.__lockdict[mname] = SharedLock(self._GetLockName(mname),
950 19b9ba9a Michael Hanselmann
                                          monitor=monitor)
951 aaae9bc0 Guido Trotter
952 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
953 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
954 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
955 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
956 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
957 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
958 aaae9bc0 Guido Trotter
    # will be trouble.
959 aaae9bc0 Guido Trotter
    self.__owners = {}
960 aaae9bc0 Guido Trotter
961 4fb780d1 Michael Hanselmann
  def _GetLockName(self, mname):
962 4fb780d1 Michael Hanselmann
    """Returns the name for a member lock.
963 4fb780d1 Michael Hanselmann

964 4fb780d1 Michael Hanselmann
    """
965 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
966 4fb780d1 Michael Hanselmann
967 3dbe3ddf Michael Hanselmann
  def _get_lock(self):
968 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock.
969 3dbe3ddf Michael Hanselmann

970 3dbe3ddf Michael Hanselmann
    """
971 3dbe3ddf Michael Hanselmann
    return self.__lock
972 3dbe3ddf Michael Hanselmann
973 3dbe3ddf Michael Hanselmann
  def _get_lockdict(self):
974 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock dictionary.
975 3dbe3ddf Michael Hanselmann

976 3dbe3ddf Michael Hanselmann
    Accessing this structure is only safe in single-thread usage or when the
977 3dbe3ddf Michael Hanselmann
    lockset-internal lock is held.
978 3dbe3ddf Michael Hanselmann

979 3dbe3ddf Michael Hanselmann
    """
980 3dbe3ddf Michael Hanselmann
    return self.__lockdict
981 3dbe3ddf Michael Hanselmann
982 ee2b99e3 Michael Hanselmann
  def is_owned(self):
983 c6a622cf Michael Hanselmann
    """Is the current thread a current level owner?
984 c6a622cf Michael Hanselmann

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

987 c6a622cf Michael Hanselmann
    """
988 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
989 aaae9bc0 Guido Trotter
990 c6a622cf Michael Hanselmann
  def check_owned(self, names, shared=-1):
991 c6a622cf Michael Hanselmann
    """Check if locks are owned in a specific mode.
992 c6a622cf Michael Hanselmann

993 c6a622cf Michael Hanselmann
    @type names: sequence or string
994 c6a622cf Michael Hanselmann
    @param names: Lock names (or a single lock name)
995 c6a622cf Michael Hanselmann
    @param shared: See L{SharedLock.is_owned}
996 c6a622cf Michael Hanselmann
    @rtype: bool
997 c6a622cf Michael Hanselmann
    @note: Use L{is_owned} to check if the current thread holds I{any} lock and
998 c6a622cf Michael Hanselmann
      L{list_owned} to get the names of all owned locks
999 c6a622cf Michael Hanselmann

1000 c6a622cf Michael Hanselmann
    """
1001 c6a622cf Michael Hanselmann
    if isinstance(names, basestring):
1002 c6a622cf Michael Hanselmann
      names = [names]
1003 c6a622cf Michael Hanselmann
1004 c6a622cf Michael Hanselmann
    # Avoid check if no locks are owned anyway
1005 c6a622cf Michael Hanselmann
    if names and self.is_owned():
1006 c6a622cf Michael Hanselmann
      candidates = []
1007 c6a622cf Michael Hanselmann
1008 c6a622cf Michael Hanselmann
      # Gather references to all locks (in case they're deleted in the meantime)
1009 c6a622cf Michael Hanselmann
      for lname in names:
1010 c6a622cf Michael Hanselmann
        try:
1011 c6a622cf Michael Hanselmann
          lock = self.__lockdict[lname]
1012 c6a622cf Michael Hanselmann
        except KeyError:
1013 c6a622cf Michael Hanselmann
          raise errors.LockError("Non-existing lock '%s' in set '%s' (it may"
1014 c6a622cf Michael Hanselmann
                                 " have been removed)" % (lname, self.name))
1015 c6a622cf Michael Hanselmann
        else:
1016 c6a622cf Michael Hanselmann
          candidates.append(lock)
1017 c6a622cf Michael Hanselmann
1018 c6a622cf Michael Hanselmann
      return compat.all(lock.is_owned(shared=shared) for lock in candidates)
1019 c6a622cf Michael Hanselmann
    else:
1020 c6a622cf Michael Hanselmann
      return False
1021 c6a622cf Michael Hanselmann
1022 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
1023 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
1024 b2dabfd6 Guido Trotter
    if name is None:
1025 ee2b99e3 Michael Hanselmann
      if not self.is_owned():
1026 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
1027 aaae9bc0 Guido Trotter
    else:
1028 ee2b99e3 Michael Hanselmann
      if self.is_owned():
1029 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
1030 b2dabfd6 Guido Trotter
      else:
1031 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
1032 b2dabfd6 Guido Trotter
1033 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
1034 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
1035 aaae9bc0 Guido Trotter
1036 ee2b99e3 Michael Hanselmann
    assert not (name is None and self.__lock.is_owned()), \
1037 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
1038 e4335b5b Michael Hanselmann
1039 b2dabfd6 Guido Trotter
    if name is not None:
1040 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
1041 b2dabfd6 Guido Trotter
1042 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
1043 ee2b99e3 Michael Hanselmann
    if (not self.__lock.is_owned() and
1044 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
1045 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
1046 aaae9bc0 Guido Trotter
1047 ee2b99e3 Michael Hanselmann
  def list_owned(self):
1048 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
1049 ee2b99e3 Michael Hanselmann
    if self.is_owned():
1050 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
1051 aaae9bc0 Guido Trotter
    else:
1052 aaae9bc0 Guido Trotter
      return set()
1053 aaae9bc0 Guido Trotter
1054 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
1055 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
1056 ee2b99e3 Michael Hanselmann
    for lname in self.list_owned():
1057 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
1058 ee2b99e3 Michael Hanselmann
      if lock.is_owned():
1059 56452af7 Michael Hanselmann
        lock.release()
1060 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
1061 5aab242c Michael Hanselmann
1062 aaae9bc0 Guido Trotter
  def __names(self):
1063 aaae9bc0 Guido Trotter
    """Return the current set of names.
1064 aaae9bc0 Guido Trotter

1065 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
1066 aaae9bc0 Guido Trotter
    result after releasing the lock.
1067 aaae9bc0 Guido Trotter

1068 aaae9bc0 Guido Trotter
    """
1069 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
1070 aaae9bc0 Guido Trotter
1071 aaae9bc0 Guido Trotter
  def _names(self):
1072 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
1073 aaae9bc0 Guido Trotter

1074 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
1075 cdb08f44 Michael Hanselmann

1076 aaae9bc0 Guido Trotter
    """
1077 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
1078 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
1079 d4803c24 Guido Trotter
    release_lock = False
1080 ee2b99e3 Michael Hanselmann
    if not self.__lock.is_owned():
1081 d4803c24 Guido Trotter
      release_lock = True
1082 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
1083 aaae9bc0 Guido Trotter
    try:
1084 aaae9bc0 Guido Trotter
      result = self.__names()
1085 aaae9bc0 Guido Trotter
    finally:
1086 d4803c24 Guido Trotter
      if release_lock:
1087 d4803c24 Guido Trotter
        self.__lock.release()
1088 0cf257c5 Guido Trotter
    return set(result)
1089 aaae9bc0 Guido Trotter
1090 7100c2fa Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, priority=None,
1091 887c7aa6 Michael Hanselmann
              test_notify=None):
1092 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
1093 aaae9bc0 Guido Trotter

1094 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1095 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1096 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1097 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1098 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
1099 c41eea6e Iustin Pop
        exclusive lock will be acquired
1100 5aab242c Michael Hanselmann
    @type timeout: float or None
1101 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1102 887c7aa6 Michael Hanselmann
    @type priority: integer
1103 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1104 5aab242c Michael Hanselmann
    @type test_notify: callable or None
1105 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1106 aaae9bc0 Guido Trotter

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

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

1113 aaae9bc0 Guido Trotter
    """
1114 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
1115 aaae9bc0 Guido Trotter
1116 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
1117 ee2b99e3 Michael Hanselmann
    assert not self.is_owned(), ("Cannot acquire locks in the same set twice"
1118 ee2b99e3 Michael Hanselmann
                                 " (lockset %s)" % self.name)
1119 aaae9bc0 Guido Trotter
1120 7100c2fa Michael Hanselmann
    if priority is None:
1121 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
1122 7100c2fa Michael Hanselmann
1123 5aab242c Michael Hanselmann
    # We need to keep track of how long we spent waiting for a lock. The
1124 5aab242c Michael Hanselmann
    # timeout passed to this function is over all lock acquires.
1125 557838c1 Renรฉ Nussbaumer
    running_timeout = utils.RunningTimeout(timeout, False)
1126 5aab242c Michael Hanselmann
1127 806e20fd Guido Trotter
    try:
1128 76e2f08a Michael Hanselmann
      if names is not None:
1129 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
1130 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
1131 5aab242c Michael Hanselmann
          names = [names]
1132 5aab242c Michael Hanselmann
1133 887c7aa6 Michael Hanselmann
        return self.__acquire_inner(names, False, shared, priority,
1134 7e8841bd Michael Hanselmann
                                    running_timeout.Remaining, test_notify)
1135 76e2f08a Michael Hanselmann
1136 76e2f08a Michael Hanselmann
      else:
1137 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
1138 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
1139 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
1140 76e2f08a Michael Hanselmann
        #
1141 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
1142 887c7aa6 Michael Hanselmann
        # everybody else can use the instances at the same time. If we are
1143 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
1144 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
1145 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
1146 887c7aa6 Michael Hanselmann
        if not self.__lock.acquire(shared=shared, priority=priority,
1147 7e8841bd Michael Hanselmann
                                   timeout=running_timeout.Remaining()):
1148 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1149 76e2f08a Michael Hanselmann
        try:
1150 76e2f08a Michael Hanselmann
          # note we own the set-lock
1151 76e2f08a Michael Hanselmann
          self._add_owned()
1152 76e2f08a Michael Hanselmann
1153 887c7aa6 Michael Hanselmann
          return self.__acquire_inner(self.__names(), True, shared, priority,
1154 7e8841bd Michael Hanselmann
                                      running_timeout.Remaining, test_notify)
1155 76e2f08a Michael Hanselmann
        except:
1156 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1157 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1158 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
1159 5aab242c Michael Hanselmann
          self.__lock.release()
1160 76e2f08a Michael Hanselmann
          self._del_owned()
1161 76e2f08a Michael Hanselmann
          raise
1162 5aab242c Michael Hanselmann
1163 5aab242c Michael Hanselmann
    except _AcquireTimeout:
1164 5aab242c Michael Hanselmann
      return None
1165 aaae9bc0 Guido Trotter
1166 887c7aa6 Michael Hanselmann
  def __acquire_inner(self, names, want_all, shared, priority,
1167 887c7aa6 Michael Hanselmann
                      timeout_fn, test_notify):
1168 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
1169 7e8841bd Michael Hanselmann

1170 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
1171 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
1172 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
1173 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
1174 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1175 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1176 76e2f08a Michael Hanselmann

1177 76e2f08a Michael Hanselmann
    """
1178 76e2f08a Michael Hanselmann
    acquire_list = []
1179 76e2f08a Michael Hanselmann
1180 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
1181 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
1182 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
1183 71e1863e Michael Hanselmann
    # deadlocks.
1184 71e1863e Michael Hanselmann
    for lname in sorted(utils.UniqueSequence(names)):
1185 76e2f08a Michael Hanselmann
      try:
1186 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
1187 76e2f08a Michael Hanselmann
      except KeyError:
1188 76e2f08a Michael Hanselmann
        if want_all:
1189 76e2f08a Michael Hanselmann
          # We are acquiring all the set, it doesn't matter if this particular
1190 76e2f08a Michael Hanselmann
          # element is not there anymore.
1191 76e2f08a Michael Hanselmann
          continue
1192 76e2f08a Michael Hanselmann
1193 e1137eb6 Michael Hanselmann
        raise errors.LockError("Non-existing lock %s in set %s (it may have"
1194 e1137eb6 Michael Hanselmann
                               " been removed)" % (lname, self.name))
1195 76e2f08a Michael Hanselmann
1196 9b154270 Michael Hanselmann
      acquire_list.append((lname, lock))
1197 9b154270 Michael Hanselmann
1198 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
1199 76e2f08a Michael Hanselmann
    acquired = set()
1200 76e2f08a Michael Hanselmann
1201 76e2f08a Michael Hanselmann
    try:
1202 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
1203 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
1204 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
1205 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
1206 76e2f08a Michael Hanselmann
      # lock gets deleted.
1207 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
1208 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
1209 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
1210 76e2f08a Michael Hanselmann
        else:
1211 76e2f08a Michael Hanselmann
          test_notify_fn = None
1212 76e2f08a Michael Hanselmann
1213 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
1214 76e2f08a Michael Hanselmann
1215 76e2f08a Michael Hanselmann
        try:
1216 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
1217 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
1218 887c7aa6 Michael Hanselmann
                                     priority=priority,
1219 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
1220 76e2f08a Michael Hanselmann
        except errors.LockError:
1221 76e2f08a Michael Hanselmann
          if want_all:
1222 76e2f08a Michael Hanselmann
            # We are acquiring all the set, it doesn't matter if this
1223 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
1224 76e2f08a Michael Hanselmann
            continue
1225 76e2f08a Michael Hanselmann
1226 e1137eb6 Michael Hanselmann
          raise errors.LockError("Non-existing lock %s in set %s (it may"
1227 e1137eb6 Michael Hanselmann
                                 " have been removed)" % (lname, self.name))
1228 76e2f08a Michael Hanselmann
1229 76e2f08a Michael Hanselmann
        if not acq_success:
1230 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
1231 76e2f08a Michael Hanselmann
          if timeout is None:
1232 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
1233 76e2f08a Michael Hanselmann
            # blocking.
1234 7f93570a Iustin Pop
            raise errors.LockError("Failed to get lock %s (set %s)" %
1235 7f93570a Iustin Pop
                                   (lname, self.name))
1236 76e2f08a Michael Hanselmann
1237 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1238 76e2f08a Michael Hanselmann
1239 76e2f08a Michael Hanselmann
        try:
1240 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
1241 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
1242 76e2f08a Michael Hanselmann
          acquired.add(lname)
1243 76e2f08a Michael Hanselmann
1244 76e2f08a Michael Hanselmann
        except:
1245 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1246 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1247 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
1248 ee2b99e3 Michael Hanselmann
          if lock.is_owned():
1249 76e2f08a Michael Hanselmann
            lock.release()
1250 76e2f08a Michael Hanselmann
          raise
1251 76e2f08a Michael Hanselmann
1252 76e2f08a Michael Hanselmann
    except:
1253 76e2f08a Michael Hanselmann
      # Release all owned locks
1254 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
1255 76e2f08a Michael Hanselmann
      raise
1256 76e2f08a Michael Hanselmann
1257 0cc00929 Guido Trotter
    return acquired
1258 aaae9bc0 Guido Trotter
1259 3dbe3ddf Michael Hanselmann
  def downgrade(self, names=None):
1260 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1261 3dbe3ddf Michael Hanselmann

1262 3dbe3ddf Michael Hanselmann
    The locks must have been acquired in exclusive mode.
1263 3dbe3ddf Michael Hanselmann

1264 3dbe3ddf Michael Hanselmann
    """
1265 ee2b99e3 Michael Hanselmann
    assert self.is_owned(), ("downgrade on lockset %s while not owning any"
1266 ee2b99e3 Michael Hanselmann
                             " lock" % self.name)
1267 3dbe3ddf Michael Hanselmann
1268 3dbe3ddf Michael Hanselmann
    # Support passing in a single resource to downgrade rather than many
1269 3dbe3ddf Michael Hanselmann
    if isinstance(names, basestring):
1270 3dbe3ddf Michael Hanselmann
      names = [names]
1271 3dbe3ddf Michael Hanselmann
1272 ee2b99e3 Michael Hanselmann
    owned = self.list_owned()
1273 3dbe3ddf Michael Hanselmann
1274 3dbe3ddf Michael Hanselmann
    if names is None:
1275 3dbe3ddf Michael Hanselmann
      names = owned
1276 3dbe3ddf Michael Hanselmann
    else:
1277 3dbe3ddf Michael Hanselmann
      names = set(names)
1278 3dbe3ddf Michael Hanselmann
      assert owned.issuperset(names), \
1279 3dbe3ddf Michael Hanselmann
        ("downgrade() on unheld resources %s (set %s)" %
1280 3dbe3ddf Michael Hanselmann
         (names.difference(owned), self.name))
1281 3dbe3ddf Michael Hanselmann
1282 3dbe3ddf Michael Hanselmann
    for lockname in names:
1283 3dbe3ddf Michael Hanselmann
      self.__lockdict[lockname].downgrade()
1284 3dbe3ddf Michael Hanselmann
1285 3dbe3ddf Michael Hanselmann
    # Do we own the lockset in exclusive mode?
1286 ee2b99e3 Michael Hanselmann
    if self.__lock.is_owned(shared=0):
1287 3dbe3ddf Michael Hanselmann
      # Have all locks been downgraded?
1288 ee2b99e3 Michael Hanselmann
      if not compat.any(lock.is_owned(shared=0)
1289 3dbe3ddf Michael Hanselmann
                        for lock in self.__lockdict.values()):
1290 3dbe3ddf Michael Hanselmann
        self.__lock.downgrade()
1291 ee2b99e3 Michael Hanselmann
        assert self.__lock.is_owned(shared=1)
1292 3dbe3ddf Michael Hanselmann
1293 3dbe3ddf Michael Hanselmann
    return True
1294 3dbe3ddf Michael Hanselmann
1295 aaae9bc0 Guido Trotter
  def release(self, names=None):
1296 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
1297 aaae9bc0 Guido Trotter

1298 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1299 aaae9bc0 Guido Trotter
    before releasing them.
1300 aaae9bc0 Guido Trotter

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

1305 aaae9bc0 Guido Trotter
    """
1306 ee2b99e3 Michael Hanselmann
    assert self.is_owned(), ("release() on lock set %s while not owner" %
1307 ee2b99e3 Michael Hanselmann
                             self.name)
1308 aaae9bc0 Guido Trotter
1309 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1310 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1311 aaae9bc0 Guido Trotter
      names = [names]
1312 aaae9bc0 Guido Trotter
1313 aaae9bc0 Guido Trotter
    if names is None:
1314 ee2b99e3 Michael Hanselmann
      names = self.list_owned()
1315 aaae9bc0 Guido Trotter
    else:
1316 aaae9bc0 Guido Trotter
      names = set(names)
1317 ee2b99e3 Michael Hanselmann
      assert self.list_owned().issuperset(names), (
1318 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1319 ee2b99e3 Michael Hanselmann
               (names.difference(self.list_owned()), self.name))
1320 aaae9bc0 Guido Trotter
1321 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1322 3b7ed473 Guido Trotter
    # After this 'add' can work again
1323 ee2b99e3 Michael Hanselmann
    if self.__lock.is_owned():
1324 3b7ed473 Guido Trotter
      self.__lock.release()
1325 b2dabfd6 Guido Trotter
      self._del_owned()
1326 3b7ed473 Guido Trotter
1327 aaae9bc0 Guido Trotter
    for lockname in names:
1328 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1329 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1330 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1331 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1332 aaae9bc0 Guido Trotter
1333 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1334 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1335 aaae9bc0 Guido Trotter

1336 ec44d893 Guido Trotter
    @type names: list of strings
1337 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1338 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1339 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1340 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1341 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1342 aaae9bc0 Guido Trotter

1343 aaae9bc0 Guido Trotter
    """
1344 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1345 ee2b99e3 Michael Hanselmann
    assert not self.is_owned() or self.__lock.is_owned(shared=0), \
1346 7f93570a Iustin Pop
      ("Cannot add locks if the set %s is only partially owned, or shared" %
1347 7f93570a Iustin Pop
       self.name)
1348 3b7ed473 Guido Trotter
1349 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1350 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1351 aaae9bc0 Guido Trotter
      names = [names]
1352 aaae9bc0 Guido Trotter
1353 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1354 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1355 3b7ed473 Guido Trotter
    release_lock = False
1356 ee2b99e3 Michael Hanselmann
    if not self.__lock.is_owned():
1357 3b7ed473 Guido Trotter
      release_lock = True
1358 3b7ed473 Guido Trotter
      self.__lock.acquire()
1359 3b7ed473 Guido Trotter
1360 aaae9bc0 Guido Trotter
    try:
1361 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1362 aaae9bc0 Guido Trotter
      if invalid_names:
1363 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1364 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1365 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1366 7f93570a Iustin Pop
        raise errors.LockError("duplicate add(%s) on lockset %s" %
1367 7f93570a Iustin Pop
                               (invalid_names, self.name))
1368 aaae9bc0 Guido Trotter
1369 aaae9bc0 Guido Trotter
      for lockname in names:
1370 19b9ba9a Michael Hanselmann
        lock = SharedLock(self._GetLockName(lockname), monitor=self.__monitor)
1371 aaae9bc0 Guido Trotter
1372 aaae9bc0 Guido Trotter
        if acquired:
1373 887c7aa6 Michael Hanselmann
          # No need for priority or timeout here as this lock has just been
1374 887c7aa6 Michael Hanselmann
          # created
1375 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1376 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1377 aaae9bc0 Guido Trotter
          try:
1378 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1379 aaae9bc0 Guido Trotter
          except:
1380 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1381 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1382 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1383 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1384 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1385 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1386 aaae9bc0 Guido Trotter
            lock.release()
1387 aaae9bc0 Guido Trotter
            raise
1388 aaae9bc0 Guido Trotter
1389 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1390 aaae9bc0 Guido Trotter
1391 aaae9bc0 Guido Trotter
    finally:
1392 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1393 3b7ed473 Guido Trotter
      if release_lock:
1394 3b7ed473 Guido Trotter
        self.__lock.release()
1395 aaae9bc0 Guido Trotter
1396 aaae9bc0 Guido Trotter
    return True
1397 aaae9bc0 Guido Trotter
1398 5e0a6daf Michael Hanselmann
  def remove(self, names):
1399 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1400 aaae9bc0 Guido Trotter

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

1404 ec44d893 Guido Trotter
    @type names: list of strings
1405 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1406 aaae9bc0 Guido Trotter

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

1411 aaae9bc0 Guido Trotter
    """
1412 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1413 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1414 aaae9bc0 Guido Trotter
      names = [names]
1415 aaae9bc0 Guido Trotter
1416 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1417 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1418 aaae9bc0 Guido Trotter
    # by the lock itself.
1419 ee2b99e3 Michael Hanselmann
    assert not self.is_owned() or self.list_owned().issuperset(names), (
1420 7f93570a Iustin Pop
      "remove() on acquired lockset %s while not owning all elements" %
1421 7f93570a Iustin Pop
      self.name)
1422 aaae9bc0 Guido Trotter
1423 3f404fc5 Guido Trotter
    removed = []
1424 aaae9bc0 Guido Trotter
1425 aaae9bc0 Guido Trotter
    for lname in names:
1426 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1427 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1428 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1429 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1430 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1431 aaae9bc0 Guido Trotter
      try:
1432 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1433 3f404fc5 Guido Trotter
        removed.append(lname)
1434 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1435 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1436 ee2b99e3 Michael Hanselmann
        assert not self.is_owned(), ("remove failed while holding lockset %s" %
1437 ee2b99e3 Michael Hanselmann
                                     self.name)
1438 aaae9bc0 Guido Trotter
      else:
1439 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1440 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1441 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1442 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1443 aaae9bc0 Guido Trotter
        #
1444 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1445 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1446 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1447 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1448 ee2b99e3 Michael Hanselmann
        if self.is_owned():
1449 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1450 aaae9bc0 Guido Trotter
1451 3f404fc5 Guido Trotter
    return removed
1452 aaae9bc0 Guido Trotter
1453 7ee7c0c7 Guido Trotter
1454 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1455 7ee7c0c7 Guido Trotter
# Current rules are:
1456 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1457 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1458 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1459 7ee7c0c7 Guido Trotter
#   avoided.
1460 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1461 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1462 7ee7c0c7 Guido Trotter
#   the same time.
1463 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1464 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1465 819ca990 Guido Trotter
LEVEL_NODEGROUP = 2
1466 819ca990 Guido Trotter
LEVEL_NODE = 3
1467 e02ee261 Helga Velroyen
#: Level for node resources, used for operations with possibly high impact on
1468 e02ee261 Helga Velroyen
#: the node's disks.
1469 4e070776 Michael Hanselmann
LEVEL_NODE_RES = 4
1470 7ee7c0c7 Guido Trotter
1471 4e070776 Michael Hanselmann
LEVELS = [
1472 4e070776 Michael Hanselmann
  LEVEL_CLUSTER,
1473 4e070776 Michael Hanselmann
  LEVEL_INSTANCE,
1474 4e070776 Michael Hanselmann
  LEVEL_NODEGROUP,
1475 4e070776 Michael Hanselmann
  LEVEL_NODE,
1476 4e070776 Michael Hanselmann
  LEVEL_NODE_RES,
1477 4e070776 Michael Hanselmann
  ]
1478 7ee7c0c7 Guido Trotter
1479 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1480 4e070776 Michael Hanselmann
LEVELS_MOD = frozenset([
1481 4e070776 Michael Hanselmann
  LEVEL_NODE_RES,
1482 4e070776 Michael Hanselmann
  LEVEL_NODE,
1483 4e070776 Michael Hanselmann
  LEVEL_NODEGROUP,
1484 4e070776 Michael Hanselmann
  LEVEL_INSTANCE,
1485 4e070776 Michael Hanselmann
  ])
1486 7ee7c0c7 Guido Trotter
1487 5d7a899e Michael Hanselmann
#: Lock level names (make sure to use singular form)
1488 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1489 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1490 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1491 819ca990 Guido Trotter
  LEVEL_NODEGROUP: "nodegroup",
1492 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1493 5d7a899e Michael Hanselmann
  LEVEL_NODE_RES: "node-res",
1494 ea205dbc Michael Hanselmann
  }
1495 ea205dbc Michael Hanselmann
1496 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1497 3ccb3a64 Michael Hanselmann
BGL = "BGL"
1498 7ee7c0c7 Guido Trotter
1499 7ee7c0c7 Guido Trotter
1500 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1501 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1502 7ee7c0c7 Guido Trotter

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

1508 7ee7c0c7 Guido Trotter
  """
1509 7ee7c0c7 Guido Trotter
  _instance = None
1510 7ee7c0c7 Guido Trotter
1511 819ca990 Guido Trotter
  def __init__(self, nodes, nodegroups, instances):
1512 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1513 7ee7c0c7 Guido Trotter

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

1517 c41eea6e Iustin Pop
    @param nodes: list of node names
1518 819ca990 Guido Trotter
    @param nodegroups: list of nodegroup uuids
1519 c41eea6e Iustin Pop
    @param instances: list of instance names
1520 7ee7c0c7 Guido Trotter

1521 7ee7c0c7 Guido Trotter
    """
1522 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1523 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1524 c41eea6e Iustin Pop
1525 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1526 7ee7c0c7 Guido Trotter
1527 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1528 19b9ba9a Michael Hanselmann
1529 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1530 7ee7c0c7 Guido Trotter
    # locking order.
1531 7ee7c0c7 Guido Trotter
    self.__keyring = {
1532 5d7a899e Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "cluster", monitor=self._monitor),
1533 5d7a899e Michael Hanselmann
      LEVEL_NODE: LockSet(nodes, "node", monitor=self._monitor),
1534 5d7a899e Michael Hanselmann
      LEVEL_NODE_RES: LockSet(nodes, "node-res", monitor=self._monitor),
1535 5d7a899e Michael Hanselmann
      LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroup", monitor=self._monitor),
1536 5d7a899e Michael Hanselmann
      LEVEL_INSTANCE: LockSet(instances, "instance",
1537 19b9ba9a Michael Hanselmann
                              monitor=self._monitor),
1538 19b9ba9a Michael Hanselmann
      }
1539 19b9ba9a Michael Hanselmann
1540 5d7a899e Michael Hanselmann
    assert compat.all(ls.name == LEVEL_NAMES[level]
1541 5d7a899e Michael Hanselmann
                      for (level, ls) in self.__keyring.items())
1542 5d7a899e Michael Hanselmann
1543 4c03b2b5 Michael Hanselmann
  def AddToLockMonitor(self, provider):
1544 4c03b2b5 Michael Hanselmann
    """Registers a new lock with the monitor.
1545 4c03b2b5 Michael Hanselmann

1546 4c03b2b5 Michael Hanselmann
    See L{LockMonitor.RegisterLock}.
1547 4c03b2b5 Michael Hanselmann

1548 4c03b2b5 Michael Hanselmann
    """
1549 4c03b2b5 Michael Hanselmann
    return self._monitor.RegisterLock(provider)
1550 4c03b2b5 Michael Hanselmann
1551 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1552 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1553 19b9ba9a Michael Hanselmann

1554 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1555 19b9ba9a Michael Hanselmann

1556 19b9ba9a Michael Hanselmann
    """
1557 24d16f76 Michael Hanselmann
    return self._monitor.QueryLocks(fields)
1558 24d16f76 Michael Hanselmann
1559 7ee7c0c7 Guido Trotter
  def _names(self, level):
1560 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1561 7ee7c0c7 Guido Trotter

1562 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1563 c41eea6e Iustin Pop

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

1566 7ee7c0c7 Guido Trotter
    """
1567 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1568 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1569 7ee7c0c7 Guido Trotter
1570 ee2b99e3 Michael Hanselmann
  def is_owned(self, level):
1571 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1572 7ee7c0c7 Guido Trotter

1573 7ee7c0c7 Guido Trotter
    """
1574 ee2b99e3 Michael Hanselmann
    return self.__keyring[level].is_owned()
1575 7ee7c0c7 Guido Trotter
1576 ee2b99e3 Michael Hanselmann
  def list_owned(self, level):
1577 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1578 7ee7c0c7 Guido Trotter

1579 7ee7c0c7 Guido Trotter
    """
1580 ee2b99e3 Michael Hanselmann
    return self.__keyring[level].list_owned()
1581 07cba1bc Michael Hanselmann
1582 c6a622cf Michael Hanselmann
  def check_owned(self, level, names, shared=-1):
1583 c6a622cf Michael Hanselmann
    """Check if locks at a certain level are owned in a specific mode.
1584 c6a622cf Michael Hanselmann

1585 c6a622cf Michael Hanselmann
    @see: L{LockSet.check_owned}
1586 c6a622cf Michael Hanselmann

1587 c6a622cf Michael Hanselmann
    """
1588 c6a622cf Michael Hanselmann
    return self.__keyring[level].check_owned(names, shared=shared)
1589 c6a622cf Michael Hanselmann
1590 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1591 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1592 7ee7c0c7 Guido Trotter

1593 7ee7c0c7 Guido Trotter
    """
1594 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1595 7ee7c0c7 Guido Trotter
    # the test cases.
1596 ee2b99e3 Michael Hanselmann
    return compat.any((self.is_owned(l) for l in LEVELS[level + 1:]))
1597 7ee7c0c7 Guido Trotter
1598 b459a848 Andrea Spadaccini
  def _BGL_owned(self): # pylint: disable=C0103
1599 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1600 7ee7c0c7 Guido Trotter

1601 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1602 7ee7c0c7 Guido Trotter

1603 7ee7c0c7 Guido Trotter
    """
1604 ee2b99e3 Michael Hanselmann
    return BGL in self.__keyring[LEVEL_CLUSTER].list_owned()
1605 7ee7c0c7 Guido Trotter
1606 c70d2d9b Iustin Pop
  @staticmethod
1607 b459a848 Andrea Spadaccini
  def _contains_BGL(level, names): # pylint: disable=C0103
1608 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1609 c41eea6e Iustin Pop

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

1613 7ee7c0c7 Guido Trotter
    """
1614 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1615 7ee7c0c7 Guido Trotter
1616 b30d95b6 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None):
1617 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1618 7ee7c0c7 Guido Trotter

1619 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1620 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1621 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1622 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1623 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1624 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1625 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1626 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1627 5e0a6daf Michael Hanselmann
    @type timeout: float
1628 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1629 b30d95b6 Michael Hanselmann
    @type priority: integer
1630 b30d95b6 Michael Hanselmann
    @param priority: Priority for acquiring lock
1631 7ee7c0c7 Guido Trotter

1632 7ee7c0c7 Guido Trotter
    """
1633 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1634 7ee7c0c7 Guido Trotter
1635 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1636 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1637 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1638 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1639 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1640 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1641 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1642 5ae4945a Iustin Pop
      "You must own the Big Ganeti Lock before acquiring any other")
1643 7ee7c0c7 Guido Trotter
1644 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1645 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1646 5ae4945a Iustin Pop
                                          " while owning some at a greater one")
1647 7ee7c0c7 Guido Trotter
1648 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1649 b30d95b6 Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout,
1650 b30d95b6 Michael Hanselmann
                                         priority=priority)
1651 7ee7c0c7 Guido Trotter
1652 3dbe3ddf Michael Hanselmann
  def downgrade(self, level, names=None):
1653 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1654 3dbe3ddf Michael Hanselmann

1655 3dbe3ddf Michael Hanselmann
    You must have acquired the locks in exclusive mode.
1656 3dbe3ddf Michael Hanselmann

1657 3dbe3ddf Michael Hanselmann
    @type level: member of locking.LEVELS
1658 3dbe3ddf Michael Hanselmann
    @param level: the level at which the locks shall be downgraded
1659 3dbe3ddf Michael Hanselmann
    @type names: list of strings, or None
1660 3dbe3ddf Michael Hanselmann
    @param names: the names of the locks which shall be downgraded
1661 3dbe3ddf Michael Hanselmann
        (defaults to all the locks acquired at the level)
1662 3dbe3ddf Michael Hanselmann

1663 3dbe3ddf Michael Hanselmann
    """
1664 3dbe3ddf Michael Hanselmann
    assert level in LEVELS, "Invalid locking level %s" % level
1665 3dbe3ddf Michael Hanselmann
1666 3dbe3ddf Michael Hanselmann
    return self.__keyring[level].downgrade(names=names)
1667 3dbe3ddf Michael Hanselmann
1668 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1669 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1670 7ee7c0c7 Guido Trotter

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

1674 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1675 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1676 ec44d893 Guido Trotter
    @type names: list of strings, or None
1677 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1678 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1679 7ee7c0c7 Guido Trotter

1680 7ee7c0c7 Guido Trotter
    """
1681 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1682 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1683 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1684 5ae4945a Iustin Pop
              "Cannot release the Big Ganeti Lock while holding something"
1685 5ae4945a Iustin Pop
              " at upper levels (%r)" %
1686 5ae4945a Iustin Pop
              (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self.list_owned(i))
1687 5ae4945a Iustin Pop
                                for i in self.__keyring.keys()]), ))
1688 7ee7c0c7 Guido Trotter
1689 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1690 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1691 7ee7c0c7 Guido Trotter
1692 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1693 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1694 7ee7c0c7 Guido Trotter

1695 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1696 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1697 ec44d893 Guido Trotter
    @type names: list of strings
1698 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1699 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1700 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1701 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1702 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1703 c41eea6e Iustin Pop

1704 7ee7c0c7 Guido Trotter
    """
1705 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1706 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1707 5ae4945a Iustin Pop
                               " operations")
1708 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1709 5ae4945a Iustin Pop
                                          " while owning some at a greater one")
1710 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1711 7ee7c0c7 Guido Trotter
1712 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1713 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1714 7ee7c0c7 Guido Trotter

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

1718 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1719 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1720 ec44d893 Guido Trotter
    @type names: list of strings
1721 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1722 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1723 7ee7c0c7 Guido Trotter

1724 7ee7c0c7 Guido Trotter
    """
1725 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1726 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1727 5ae4945a Iustin Pop
                               " operations")
1728 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1729 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1730 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1731 ee2b99e3 Michael Hanselmann
    assert self.is_owned(level) or not self._upper_owned(level), (
1732 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1733 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1734 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1735 19b9ba9a Michael Hanselmann
1736 19b9ba9a Michael Hanselmann
1737 44b4eddc Michael Hanselmann
def _MonitorSortKey((item, idx, num)):
1738 e4e35357 Michael Hanselmann
  """Sorting key function.
1739 e4e35357 Michael Hanselmann

1740 44b4eddc Michael Hanselmann
  Sort by name, registration order and then order of information. This provides
1741 44b4eddc Michael Hanselmann
  a stable sort order over different providers, even if they return the same
1742 44b4eddc Michael Hanselmann
  name.
1743 e4e35357 Michael Hanselmann

1744 e4e35357 Michael Hanselmann
  """
1745 e4e35357 Michael Hanselmann
  (name, _, _, _) = item
1746 e4e35357 Michael Hanselmann
1747 44b4eddc Michael Hanselmann
  return (utils.NiceSortKey(name), num, idx)
1748 e4e35357 Michael Hanselmann
1749 e4e35357 Michael Hanselmann
1750 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1751 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1752 19b9ba9a Michael Hanselmann
1753 19b9ba9a Michael Hanselmann
  def __init__(self):
1754 19b9ba9a Michael Hanselmann
    """Initializes this class.
1755 19b9ba9a Michael Hanselmann

1756 19b9ba9a Michael Hanselmann
    """
1757 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1758 19b9ba9a Michael Hanselmann
1759 e4e35357 Michael Hanselmann
    # Counter for stable sorting
1760 e4e35357 Michael Hanselmann
    self._counter = itertools.count(0)
1761 e4e35357 Michael Hanselmann
1762 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1763 19b9ba9a Michael Hanselmann
    # references and deletion.
1764 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1765 19b9ba9a Michael Hanselmann
1766 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1767 44b4eddc Michael Hanselmann
  def RegisterLock(self, provider):
1768 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1769 19b9ba9a Michael Hanselmann

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

1778 19b9ba9a Michael Hanselmann
    """
1779 44b4eddc Michael Hanselmann
    assert provider not in self._locks, "Duplicate registration"
1780 e4e35357 Michael Hanselmann
1781 e4e35357 Michael Hanselmann
    # There used to be a check for duplicate names here. As it turned out, when
1782 e4e35357 Michael Hanselmann
    # a lock is re-created with the same name in a very short timeframe, the
1783 e4e35357 Michael Hanselmann
    # previous instance might not yet be removed from the weakref dictionary.
1784 e4e35357 Michael Hanselmann
    # By keeping track of the order of incoming registrations, a stable sort
1785 e4e35357 Michael Hanselmann
    # ordering can still be guaranteed.
1786 e4e35357 Michael Hanselmann
1787 44b4eddc Michael Hanselmann
    self._locks[provider] = self._counter.next()
1788 19b9ba9a Michael Hanselmann
1789 24d16f76 Michael Hanselmann
  def _GetLockInfo(self, requested):
1790 44b4eddc Michael Hanselmann
    """Get information from all locks.
1791 19b9ba9a Michael Hanselmann

1792 19b9ba9a Michael Hanselmann
    """
1793 44b4eddc Michael Hanselmann
    # Must hold lock while getting consistent list of tracked items
1794 44b4eddc Michael Hanselmann
    self._lock.acquire(shared=1)
1795 44b4eddc Michael Hanselmann
    try:
1796 44b4eddc Michael Hanselmann
      items = self._locks.items()
1797 44b4eddc Michael Hanselmann
    finally:
1798 44b4eddc Michael Hanselmann
      self._lock.release()
1799 44b4eddc Michael Hanselmann
1800 44b4eddc Michael Hanselmann
    return [(info, idx, num)
1801 44b4eddc Michael Hanselmann
            for (provider, num) in items
1802 44b4eddc Michael Hanselmann
            for (idx, info) in enumerate(provider.GetLockInfo(requested))]
1803 19b9ba9a Michael Hanselmann
1804 24d16f76 Michael Hanselmann
  def _Query(self, fields):
1805 24d16f76 Michael Hanselmann
    """Queries information from all locks.
1806 19b9ba9a Michael Hanselmann

1807 24d16f76 Michael Hanselmann
    @type fields: list of strings
1808 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1809 24d16f76 Michael Hanselmann

1810 24d16f76 Michael Hanselmann
    """
1811 24d16f76 Michael Hanselmann
    qobj = query.Query(query.LOCK_FIELDS, fields)
1812 24d16f76 Michael Hanselmann
1813 e4e35357 Michael Hanselmann
    # Get all data with internal lock held and then sort by name and incoming
1814 e4e35357 Michael Hanselmann
    # order
1815 e4e35357 Michael Hanselmann
    lockinfo = sorted(self._GetLockInfo(qobj.RequestedData()),
1816 e4e35357 Michael Hanselmann
                      key=_MonitorSortKey)
1817 24d16f76 Michael Hanselmann
1818 e4e35357 Michael Hanselmann
    # Extract lock information and build query data
1819 eb62069e Iustin Pop
    return (qobj, query.LockQueryData(map(compat.fst, lockinfo)))
1820 19b9ba9a Michael Hanselmann
1821 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1822 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1823 19b9ba9a Michael Hanselmann

1824 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1825 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1826 19b9ba9a Michael Hanselmann

1827 19b9ba9a Michael Hanselmann
    """
1828 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1829 19b9ba9a Michael Hanselmann
1830 24d16f76 Michael Hanselmann
    # Prepare query response
1831 24d16f76 Michael Hanselmann
    return query.GetQueryResponse(qobj, ctx)