Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 03c5291c

History | View | Annotate | Download (56.2 kB)

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

58 42a999d1 Guido Trotter
  Calls the function holding the given lock, either in exclusive or shared
59 42a999d1 Guido Trotter
  mode. It requires the passed lock to be a SharedLock (or support its
60 42a999d1 Guido Trotter
  semantics).
61 42a999d1 Guido Trotter

62 dbb11e8b Guido Trotter
  @type mylock: lockable object or string
63 dbb11e8b Guido Trotter
  @param mylock: lock to acquire or class member name of the lock to acquire
64 dbb11e8b Guido Trotter

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

86 d76167a5 Michael Hanselmann
  """
87 d76167a5 Michael Hanselmann
  __slots__ = [
88 d76167a5 Michael Hanselmann
    "_fd",
89 d76167a5 Michael Hanselmann
    "_poller",
90 d76167a5 Michael Hanselmann
    ]
91 d76167a5 Michael Hanselmann
92 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
93 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
94 d76167a5 Michael Hanselmann

95 d76167a5 Michael Hanselmann
    @type poller: select.poll
96 d76167a5 Michael Hanselmann
    @param poller: Poller object
97 d76167a5 Michael Hanselmann
    @type fd: int
98 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
99 d76167a5 Michael Hanselmann

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

108 d76167a5 Michael Hanselmann
    @type timeout: float or None
109 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
110 d76167a5 Michael Hanselmann

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

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

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

154 69b99987 Michael Hanselmann
    @type lock: threading.Lock
155 2419060d Guido Trotter
    @param lock: condition base lock
156 2419060d Guido Trotter

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

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

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

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

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

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

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

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

257 34cb5617 Guido Trotter
    @type timeout: float or None
258 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
259 d76167a5 Michael Hanselmann

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

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

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

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

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

324 48dabc6a Michael Hanselmann
    @type timeout: float or None
325 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
326 48dabc6a Michael Hanselmann

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

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

352 c31825f7 Michael Hanselmann
    """
353 c31825f7 Michael Hanselmann
    self._check_owned()
354 c31825f7 Michael Hanselmann
355 c31825f7 Michael Hanselmann
    return self._waiters
356 c31825f7 Michael Hanselmann
357 48dabc6a Michael Hanselmann
  def has_waiting(self):
358 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
359 48dabc6a Michael Hanselmann

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

379 887c7aa6 Michael Hanselmann
    """
380 887c7aa6 Michael Hanselmann
    self.shared = shared
381 887c7aa6 Michael Hanselmann
    PipeCondition.__init__(self, lock)
382 887c7aa6 Michael Hanselmann
383 887c7aa6 Michael Hanselmann
384 84e344d4 Michael Hanselmann
class SharedLock(object):
385 162c1c1f Guido Trotter
  """Implements a shared lock.
386 162c1c1f Guido Trotter

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

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

399 7f93570a Iustin Pop
  @type name: string
400 7f93570a Iustin Pop
  @ivar name: the name of the lock
401 7f93570a Iustin Pop

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

421 7f93570a Iustin Pop
    @param name: the name of the lock
422 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
423 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register
424 7f93570a Iustin Pop

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

461 24d16f76 Michael Hanselmann
    @type requested: set
462 24d16f76 Michael Hanselmann
    @param requested: Requested information, see C{query.LQ_*}
463 19b9ba9a Michael Hanselmann

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

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

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

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

537 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
538 162c1c1f Guido Trotter
    the internal lock.
539 162c1c1f Guido Trotter

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

551 c41eea6e Iustin Pop
    @param shared:
552 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
553 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
554 c41eea6e Iustin Pop
        - > 0: check for shared ownership
555 162c1c1f Guido Trotter

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

570 84e344d4 Michael Hanselmann
    @rtype: int
571 a95fd5d7 Guido Trotter

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

582 887c7aa6 Michael Hanselmann
    @rtype: bool
583 887c7aa6 Michael Hanselmann

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

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

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

618 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
619 887c7aa6 Michael Hanselmann

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

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

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

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

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

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

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

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

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

807 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
808 162c1c1f Guido Trotter
    before calling this function.
809 162c1c1f Guido Trotter

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

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

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

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

861 84e344d4 Michael Hanselmann
    @type timeout: float
862 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
863 887c7aa6 Michael Hanselmann
    @type priority: integer
864 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
865 a95fd5d7 Guido Trotter

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

919 5aab242c Michael Hanselmann
  """
920 5aab242c Michael Hanselmann
921 5aab242c Michael Hanselmann
922 aaae9bc0 Guido Trotter
class LockSet:
923 aaae9bc0 Guido Trotter
  """Implements a set of locks.
924 aaae9bc0 Guido Trotter

925 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
926 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
927 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
928 aaae9bc0 Guido Trotter
  preventing deadlock.
929 aaae9bc0 Guido Trotter

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

932 7f93570a Iustin Pop
  @type name: string
933 7f93570a Iustin Pop
  @ivar name: the name of the lockset
934 7f93570a Iustin Pop

935 aaae9bc0 Guido Trotter
  """
936 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
937 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
938 aaae9bc0 Guido Trotter

939 ec44d893 Guido Trotter
    @type members: list of strings
940 c41eea6e Iustin Pop
    @param members: initial members of the set
941 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
942 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
943 aaae9bc0 Guido Trotter

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

974 4fb780d1 Michael Hanselmann
    """
975 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
976 4fb780d1 Michael Hanselmann
977 3dbe3ddf Michael Hanselmann
  def _get_lock(self):
978 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock.
979 3dbe3ddf Michael Hanselmann

980 3dbe3ddf Michael Hanselmann
    """
981 3dbe3ddf Michael Hanselmann
    return self.__lock
982 3dbe3ddf Michael Hanselmann
983 3dbe3ddf Michael Hanselmann
  def _get_lockdict(self):
984 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock dictionary.
985 3dbe3ddf Michael Hanselmann

986 3dbe3ddf Michael Hanselmann
    Accessing this structure is only safe in single-thread usage or when the
987 3dbe3ddf Michael Hanselmann
    lockset-internal lock is held.
988 3dbe3ddf Michael Hanselmann

989 3dbe3ddf Michael Hanselmann
    """
990 3dbe3ddf Michael Hanselmann
    return self.__lockdict
991 3dbe3ddf Michael Hanselmann
992 ee2b99e3 Michael Hanselmann
  def is_owned(self):
993 c6a622cf Michael Hanselmann
    """Is the current thread a current level owner?
994 c6a622cf Michael Hanselmann

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

997 c6a622cf Michael Hanselmann
    """
998 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
999 aaae9bc0 Guido Trotter
1000 c6a622cf Michael Hanselmann
  def check_owned(self, names, shared=-1):
1001 c6a622cf Michael Hanselmann
    """Check if locks are owned in a specific mode.
1002 c6a622cf Michael Hanselmann

1003 c6a622cf Michael Hanselmann
    @type names: sequence or string
1004 c6a622cf Michael Hanselmann
    @param names: Lock names (or a single lock name)
1005 c6a622cf Michael Hanselmann
    @param shared: See L{SharedLock.is_owned}
1006 c6a622cf Michael Hanselmann
    @rtype: bool
1007 c6a622cf Michael Hanselmann
    @note: Use L{is_owned} to check if the current thread holds I{any} lock and
1008 c6a622cf Michael Hanselmann
      L{list_owned} to get the names of all owned locks
1009 c6a622cf Michael Hanselmann

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

1075 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
1076 aaae9bc0 Guido Trotter
    result after releasing the lock.
1077 aaae9bc0 Guido Trotter

1078 aaae9bc0 Guido Trotter
    """
1079 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
1080 aaae9bc0 Guido Trotter
1081 aaae9bc0 Guido Trotter
  def _names(self):
1082 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
1083 aaae9bc0 Guido Trotter

1084 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
1085 cdb08f44 Michael Hanselmann

1086 aaae9bc0 Guido Trotter
    """
1087 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
1088 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
1089 d4803c24 Guido Trotter
    release_lock = False
1090 ee2b99e3 Michael Hanselmann
    if not self.__lock.is_owned():
1091 d4803c24 Guido Trotter
      release_lock = True
1092 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
1093 aaae9bc0 Guido Trotter
    try:
1094 aaae9bc0 Guido Trotter
      result = self.__names()
1095 aaae9bc0 Guido Trotter
    finally:
1096 d4803c24 Guido Trotter
      if release_lock:
1097 d4803c24 Guido Trotter
        self.__lock.release()
1098 0cf257c5 Guido Trotter
    return set(result)
1099 aaae9bc0 Guido Trotter
1100 7100c2fa Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, priority=None,
1101 887c7aa6 Michael Hanselmann
              test_notify=None):
1102 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
1103 aaae9bc0 Guido Trotter

1104 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1105 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1106 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1107 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1108 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
1109 c41eea6e Iustin Pop
        exclusive lock will be acquired
1110 5aab242c Michael Hanselmann
    @type timeout: float or None
1111 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1112 887c7aa6 Michael Hanselmann
    @type priority: integer
1113 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1114 5aab242c Michael Hanselmann
    @type test_notify: callable or None
1115 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1116 aaae9bc0 Guido Trotter

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

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

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

1180 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
1181 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
1182 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
1183 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
1184 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1185 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1186 76e2f08a Michael Hanselmann

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

1272 3dbe3ddf Michael Hanselmann
    The locks must have been acquired in exclusive mode.
1273 3dbe3ddf Michael Hanselmann

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

1308 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1309 aaae9bc0 Guido Trotter
    before releasing them.
1310 aaae9bc0 Guido Trotter

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

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

1346 ec44d893 Guido Trotter
    @type names: list of strings
1347 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1348 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1349 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1350 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1351 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1352 aaae9bc0 Guido Trotter

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

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

1414 ec44d893 Guido Trotter
    @type names: list of strings
1415 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1416 aaae9bc0 Guido Trotter

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

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

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

1518 7ee7c0c7 Guido Trotter
  """
1519 7ee7c0c7 Guido Trotter
  _instance = None
1520 7ee7c0c7 Guido Trotter
1521 819ca990 Guido Trotter
  def __init__(self, nodes, nodegroups, instances):
1522 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1523 7ee7c0c7 Guido Trotter

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

1527 c41eea6e Iustin Pop
    @param nodes: list of node names
1528 819ca990 Guido Trotter
    @param nodegroups: list of nodegroup uuids
1529 c41eea6e Iustin Pop
    @param instances: list of instance names
1530 7ee7c0c7 Guido Trotter

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

1556 4c03b2b5 Michael Hanselmann
    See L{LockMonitor.RegisterLock}.
1557 4c03b2b5 Michael Hanselmann

1558 4c03b2b5 Michael Hanselmann
    """
1559 4c03b2b5 Michael Hanselmann
    return self._monitor.RegisterLock(provider)
1560 4c03b2b5 Michael Hanselmann
1561 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1562 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1563 19b9ba9a Michael Hanselmann

1564 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1565 19b9ba9a Michael Hanselmann

1566 19b9ba9a Michael Hanselmann
    """
1567 24d16f76 Michael Hanselmann
    return self._monitor.QueryLocks(fields)
1568 24d16f76 Michael Hanselmann
1569 7ee7c0c7 Guido Trotter
  def _names(self, level):
1570 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1571 7ee7c0c7 Guido Trotter

1572 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1573 c41eea6e Iustin Pop

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

1576 7ee7c0c7 Guido Trotter
    """
1577 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1578 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1579 7ee7c0c7 Guido Trotter
1580 ee2b99e3 Michael Hanselmann
  def is_owned(self, level):
1581 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1582 7ee7c0c7 Guido Trotter

1583 7ee7c0c7 Guido Trotter
    """
1584 ee2b99e3 Michael Hanselmann
    return self.__keyring[level].is_owned()
1585 7ee7c0c7 Guido Trotter
1586 ee2b99e3 Michael Hanselmann
  def list_owned(self, level):
1587 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1588 7ee7c0c7 Guido Trotter

1589 7ee7c0c7 Guido Trotter
    """
1590 ee2b99e3 Michael Hanselmann
    return self.__keyring[level].list_owned()
1591 07cba1bc Michael Hanselmann
1592 c6a622cf Michael Hanselmann
  def check_owned(self, level, names, shared=-1):
1593 c6a622cf Michael Hanselmann
    """Check if locks at a certain level are owned in a specific mode.
1594 c6a622cf Michael Hanselmann

1595 c6a622cf Michael Hanselmann
    @see: L{LockSet.check_owned}
1596 c6a622cf Michael Hanselmann

1597 c6a622cf Michael Hanselmann
    """
1598 c6a622cf Michael Hanselmann
    return self.__keyring[level].check_owned(names, shared=shared)
1599 c6a622cf Michael Hanselmann
1600 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1601 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1602 7ee7c0c7 Guido Trotter

1603 7ee7c0c7 Guido Trotter
    """
1604 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1605 7ee7c0c7 Guido Trotter
    # the test cases.
1606 ee2b99e3 Michael Hanselmann
    return compat.any((self.is_owned(l) for l in LEVELS[level + 1:]))
1607 7ee7c0c7 Guido Trotter
1608 b459a848 Andrea Spadaccini
  def _BGL_owned(self): # pylint: disable=C0103
1609 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1610 7ee7c0c7 Guido Trotter

1611 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1612 7ee7c0c7 Guido Trotter

1613 7ee7c0c7 Guido Trotter
    """
1614 ee2b99e3 Michael Hanselmann
    return BGL in self.__keyring[LEVEL_CLUSTER].list_owned()
1615 7ee7c0c7 Guido Trotter
1616 c70d2d9b Iustin Pop
  @staticmethod
1617 b459a848 Andrea Spadaccini
  def _contains_BGL(level, names): # pylint: disable=C0103
1618 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1619 c41eea6e Iustin Pop

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

1623 7ee7c0c7 Guido Trotter
    """
1624 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1625 7ee7c0c7 Guido Trotter
1626 b30d95b6 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None):
1627 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1628 7ee7c0c7 Guido Trotter

1629 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1630 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1631 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1632 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1633 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1634 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1635 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1636 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1637 5e0a6daf Michael Hanselmann
    @type timeout: float
1638 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1639 b30d95b6 Michael Hanselmann
    @type priority: integer
1640 b30d95b6 Michael Hanselmann
    @param priority: Priority for acquiring lock
1641 7ee7c0c7 Guido Trotter

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

1665 3dbe3ddf Michael Hanselmann
    You must have acquired the locks in exclusive mode.
1666 3dbe3ddf Michael Hanselmann

1667 3dbe3ddf Michael Hanselmann
    @type level: member of locking.LEVELS
1668 3dbe3ddf Michael Hanselmann
    @param level: the level at which the locks shall be downgraded
1669 3dbe3ddf Michael Hanselmann
    @type names: list of strings, or None
1670 3dbe3ddf Michael Hanselmann
    @param names: the names of the locks which shall be downgraded
1671 3dbe3ddf Michael Hanselmann
        (defaults to all the locks acquired at the level)
1672 3dbe3ddf Michael Hanselmann

1673 3dbe3ddf Michael Hanselmann
    """
1674 3dbe3ddf Michael Hanselmann
    assert level in LEVELS, "Invalid locking level %s" % level
1675 3dbe3ddf Michael Hanselmann
1676 3dbe3ddf Michael Hanselmann
    return self.__keyring[level].downgrade(names=names)
1677 3dbe3ddf Michael Hanselmann
1678 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1679 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1680 7ee7c0c7 Guido Trotter

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

1684 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1685 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1686 ec44d893 Guido Trotter
    @type names: list of strings, or None
1687 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1688 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1689 7ee7c0c7 Guido Trotter

1690 7ee7c0c7 Guido Trotter
    """
1691 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1692 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1693 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1694 5ae4945a Iustin Pop
              "Cannot release the Big Ganeti Lock while holding something"
1695 5ae4945a Iustin Pop
              " at upper levels (%r)" %
1696 5ae4945a Iustin Pop
              (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self.list_owned(i))
1697 5ae4945a Iustin Pop
                                for i in self.__keyring.keys()]), ))
1698 7ee7c0c7 Guido Trotter
1699 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1700 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1701 7ee7c0c7 Guido Trotter
1702 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1703 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1704 7ee7c0c7 Guido Trotter

1705 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1706 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1707 ec44d893 Guido Trotter
    @type names: list of strings
1708 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1709 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1710 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1711 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1712 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1713 c41eea6e Iustin Pop

1714 7ee7c0c7 Guido Trotter
    """
1715 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1716 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1717 5ae4945a Iustin Pop
                               " operations")
1718 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1719 5ae4945a Iustin Pop
                                          " while owning some at a greater one")
1720 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1721 7ee7c0c7 Guido Trotter
1722 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1723 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1724 7ee7c0c7 Guido Trotter

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

1728 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1729 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1730 ec44d893 Guido Trotter
    @type names: list of strings
1731 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1732 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1733 7ee7c0c7 Guido Trotter

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

1750 44b4eddc Michael Hanselmann
  Sort by name, registration order and then order of information. This provides
1751 44b4eddc Michael Hanselmann
  a stable sort order over different providers, even if they return the same
1752 44b4eddc Michael Hanselmann
  name.
1753 e4e35357 Michael Hanselmann

1754 e4e35357 Michael Hanselmann
  """
1755 e4e35357 Michael Hanselmann
  (name, _, _, _) = item
1756 e4e35357 Michael Hanselmann
1757 44b4eddc Michael Hanselmann
  return (utils.NiceSortKey(name), num, idx)
1758 e4e35357 Michael Hanselmann
1759 e4e35357 Michael Hanselmann
1760 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1761 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1762 19b9ba9a Michael Hanselmann
1763 19b9ba9a Michael Hanselmann
  def __init__(self):
1764 19b9ba9a Michael Hanselmann
    """Initializes this class.
1765 19b9ba9a Michael Hanselmann

1766 19b9ba9a Michael Hanselmann
    """
1767 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1768 19b9ba9a Michael Hanselmann
1769 e4e35357 Michael Hanselmann
    # Counter for stable sorting
1770 e4e35357 Michael Hanselmann
    self._counter = itertools.count(0)
1771 e4e35357 Michael Hanselmann
1772 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1773 19b9ba9a Michael Hanselmann
    # references and deletion.
1774 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1775 19b9ba9a Michael Hanselmann
1776 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1777 44b4eddc Michael Hanselmann
  def RegisterLock(self, provider):
1778 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1779 19b9ba9a Michael Hanselmann

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

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

1802 19b9ba9a Michael Hanselmann
    """
1803 44b4eddc Michael Hanselmann
    # Must hold lock while getting consistent list of tracked items
1804 44b4eddc Michael Hanselmann
    self._lock.acquire(shared=1)
1805 44b4eddc Michael Hanselmann
    try:
1806 44b4eddc Michael Hanselmann
      items = self._locks.items()
1807 44b4eddc Michael Hanselmann
    finally:
1808 44b4eddc Michael Hanselmann
      self._lock.release()
1809 44b4eddc Michael Hanselmann
1810 44b4eddc Michael Hanselmann
    return [(info, idx, num)
1811 44b4eddc Michael Hanselmann
            for (provider, num) in items
1812 44b4eddc Michael Hanselmann
            for (idx, info) in enumerate(provider.GetLockInfo(requested))]
1813 19b9ba9a Michael Hanselmann
1814 24d16f76 Michael Hanselmann
  def _Query(self, fields):
1815 24d16f76 Michael Hanselmann
    """Queries information from all locks.
1816 19b9ba9a Michael Hanselmann

1817 24d16f76 Michael Hanselmann
    @type fields: list of strings
1818 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1819 24d16f76 Michael Hanselmann

1820 24d16f76 Michael Hanselmann
    """
1821 24d16f76 Michael Hanselmann
    qobj = query.Query(query.LOCK_FIELDS, fields)
1822 24d16f76 Michael Hanselmann
1823 e4e35357 Michael Hanselmann
    # Get all data with internal lock held and then sort by name and incoming
1824 e4e35357 Michael Hanselmann
    # order
1825 e4e35357 Michael Hanselmann
    lockinfo = sorted(self._GetLockInfo(qobj.RequestedData()),
1826 e4e35357 Michael Hanselmann
                      key=_MonitorSortKey)
1827 24d16f76 Michael Hanselmann
1828 e4e35357 Michael Hanselmann
    # Extract lock information and build query data
1829 eb62069e Iustin Pop
    return (qobj, query.LockQueryData(map(compat.fst, lockinfo)))
1830 19b9ba9a Michael Hanselmann
1831 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1832 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1833 19b9ba9a Michael Hanselmann

1834 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1835 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1836 19b9ba9a Michael Hanselmann

1837 19b9ba9a Michael Hanselmann
    """
1838 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1839 19b9ba9a Michael Hanselmann
1840 24d16f76 Michael Hanselmann
    # Prepare query response
1841 24d16f76 Michael Hanselmann
    return query.GetQueryResponse(qobj, ctx)