Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 8062638d

History | View | Annotate | Download (44.7 kB)

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

44 42a999d1 Guido Trotter
  Calls the function holding the given lock, either in exclusive or shared
45 42a999d1 Guido Trotter
  mode. It requires the passed lock to be a SharedLock (or support its
46 42a999d1 Guido Trotter
  semantics).
47 42a999d1 Guido Trotter

48 dbb11e8b Guido Trotter
  @type mylock: lockable object or string
49 dbb11e8b Guido Trotter
  @param mylock: lock to acquire or class member name of the lock to acquire
50 dbb11e8b Guido Trotter

51 42a999d1 Guido Trotter
  """
52 42a999d1 Guido Trotter
  def wrap(fn):
53 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
54 dbb11e8b Guido Trotter
      if isinstance(mylock, basestring):
55 dbb11e8b Guido Trotter
        assert args, "cannot ssynchronize on non-class method: self not found"
56 dbb11e8b Guido Trotter
        # args[0] is "self"
57 dbb11e8b Guido Trotter
        lock = getattr(args[0], mylock)
58 dbb11e8b Guido Trotter
      else:
59 dbb11e8b Guido Trotter
        lock = mylock
60 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
61 42a999d1 Guido Trotter
      try:
62 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
63 42a999d1 Guido Trotter
      finally:
64 42a999d1 Guido Trotter
        lock.release()
65 42a999d1 Guido Trotter
    return sync_function
66 42a999d1 Guido Trotter
  return wrap
67 42a999d1 Guido Trotter
68 42a999d1 Guido Trotter
69 7e8841bd Michael Hanselmann
class RunningTimeout(object):
70 7e8841bd Michael Hanselmann
  """Class to calculate remaining timeout when doing several operations.
71 7e8841bd Michael Hanselmann

72 7e8841bd Michael Hanselmann
  """
73 7e8841bd Michael Hanselmann
  __slots__ = [
74 7e8841bd Michael Hanselmann
    "_allow_negative",
75 7e8841bd Michael Hanselmann
    "_start_time",
76 7e8841bd Michael Hanselmann
    "_time_fn",
77 7e8841bd Michael Hanselmann
    "_timeout",
78 7e8841bd Michael Hanselmann
    ]
79 7e8841bd Michael Hanselmann
80 7e8841bd Michael Hanselmann
  def __init__(self, timeout, allow_negative, _time_fn=time.time):
81 7e8841bd Michael Hanselmann
    """Initializes this class.
82 7e8841bd Michael Hanselmann

83 7e8841bd Michael Hanselmann
    @type timeout: float
84 7e8841bd Michael Hanselmann
    @param timeout: Timeout duration
85 7e8841bd Michael Hanselmann
    @type allow_negative: bool
86 7e8841bd Michael Hanselmann
    @param allow_negative: Whether to return values below zero
87 7e8841bd Michael Hanselmann
    @param _time_fn: Time function for unittests
88 7e8841bd Michael Hanselmann

89 7e8841bd Michael Hanselmann
    """
90 7e8841bd Michael Hanselmann
    object.__init__(self)
91 7e8841bd Michael Hanselmann
92 7e8841bd Michael Hanselmann
    if timeout is not None and timeout < 0.0:
93 7e8841bd Michael Hanselmann
      raise ValueError("Timeout must not be negative")
94 7e8841bd Michael Hanselmann
95 7e8841bd Michael Hanselmann
    self._timeout = timeout
96 7e8841bd Michael Hanselmann
    self._allow_negative = allow_negative
97 7e8841bd Michael Hanselmann
    self._time_fn = _time_fn
98 7e8841bd Michael Hanselmann
99 7e8841bd Michael Hanselmann
    self._start_time = None
100 7e8841bd Michael Hanselmann
101 7e8841bd Michael Hanselmann
  def Remaining(self):
102 7e8841bd Michael Hanselmann
    """Returns the remaining timeout.
103 7e8841bd Michael Hanselmann

104 7e8841bd Michael Hanselmann
    """
105 7e8841bd Michael Hanselmann
    if self._timeout is None:
106 7e8841bd Michael Hanselmann
      return None
107 7e8841bd Michael Hanselmann
108 7e8841bd Michael Hanselmann
    # Get start time on first calculation
109 7e8841bd Michael Hanselmann
    if self._start_time is None:
110 7e8841bd Michael Hanselmann
      self._start_time = self._time_fn()
111 7e8841bd Michael Hanselmann
112 7e8841bd Michael Hanselmann
    # Calculate remaining time
113 7e8841bd Michael Hanselmann
    remaining_timeout = self._start_time + self._timeout - self._time_fn()
114 7e8841bd Michael Hanselmann
115 7e8841bd Michael Hanselmann
    if not self._allow_negative:
116 7e8841bd Michael Hanselmann
      # Ensure timeout is always >= 0
117 7e8841bd Michael Hanselmann
      return max(0.0, remaining_timeout)
118 7e8841bd Michael Hanselmann
119 7e8841bd Michael Hanselmann
    return remaining_timeout
120 7e8841bd Michael Hanselmann
121 7e8841bd Michael Hanselmann
122 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
123 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
124 d76167a5 Michael Hanselmann

125 d76167a5 Michael Hanselmann
  """
126 d76167a5 Michael Hanselmann
  __slots__ = [
127 d76167a5 Michael Hanselmann
    "_fd",
128 d76167a5 Michael Hanselmann
    "_poller",
129 d76167a5 Michael Hanselmann
    ]
130 d76167a5 Michael Hanselmann
131 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
132 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
133 d76167a5 Michael Hanselmann

134 d76167a5 Michael Hanselmann
    @type poller: select.poll
135 d76167a5 Michael Hanselmann
    @param poller: Poller object
136 d76167a5 Michael Hanselmann
    @type fd: int
137 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
138 d76167a5 Michael Hanselmann

139 d76167a5 Michael Hanselmann
    """
140 d76167a5 Michael Hanselmann
    object.__init__(self)
141 d76167a5 Michael Hanselmann
    self._poller = poller
142 d76167a5 Michael Hanselmann
    self._fd = fd
143 d76167a5 Michael Hanselmann
144 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
145 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
146 d76167a5 Michael Hanselmann

147 d76167a5 Michael Hanselmann
    @type timeout: float or None
148 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
149 d76167a5 Michael Hanselmann

150 d76167a5 Michael Hanselmann
    """
151 f4e673fb Michael Hanselmann
    running_timeout = RunningTimeout(timeout, True)
152 f4e673fb Michael Hanselmann
153 f4e673fb Michael Hanselmann
    while True:
154 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
155 f4e673fb Michael Hanselmann
156 b44b0141 Michael Hanselmann
      if remaining_time is not None:
157 b44b0141 Michael Hanselmann
        if remaining_time < 0.0:
158 b44b0141 Michael Hanselmann
          break
159 d76167a5 Michael Hanselmann
160 413b7472 Michael Hanselmann
        # Our calculation uses seconds, poll() wants milliseconds
161 b44b0141 Michael Hanselmann
        remaining_time *= 1000
162 d76167a5 Michael Hanselmann
163 d76167a5 Michael Hanselmann
      try:
164 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
165 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
166 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
167 d76167a5 Michael Hanselmann
          raise
168 d76167a5 Michael Hanselmann
        result = None
169 d76167a5 Michael Hanselmann
170 d76167a5 Michael Hanselmann
      # Check whether we were notified
171 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
172 d76167a5 Michael Hanselmann
        break
173 d76167a5 Michael Hanselmann
174 d76167a5 Michael Hanselmann
175 2419060d Guido Trotter
class _BaseCondition(object):
176 2419060d Guido Trotter
  """Base class containing common code for conditions.
177 2419060d Guido Trotter

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

180 2419060d Guido Trotter
  """
181 2419060d Guido Trotter
  __slots__ = [
182 2419060d Guido Trotter
    "_lock",
183 2419060d Guido Trotter
    "acquire",
184 2419060d Guido Trotter
    "release",
185 7f890059 Guido Trotter
    "_is_owned",
186 7f890059 Guido Trotter
    "_acquire_restore",
187 7f890059 Guido Trotter
    "_release_save",
188 2419060d Guido Trotter
    ]
189 2419060d Guido Trotter
190 2419060d Guido Trotter
  def __init__(self, lock):
191 2419060d Guido Trotter
    """Constructor for _BaseCondition.
192 2419060d Guido Trotter

193 69b99987 Michael Hanselmann
    @type lock: threading.Lock
194 2419060d Guido Trotter
    @param lock: condition base lock
195 2419060d Guido Trotter

196 2419060d Guido Trotter
    """
197 2419060d Guido Trotter
    object.__init__(self)
198 2419060d Guido Trotter
199 7f890059 Guido Trotter
    try:
200 7f890059 Guido Trotter
      self._release_save = lock._release_save
201 7f890059 Guido Trotter
    except AttributeError:
202 7f890059 Guido Trotter
      self._release_save = self._base_release_save
203 7f890059 Guido Trotter
    try:
204 7f890059 Guido Trotter
      self._acquire_restore = lock._acquire_restore
205 7f890059 Guido Trotter
    except AttributeError:
206 7f890059 Guido Trotter
      self._acquire_restore = self._base_acquire_restore
207 7f890059 Guido Trotter
    try:
208 7f890059 Guido Trotter
      self._is_owned = lock._is_owned
209 7f890059 Guido Trotter
    except AttributeError:
210 7f890059 Guido Trotter
      self._is_owned = self._base_is_owned
211 2419060d Guido Trotter
212 2419060d Guido Trotter
    self._lock = lock
213 2419060d Guido Trotter
214 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
215 2419060d Guido Trotter
    self.acquire = lock.acquire
216 2419060d Guido Trotter
    self.release = lock.release
217 2419060d Guido Trotter
218 7f890059 Guido Trotter
  def _base_is_owned(self):
219 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
220 2419060d Guido Trotter

221 2419060d Guido Trotter
    """
222 2419060d Guido Trotter
    if self._lock.acquire(0):
223 2419060d Guido Trotter
      self._lock.release()
224 2419060d Guido Trotter
      return False
225 2419060d Guido Trotter
    return True
226 2419060d Guido Trotter
227 7f890059 Guido Trotter
  def _base_release_save(self):
228 7f890059 Guido Trotter
    self._lock.release()
229 7f890059 Guido Trotter
230 7f890059 Guido Trotter
  def _base_acquire_restore(self, _):
231 7f890059 Guido Trotter
    self._lock.acquire()
232 7f890059 Guido Trotter
233 2419060d Guido Trotter
  def _check_owned(self):
234 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
235 2419060d Guido Trotter

236 2419060d Guido Trotter
    """
237 2419060d Guido Trotter
    if not self._is_owned():
238 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
239 2419060d Guido Trotter
240 2419060d Guido Trotter
241 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
242 34cb5617 Guido Trotter
  """Condition which can only be notified once.
243 d76167a5 Michael Hanselmann

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

250 d76167a5 Michael Hanselmann
  """
251 34cb5617 Guido Trotter
252 154b9580 Balazs Lecz
  __slots__ = [
253 d76167a5 Michael Hanselmann
    "_poller",
254 d76167a5 Michael Hanselmann
    "_read_fd",
255 d76167a5 Michael Hanselmann
    "_write_fd",
256 d76167a5 Michael Hanselmann
    "_nwaiters",
257 34cb5617 Guido Trotter
    "_notified",
258 d76167a5 Michael Hanselmann
    ]
259 d76167a5 Michael Hanselmann
260 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
261 d76167a5 Michael Hanselmann
262 34cb5617 Guido Trotter
  def __init__(self, lock):
263 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
264 d76167a5 Michael Hanselmann

265 d76167a5 Michael Hanselmann
    """
266 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
267 d76167a5 Michael Hanselmann
    self._nwaiters = 0
268 34cb5617 Guido Trotter
    self._notified = False
269 34cb5617 Guido Trotter
    self._read_fd = None
270 34cb5617 Guido Trotter
    self._write_fd = None
271 34cb5617 Guido Trotter
    self._poller = None
272 d76167a5 Michael Hanselmann
273 34cb5617 Guido Trotter
  def _check_unnotified(self):
274 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
275 69b99987 Michael Hanselmann

276 69b99987 Michael Hanselmann
    """
277 34cb5617 Guido Trotter
    if self._notified:
278 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
279 d76167a5 Michael Hanselmann
280 34cb5617 Guido Trotter
  def _Cleanup(self):
281 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
282 d76167a5 Michael Hanselmann

283 d76167a5 Michael Hanselmann
    """
284 34cb5617 Guido Trotter
    if self._read_fd is not None:
285 34cb5617 Guido Trotter
      os.close(self._read_fd)
286 34cb5617 Guido Trotter
      self._read_fd = None
287 d76167a5 Michael Hanselmann
288 34cb5617 Guido Trotter
    if self._write_fd is not None:
289 34cb5617 Guido Trotter
      os.close(self._write_fd)
290 34cb5617 Guido Trotter
      self._write_fd = None
291 34cb5617 Guido Trotter
    self._poller = None
292 d76167a5 Michael Hanselmann
293 34cb5617 Guido Trotter
  def wait(self, timeout=None):
294 34cb5617 Guido Trotter
    """Wait for a notification.
295 d76167a5 Michael Hanselmann

296 34cb5617 Guido Trotter
    @type timeout: float or None
297 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
298 d76167a5 Michael Hanselmann

299 d76167a5 Michael Hanselmann
    """
300 34cb5617 Guido Trotter
    self._check_owned()
301 34cb5617 Guido Trotter
    self._check_unnotified()
302 d76167a5 Michael Hanselmann
303 34cb5617 Guido Trotter
    self._nwaiters += 1
304 34cb5617 Guido Trotter
    try:
305 34cb5617 Guido Trotter
      if self._poller is None:
306 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
307 34cb5617 Guido Trotter
        self._poller = select.poll()
308 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
309 d76167a5 Michael Hanselmann
310 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
311 7f890059 Guido Trotter
      state = self._release_save()
312 34cb5617 Guido Trotter
      try:
313 34cb5617 Guido Trotter
        # Wait for notification
314 34cb5617 Guido Trotter
        wait_fn(timeout)
315 34cb5617 Guido Trotter
      finally:
316 34cb5617 Guido Trotter
        # Re-acquire lock
317 7f890059 Guido Trotter
        self._acquire_restore(state)
318 34cb5617 Guido Trotter
    finally:
319 34cb5617 Guido Trotter
      self._nwaiters -= 1
320 34cb5617 Guido Trotter
      if self._nwaiters == 0:
321 34cb5617 Guido Trotter
        self._Cleanup()
322 d76167a5 Michael Hanselmann
323 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
324 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
325 d76167a5 Michael Hanselmann

326 d76167a5 Michael Hanselmann
    """
327 34cb5617 Guido Trotter
    self._check_owned()
328 34cb5617 Guido Trotter
    self._check_unnotified()
329 34cb5617 Guido Trotter
    self._notified = True
330 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
331 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
332 d76167a5 Michael Hanselmann
      self._write_fd = None
333 d76167a5 Michael Hanselmann
334 d76167a5 Michael Hanselmann
335 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
336 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
337 48dabc6a Michael Hanselmann

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

344 48dabc6a Michael Hanselmann
  """
345 154b9580 Balazs Lecz
  __slots__ = [
346 48dabc6a Michael Hanselmann
    "_nwaiters",
347 34cb5617 Guido Trotter
    "_single_condition",
348 48dabc6a Michael Hanselmann
    ]
349 48dabc6a Michael Hanselmann
350 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
351 48dabc6a Michael Hanselmann
352 48dabc6a Michael Hanselmann
  def __init__(self, lock):
353 48dabc6a Michael Hanselmann
    """Initializes this class.
354 48dabc6a Michael Hanselmann

355 48dabc6a Michael Hanselmann
    """
356 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
357 48dabc6a Michael Hanselmann
    self._nwaiters = 0
358 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
359 48dabc6a Michael Hanselmann
360 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
361 48dabc6a Michael Hanselmann
    """Wait for a notification.
362 48dabc6a Michael Hanselmann

363 48dabc6a Michael Hanselmann
    @type timeout: float or None
364 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
365 48dabc6a Michael Hanselmann

366 48dabc6a Michael Hanselmann
    """
367 48dabc6a Michael Hanselmann
    self._check_owned()
368 48dabc6a Michael Hanselmann
369 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
370 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
371 34cb5617 Guido Trotter
    my_condition = self._single_condition
372 48dabc6a Michael Hanselmann
373 48dabc6a Michael Hanselmann
    assert self._nwaiters >= 0
374 48dabc6a Michael Hanselmann
    self._nwaiters += 1
375 48dabc6a Michael Hanselmann
    try:
376 34cb5617 Guido Trotter
      my_condition.wait(timeout)
377 48dabc6a Michael Hanselmann
    finally:
378 48dabc6a Michael Hanselmann
      assert self._nwaiters > 0
379 48dabc6a Michael Hanselmann
      self._nwaiters -= 1
380 48dabc6a Michael Hanselmann
381 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
382 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
383 48dabc6a Michael Hanselmann

384 48dabc6a Michael Hanselmann
    """
385 48dabc6a Michael Hanselmann
    self._check_owned()
386 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
387 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
388 48dabc6a Michael Hanselmann
389 48dabc6a Michael Hanselmann
  def has_waiting(self):
390 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
391 48dabc6a Michael Hanselmann

392 48dabc6a Michael Hanselmann
    """
393 48dabc6a Michael Hanselmann
    self._check_owned()
394 48dabc6a Michael Hanselmann
395 48dabc6a Michael Hanselmann
    return bool(self._nwaiters)
396 48dabc6a Michael Hanselmann
397 48dabc6a Michael Hanselmann
398 84e344d4 Michael Hanselmann
class SharedLock(object):
399 162c1c1f Guido Trotter
  """Implements a shared lock.
400 162c1c1f Guido Trotter

401 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
402 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
403 162c1c1f Guido Trotter
  can call acquire_exclusive().
404 162c1c1f Guido Trotter

405 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
406 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
407 162c1c1f Guido Trotter
  eventually do so.
408 162c1c1f Guido Trotter

409 7f93570a Iustin Pop
  @type name: string
410 7f93570a Iustin Pop
  @ivar name: the name of the lock
411 7f93570a Iustin Pop

412 162c1c1f Guido Trotter
  """
413 84e344d4 Michael Hanselmann
  __slots__ = [
414 19b9ba9a Michael Hanselmann
    "__weakref__",
415 84e344d4 Michael Hanselmann
    "__active_shr_c",
416 84e344d4 Michael Hanselmann
    "__inactive_shr_c",
417 84e344d4 Michael Hanselmann
    "__deleted",
418 84e344d4 Michael Hanselmann
    "__exc",
419 84e344d4 Michael Hanselmann
    "__lock",
420 84e344d4 Michael Hanselmann
    "__pending",
421 84e344d4 Michael Hanselmann
    "__shr",
422 7f93570a Iustin Pop
    "name",
423 84e344d4 Michael Hanselmann
    ]
424 84e344d4 Michael Hanselmann
425 34cb5617 Guido Trotter
  __condition_class = PipeCondition
426 84e344d4 Michael Hanselmann
427 19b9ba9a Michael Hanselmann
  def __init__(self, name, monitor=None):
428 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
429 84e344d4 Michael Hanselmann

430 7f93570a Iustin Pop
    @param name: the name of the lock
431 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
432 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register
433 7f93570a Iustin Pop

434 84e344d4 Michael Hanselmann
    """
435 84e344d4 Michael Hanselmann
    object.__init__(self)
436 84e344d4 Michael Hanselmann
437 7f93570a Iustin Pop
    self.name = name
438 7f93570a Iustin Pop
439 84e344d4 Michael Hanselmann
    # Internal lock
440 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
441 162c1c1f Guido Trotter
442 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
443 84e344d4 Michael Hanselmann
    self.__pending = []
444 84e344d4 Michael Hanselmann
445 84e344d4 Michael Hanselmann
    # Active and inactive conditions for shared locks
446 84e344d4 Michael Hanselmann
    self.__active_shr_c = self.__condition_class(self.__lock)
447 84e344d4 Michael Hanselmann
    self.__inactive_shr_c = self.__condition_class(self.__lock)
448 84e344d4 Michael Hanselmann
449 84e344d4 Michael Hanselmann
    # Current lock holders
450 162c1c1f Guido Trotter
    self.__shr = set()
451 162c1c1f Guido Trotter
    self.__exc = None
452 162c1c1f Guido Trotter
453 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
454 a95fd5d7 Guido Trotter
    self.__deleted = False
455 a95fd5d7 Guido Trotter
456 19b9ba9a Michael Hanselmann
    # Register with lock monitor
457 19b9ba9a Michael Hanselmann
    if monitor:
458 19b9ba9a Michael Hanselmann
      monitor.RegisterLock(self)
459 19b9ba9a Michael Hanselmann
460 19b9ba9a Michael Hanselmann
  def GetInfo(self, fields):
461 19b9ba9a Michael Hanselmann
    """Retrieves information for querying locks.
462 19b9ba9a Michael Hanselmann

463 19b9ba9a Michael Hanselmann
    @type fields: list of strings
464 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
465 19b9ba9a Michael Hanselmann

466 19b9ba9a Michael Hanselmann
    """
467 19b9ba9a Michael Hanselmann
    self.__lock.acquire()
468 19b9ba9a Michael Hanselmann
    try:
469 19b9ba9a Michael Hanselmann
      info = []
470 19b9ba9a Michael Hanselmann
471 19b9ba9a Michael Hanselmann
      # Note: to avoid unintentional race conditions, no references to
472 19b9ba9a Michael Hanselmann
      # modifiable objects should be returned unless they were created in this
473 19b9ba9a Michael Hanselmann
      # function.
474 19b9ba9a Michael Hanselmann
      for fname in fields:
475 19b9ba9a Michael Hanselmann
        if fname == "name":
476 19b9ba9a Michael Hanselmann
          info.append(self.name)
477 19b9ba9a Michael Hanselmann
        elif fname == "mode":
478 19b9ba9a Michael Hanselmann
          if self.__deleted:
479 19b9ba9a Michael Hanselmann
            info.append("deleted")
480 19b9ba9a Michael Hanselmann
            assert not (self.__exc or self.__shr)
481 19b9ba9a Michael Hanselmann
          elif self.__exc:
482 19b9ba9a Michael Hanselmann
            info.append("exclusive")
483 19b9ba9a Michael Hanselmann
          elif self.__shr:
484 19b9ba9a Michael Hanselmann
            info.append("shared")
485 19b9ba9a Michael Hanselmann
          else:
486 19b9ba9a Michael Hanselmann
            info.append(None)
487 19b9ba9a Michael Hanselmann
        elif fname == "owner":
488 19b9ba9a Michael Hanselmann
          if self.__exc:
489 19b9ba9a Michael Hanselmann
            owner = [self.__exc]
490 19b9ba9a Michael Hanselmann
          else:
491 19b9ba9a Michael Hanselmann
            owner = self.__shr
492 19b9ba9a Michael Hanselmann
493 19b9ba9a Michael Hanselmann
          if owner:
494 19b9ba9a Michael Hanselmann
            assert not self.__deleted
495 19b9ba9a Michael Hanselmann
            info.append([i.getName() for i in owner])
496 19b9ba9a Michael Hanselmann
          else:
497 19b9ba9a Michael Hanselmann
            info.append(None)
498 19b9ba9a Michael Hanselmann
        else:
499 19b9ba9a Michael Hanselmann
          raise errors.OpExecError("Invalid query field '%s'" % fname)
500 19b9ba9a Michael Hanselmann
501 19b9ba9a Michael Hanselmann
      return info
502 19b9ba9a Michael Hanselmann
    finally:
503 19b9ba9a Michael Hanselmann
      self.__lock.release()
504 19b9ba9a Michael Hanselmann
505 84e344d4 Michael Hanselmann
  def __check_deleted(self):
506 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
507 84e344d4 Michael Hanselmann

508 84e344d4 Michael Hanselmann
    """
509 84e344d4 Michael Hanselmann
    if self.__deleted:
510 7f93570a Iustin Pop
      raise errors.LockError("Deleted lock %s" % self.name)
511 84e344d4 Michael Hanselmann
512 162c1c1f Guido Trotter
  def __is_sharer(self):
513 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
514 84e344d4 Michael Hanselmann

515 84e344d4 Michael Hanselmann
    """
516 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
517 162c1c1f Guido Trotter
518 162c1c1f Guido Trotter
  def __is_exclusive(self):
519 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
520 84e344d4 Michael Hanselmann

521 84e344d4 Michael Hanselmann
    """
522 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
523 162c1c1f Guido Trotter
524 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
525 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
526 162c1c1f Guido Trotter

527 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
528 162c1c1f Guido Trotter
    the internal lock.
529 162c1c1f Guido Trotter

530 162c1c1f Guido Trotter
    """
531 162c1c1f Guido Trotter
    if shared < 0:
532 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
533 162c1c1f Guido Trotter
    elif shared:
534 162c1c1f Guido Trotter
      return self.__is_sharer()
535 162c1c1f Guido Trotter
    else:
536 162c1c1f Guido Trotter
      return self.__is_exclusive()
537 162c1c1f Guido Trotter
538 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
539 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
540 162c1c1f Guido Trotter

541 c41eea6e Iustin Pop
    @param shared:
542 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
543 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
544 c41eea6e Iustin Pop
        - > 0: check for shared ownership
545 162c1c1f Guido Trotter

546 162c1c1f Guido Trotter
    """
547 162c1c1f Guido Trotter
    self.__lock.acquire()
548 162c1c1f Guido Trotter
    try:
549 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
550 162c1c1f Guido Trotter
    finally:
551 162c1c1f Guido Trotter
      self.__lock.release()
552 162c1c1f Guido Trotter
553 84e344d4 Michael Hanselmann
  def _count_pending(self):
554 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
555 a95fd5d7 Guido Trotter

556 84e344d4 Michael Hanselmann
    @rtype: int
557 a95fd5d7 Guido Trotter

558 a95fd5d7 Guido Trotter
    """
559 84e344d4 Michael Hanselmann
    self.__lock.acquire()
560 84e344d4 Michael Hanselmann
    try:
561 84e344d4 Michael Hanselmann
      return len(self.__pending)
562 84e344d4 Michael Hanselmann
    finally:
563 84e344d4 Michael Hanselmann
      self.__lock.release()
564 a95fd5d7 Guido Trotter
565 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
566 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
567 84e344d4 Michael Hanselmann

568 84e344d4 Michael Hanselmann
    """
569 84e344d4 Michael Hanselmann
    if shared:
570 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
571 84e344d4 Michael Hanselmann
    else:
572 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
573 a95fd5d7 Guido Trotter
574 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
575 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
576 a95fd5d7 Guido Trotter

577 a95fd5d7 Guido Trotter
    """
578 84e344d4 Michael Hanselmann
    if shared:
579 84e344d4 Michael Hanselmann
      return self.__exc is None
580 84e344d4 Michael Hanselmann
    else:
581 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
582 a95fd5d7 Guido Trotter
583 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
584 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
585 a95fd5d7 Guido Trotter

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

588 84e344d4 Michael Hanselmann
    """
589 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
590 4d686df8 Guido Trotter
591 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
592 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
593 9216a9f7 Michael Hanselmann

594 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
595 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
596 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
597 9216a9f7 Michael Hanselmann

598 9216a9f7 Michael Hanselmann
    """
599 84e344d4 Michael Hanselmann
    self.__check_deleted()
600 9216a9f7 Michael Hanselmann
601 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
602 7f93570a Iustin Pop
    assert not self.__is_owned(), ("double acquire() on a non-recursive lock"
603 7f93570a Iustin Pop
                                   " %s" % self.name)
604 84e344d4 Michael Hanselmann
605 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
606 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
607 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
608 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
609 84e344d4 Michael Hanselmann
      return True
610 9216a9f7 Michael Hanselmann
611 84e344d4 Michael Hanselmann
    if shared:
612 84e344d4 Michael Hanselmann
      wait_condition = self.__active_shr_c
613 9216a9f7 Michael Hanselmann
614 84e344d4 Michael Hanselmann
      # Check if we're not yet in the queue
615 84e344d4 Michael Hanselmann
      if wait_condition not in self.__pending:
616 84e344d4 Michael Hanselmann
        self.__pending.append(wait_condition)
617 84e344d4 Michael Hanselmann
    else:
618 84e344d4 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock)
619 84e344d4 Michael Hanselmann
      # Always add to queue
620 84e344d4 Michael Hanselmann
      self.__pending.append(wait_condition)
621 84e344d4 Michael Hanselmann
622 84e344d4 Michael Hanselmann
    try:
623 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
624 84e344d4 Michael Hanselmann
      # expires.
625 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
626 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
627 84e344d4 Michael Hanselmann
        # Wait for notification
628 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
629 84e344d4 Michael Hanselmann
        self.__check_deleted()
630 84e344d4 Michael Hanselmann
631 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
632 84e344d4 Michael Hanselmann
        # internally for that case.
633 84e344d4 Michael Hanselmann
        if timeout is not None:
634 84e344d4 Michael Hanselmann
          break
635 84e344d4 Michael Hanselmann
636 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
637 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
638 84e344d4 Michael Hanselmann
        return True
639 9216a9f7 Michael Hanselmann
    finally:
640 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
641 84e344d4 Michael Hanselmann
      if not wait_condition.has_waiting() and not self.__deleted:
642 84e344d4 Michael Hanselmann
        self.__pending.remove(wait_condition)
643 9216a9f7 Michael Hanselmann
644 84e344d4 Michael Hanselmann
    return False
645 9216a9f7 Michael Hanselmann
646 008b92fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, test_notify=None):
647 162c1c1f Guido Trotter
    """Acquire a shared lock.
648 162c1c1f Guido Trotter

649 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
650 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
651 c41eea6e Iustin Pop
        exclusive lock will be acquired
652 84e344d4 Michael Hanselmann
    @type timeout: float
653 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
654 008b92fa Michael Hanselmann
    @type test_notify: callable or None
655 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
656 162c1c1f Guido Trotter

657 162c1c1f Guido Trotter
    """
658 162c1c1f Guido Trotter
    self.__lock.acquire()
659 162c1c1f Guido Trotter
    try:
660 008b92fa Michael Hanselmann
      # We already got the lock, notify now
661 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
662 008b92fa Michael Hanselmann
        test_notify()
663 008b92fa Michael Hanselmann
664 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
665 162c1c1f Guido Trotter
    finally:
666 162c1c1f Guido Trotter
      self.__lock.release()
667 162c1c1f Guido Trotter
668 162c1c1f Guido Trotter
  def release(self):
669 162c1c1f Guido Trotter
    """Release a Shared Lock.
670 162c1c1f Guido Trotter

671 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
672 162c1c1f Guido Trotter
    before calling this function.
673 162c1c1f Guido Trotter

674 162c1c1f Guido Trotter
    """
675 162c1c1f Guido Trotter
    self.__lock.acquire()
676 162c1c1f Guido Trotter
    try:
677 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
678 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
679 84e344d4 Michael Hanselmann
680 162c1c1f Guido Trotter
      # Autodetect release type
681 162c1c1f Guido Trotter
      if self.__is_exclusive():
682 162c1c1f Guido Trotter
        self.__exc = None
683 84e344d4 Michael Hanselmann
      else:
684 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
685 162c1c1f Guido Trotter
686 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
687 84e344d4 Michael Hanselmann
      if self.__pending:
688 84e344d4 Michael Hanselmann
        first_condition = self.__pending[0]
689 84e344d4 Michael Hanselmann
        first_condition.notifyAll()
690 4d686df8 Guido Trotter
691 84e344d4 Michael Hanselmann
        if first_condition == self.__active_shr_c:
692 84e344d4 Michael Hanselmann
          self.__active_shr_c = self.__inactive_shr_c
693 84e344d4 Michael Hanselmann
          self.__inactive_shr_c = first_condition
694 162c1c1f Guido Trotter
695 162c1c1f Guido Trotter
    finally:
696 162c1c1f Guido Trotter
      self.__lock.release()
697 162c1c1f Guido Trotter
698 84e344d4 Michael Hanselmann
  def delete(self, timeout=None):
699 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
700 a95fd5d7 Guido Trotter

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

705 84e344d4 Michael Hanselmann
    @type timeout: float
706 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
707 a95fd5d7 Guido Trotter

708 a95fd5d7 Guido Trotter
    """
709 a95fd5d7 Guido Trotter
    self.__lock.acquire()
710 a95fd5d7 Guido Trotter
    try:
711 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
712 84e344d4 Michael Hanselmann
713 84e344d4 Michael Hanselmann
      self.__check_deleted()
714 a95fd5d7 Guido Trotter
715 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
716 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
717 a95fd5d7 Guido Trotter
718 84e344d4 Michael Hanselmann
      if not acquired:
719 a66bd91b Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout)
720 a66bd91b Michael Hanselmann
721 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
722 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
723 84e344d4 Michael Hanselmann
724 84e344d4 Michael Hanselmann
      if acquired:
725 84e344d4 Michael Hanselmann
        self.__deleted = True
726 84e344d4 Michael Hanselmann
        self.__exc = None
727 a95fd5d7 Guido Trotter
728 19b9ba9a Michael Hanselmann
        assert not (self.__exc or self.__shr), "Found owner during deletion"
729 19b9ba9a Michael Hanselmann
730 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
731 84e344d4 Michael Hanselmann
        while self.__pending:
732 84e344d4 Michael Hanselmann
          self.__pending.pop().notifyAll()
733 a95fd5d7 Guido Trotter
734 84e344d4 Michael Hanselmann
      return acquired
735 a95fd5d7 Guido Trotter
    finally:
736 a95fd5d7 Guido Trotter
      self.__lock.release()
737 a95fd5d7 Guido Trotter
738 1a4e32d0 Guido Trotter
  def _release_save(self):
739 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
740 1a4e32d0 Guido Trotter
    self.release()
741 1a4e32d0 Guido Trotter
    return shared
742 1a4e32d0 Guido Trotter
743 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
744 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
745 1a4e32d0 Guido Trotter
746 aaae9bc0 Guido Trotter
747 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
748 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
749 e310b019 Guido Trotter
ALL_SET = None
750 e310b019 Guido Trotter
751 e310b019 Guido Trotter
752 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
753 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
754 5aab242c Michael Hanselmann

755 5aab242c Michael Hanselmann
  """
756 5aab242c Michael Hanselmann
757 5aab242c Michael Hanselmann
758 aaae9bc0 Guido Trotter
class LockSet:
759 aaae9bc0 Guido Trotter
  """Implements a set of locks.
760 aaae9bc0 Guido Trotter

761 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
762 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
763 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
764 aaae9bc0 Guido Trotter
  preventing deadlock.
765 aaae9bc0 Guido Trotter

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

768 7f93570a Iustin Pop
  @type name: string
769 7f93570a Iustin Pop
  @ivar name: the name of the lockset
770 7f93570a Iustin Pop

771 aaae9bc0 Guido Trotter
  """
772 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
773 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
774 aaae9bc0 Guido Trotter

775 ec44d893 Guido Trotter
    @type members: list of strings
776 c41eea6e Iustin Pop
    @param members: initial members of the set
777 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
778 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
779 aaae9bc0 Guido Trotter

780 aaae9bc0 Guido Trotter
    """
781 7f93570a Iustin Pop
    assert members is not None, "members parameter is not a list"
782 7f93570a Iustin Pop
    self.name = name
783 7f93570a Iustin Pop
784 19b9ba9a Michael Hanselmann
    # Lock monitor
785 19b9ba9a Michael Hanselmann
    self.__monitor = monitor
786 19b9ba9a Michael Hanselmann
787 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
788 7f93570a Iustin Pop
    self.__lock = SharedLock(name)
789 aaae9bc0 Guido Trotter
790 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
791 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
792 aaae9bc0 Guido Trotter
    self.__lockdict = {}
793 aaae9bc0 Guido Trotter
794 7f93570a Iustin Pop
    for mname in members:
795 19b9ba9a Michael Hanselmann
      self.__lockdict[mname] = SharedLock(self._GetLockName(mname),
796 19b9ba9a Michael Hanselmann
                                          monitor=monitor)
797 aaae9bc0 Guido Trotter
798 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
799 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
800 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
801 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
802 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
803 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
804 aaae9bc0 Guido Trotter
    # will be trouble.
805 aaae9bc0 Guido Trotter
    self.__owners = {}
806 aaae9bc0 Guido Trotter
807 4fb780d1 Michael Hanselmann
  def _GetLockName(self, mname):
808 4fb780d1 Michael Hanselmann
    """Returns the name for a member lock.
809 4fb780d1 Michael Hanselmann

810 4fb780d1 Michael Hanselmann
    """
811 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
812 4fb780d1 Michael Hanselmann
813 aaae9bc0 Guido Trotter
  def _is_owned(self):
814 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
815 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
816 aaae9bc0 Guido Trotter
817 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
818 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
819 b2dabfd6 Guido Trotter
    if name is None:
820 b2dabfd6 Guido Trotter
      if not self._is_owned():
821 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
822 aaae9bc0 Guido Trotter
    else:
823 b2dabfd6 Guido Trotter
      if self._is_owned():
824 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
825 b2dabfd6 Guido Trotter
      else:
826 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
827 b2dabfd6 Guido Trotter
828 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
829 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
830 aaae9bc0 Guido Trotter
831 e4335b5b Michael Hanselmann
    assert not (name is None and self.__lock._is_owned()), \
832 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
833 e4335b5b Michael Hanselmann
834 b2dabfd6 Guido Trotter
    if name is not None:
835 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
836 b2dabfd6 Guido Trotter
837 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
838 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
839 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
840 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
841 aaae9bc0 Guido Trotter
842 aaae9bc0 Guido Trotter
  def _list_owned(self):
843 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
844 aaae9bc0 Guido Trotter
    if self._is_owned():
845 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
846 aaae9bc0 Guido Trotter
    else:
847 aaae9bc0 Guido Trotter
      return set()
848 aaae9bc0 Guido Trotter
849 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
850 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
851 5aab242c Michael Hanselmann
    for lname in self._list_owned():
852 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
853 56452af7 Michael Hanselmann
      if lock._is_owned():
854 56452af7 Michael Hanselmann
        lock.release()
855 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
856 5aab242c Michael Hanselmann
857 aaae9bc0 Guido Trotter
  def __names(self):
858 aaae9bc0 Guido Trotter
    """Return the current set of names.
859 aaae9bc0 Guido Trotter

860 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
861 aaae9bc0 Guido Trotter
    result after releasing the lock.
862 aaae9bc0 Guido Trotter

863 aaae9bc0 Guido Trotter
    """
864 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
865 aaae9bc0 Guido Trotter
866 aaae9bc0 Guido Trotter
  def _names(self):
867 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
868 aaae9bc0 Guido Trotter

869 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
870 cdb08f44 Michael Hanselmann

871 aaae9bc0 Guido Trotter
    """
872 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
873 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
874 d4803c24 Guido Trotter
    release_lock = False
875 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
876 d4803c24 Guido Trotter
      release_lock = True
877 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
878 aaae9bc0 Guido Trotter
    try:
879 aaae9bc0 Guido Trotter
      result = self.__names()
880 aaae9bc0 Guido Trotter
    finally:
881 d4803c24 Guido Trotter
      if release_lock:
882 d4803c24 Guido Trotter
        self.__lock.release()
883 0cf257c5 Guido Trotter
    return set(result)
884 aaae9bc0 Guido Trotter
885 5aab242c Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, test_notify=None):
886 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
887 aaae9bc0 Guido Trotter

888 ec44d893 Guido Trotter
    @type names: list of strings (or string)
889 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
890 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
891 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
892 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
893 c41eea6e Iustin Pop
        exclusive lock will be acquired
894 5aab242c Michael Hanselmann
    @type timeout: float or None
895 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
896 5aab242c Michael Hanselmann
    @type test_notify: callable or None
897 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
898 aaae9bc0 Guido Trotter

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

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

905 aaae9bc0 Guido Trotter
    """
906 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
907 aaae9bc0 Guido Trotter
908 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
909 7f93570a Iustin Pop
    assert not self._is_owned(), ("Cannot acquire locks in the same set twice"
910 7f93570a Iustin Pop
                                  " (lockset %s)" % self.name)
911 aaae9bc0 Guido Trotter
912 5aab242c Michael Hanselmann
    # We need to keep track of how long we spent waiting for a lock. The
913 5aab242c Michael Hanselmann
    # timeout passed to this function is over all lock acquires.
914 7e8841bd Michael Hanselmann
    running_timeout = RunningTimeout(timeout, False)
915 5aab242c Michael Hanselmann
916 806e20fd Guido Trotter
    try:
917 76e2f08a Michael Hanselmann
      if names is not None:
918 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
919 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
920 5aab242c Michael Hanselmann
          names = [names]
921 5aab242c Michael Hanselmann
922 76e2f08a Michael Hanselmann
        return self.__acquire_inner(names, False, shared,
923 7e8841bd Michael Hanselmann
                                    running_timeout.Remaining, test_notify)
924 76e2f08a Michael Hanselmann
925 76e2f08a Michael Hanselmann
      else:
926 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
927 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
928 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
929 76e2f08a Michael Hanselmann
        #
930 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
931 76e2f08a Michael Hanselmann
        # everybody else can use the instances at the same time. If are
932 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
933 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
934 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
935 76e2f08a Michael Hanselmann
        if not self.__lock.acquire(shared=shared,
936 7e8841bd Michael Hanselmann
                                   timeout=running_timeout.Remaining()):
937 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
938 76e2f08a Michael Hanselmann
        try:
939 76e2f08a Michael Hanselmann
          # note we own the set-lock
940 76e2f08a Michael Hanselmann
          self._add_owned()
941 76e2f08a Michael Hanselmann
942 76e2f08a Michael Hanselmann
          return self.__acquire_inner(self.__names(), True, shared,
943 7e8841bd Michael Hanselmann
                                      running_timeout.Remaining, test_notify)
944 76e2f08a Michael Hanselmann
        except:
945 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
946 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
947 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
948 5aab242c Michael Hanselmann
          self.__lock.release()
949 76e2f08a Michael Hanselmann
          self._del_owned()
950 76e2f08a Michael Hanselmann
          raise
951 5aab242c Michael Hanselmann
952 5aab242c Michael Hanselmann
    except _AcquireTimeout:
953 5aab242c Michael Hanselmann
      return None
954 aaae9bc0 Guido Trotter
955 76e2f08a Michael Hanselmann
  def __acquire_inner(self, names, want_all, shared, timeout_fn, test_notify):
956 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
957 7e8841bd Michael Hanselmann

958 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
959 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
960 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
961 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
962 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
963 76e2f08a Michael Hanselmann

964 76e2f08a Michael Hanselmann
    """
965 76e2f08a Michael Hanselmann
    acquire_list = []
966 76e2f08a Michael Hanselmann
967 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
968 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
969 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
970 71e1863e Michael Hanselmann
    # deadlocks.
971 71e1863e Michael Hanselmann
    for lname in sorted(utils.UniqueSequence(names)):
972 76e2f08a Michael Hanselmann
      try:
973 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
974 76e2f08a Michael Hanselmann
      except KeyError:
975 76e2f08a Michael Hanselmann
        if want_all:
976 76e2f08a Michael Hanselmann
          # We are acquiring all the set, it doesn't matter if this particular
977 76e2f08a Michael Hanselmann
          # element is not there anymore.
978 76e2f08a Michael Hanselmann
          continue
979 76e2f08a Michael Hanselmann
980 7f93570a Iustin Pop
        raise errors.LockError("Non-existing lock %s in set %s" %
981 7f93570a Iustin Pop
                               (lname, self.name))
982 76e2f08a Michael Hanselmann
983 9b154270 Michael Hanselmann
      acquire_list.append((lname, lock))
984 9b154270 Michael Hanselmann
985 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
986 76e2f08a Michael Hanselmann
    acquired = set()
987 76e2f08a Michael Hanselmann
988 76e2f08a Michael Hanselmann
    try:
989 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
990 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
991 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
992 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
993 76e2f08a Michael Hanselmann
      # lock gets deleted.
994 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
995 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
996 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
997 76e2f08a Michael Hanselmann
        else:
998 76e2f08a Michael Hanselmann
          test_notify_fn = None
999 76e2f08a Michael Hanselmann
1000 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
1001 76e2f08a Michael Hanselmann
1002 76e2f08a Michael Hanselmann
        try:
1003 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
1004 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
1005 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
1006 76e2f08a Michael Hanselmann
        except errors.LockError:
1007 76e2f08a Michael Hanselmann
          if want_all:
1008 76e2f08a Michael Hanselmann
            # We are acquiring all the set, it doesn't matter if this
1009 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
1010 76e2f08a Michael Hanselmann
            continue
1011 76e2f08a Michael Hanselmann
1012 7f93570a Iustin Pop
          raise errors.LockError("Non-existing lock %s in set %s" %
1013 7f93570a Iustin Pop
                                 (lname, self.name))
1014 76e2f08a Michael Hanselmann
1015 76e2f08a Michael Hanselmann
        if not acq_success:
1016 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
1017 76e2f08a Michael Hanselmann
          if timeout is None:
1018 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
1019 76e2f08a Michael Hanselmann
            # blocking.
1020 7f93570a Iustin Pop
            raise errors.LockError("Failed to get lock %s (set %s)" %
1021 7f93570a Iustin Pop
                                   (lname, self.name))
1022 76e2f08a Michael Hanselmann
1023 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1024 76e2f08a Michael Hanselmann
1025 76e2f08a Michael Hanselmann
        try:
1026 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
1027 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
1028 76e2f08a Michael Hanselmann
          acquired.add(lname)
1029 76e2f08a Michael Hanselmann
1030 76e2f08a Michael Hanselmann
        except:
1031 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1032 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1033 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
1034 76e2f08a Michael Hanselmann
          if lock._is_owned():
1035 76e2f08a Michael Hanselmann
            lock.release()
1036 76e2f08a Michael Hanselmann
          raise
1037 76e2f08a Michael Hanselmann
1038 76e2f08a Michael Hanselmann
    except:
1039 76e2f08a Michael Hanselmann
      # Release all owned locks
1040 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
1041 76e2f08a Michael Hanselmann
      raise
1042 76e2f08a Michael Hanselmann
1043 0cc00929 Guido Trotter
    return acquired
1044 aaae9bc0 Guido Trotter
1045 aaae9bc0 Guido Trotter
  def release(self, names=None):
1046 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
1047 aaae9bc0 Guido Trotter

1048 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1049 aaae9bc0 Guido Trotter
    before releasing them.
1050 aaae9bc0 Guido Trotter

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

1055 aaae9bc0 Guido Trotter
    """
1056 7f93570a Iustin Pop
    assert self._is_owned(), ("release() on lock set %s while not owner" %
1057 7f93570a Iustin Pop
                              self.name)
1058 aaae9bc0 Guido Trotter
1059 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1060 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1061 aaae9bc0 Guido Trotter
      names = [names]
1062 aaae9bc0 Guido Trotter
1063 aaae9bc0 Guido Trotter
    if names is None:
1064 aaae9bc0 Guido Trotter
      names = self._list_owned()
1065 aaae9bc0 Guido Trotter
    else:
1066 aaae9bc0 Guido Trotter
      names = set(names)
1067 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
1068 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1069 7f93570a Iustin Pop
               (names.difference(self._list_owned()), self.name))
1070 aaae9bc0 Guido Trotter
1071 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1072 3b7ed473 Guido Trotter
    # After this 'add' can work again
1073 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
1074 3b7ed473 Guido Trotter
      self.__lock.release()
1075 b2dabfd6 Guido Trotter
      self._del_owned()
1076 3b7ed473 Guido Trotter
1077 aaae9bc0 Guido Trotter
    for lockname in names:
1078 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1079 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1080 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1081 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1082 aaae9bc0 Guido Trotter
1083 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1084 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1085 aaae9bc0 Guido Trotter

1086 ec44d893 Guido Trotter
    @type names: list of strings
1087 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1088 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1089 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1090 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1091 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1092 aaae9bc0 Guido Trotter

1093 aaae9bc0 Guido Trotter
    """
1094 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1095 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
1096 7f93570a Iustin Pop
      ("Cannot add locks if the set %s is only partially owned, or shared" %
1097 7f93570a Iustin Pop
       self.name)
1098 3b7ed473 Guido Trotter
1099 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1100 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1101 aaae9bc0 Guido Trotter
      names = [names]
1102 aaae9bc0 Guido Trotter
1103 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1104 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1105 3b7ed473 Guido Trotter
    release_lock = False
1106 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
1107 3b7ed473 Guido Trotter
      release_lock = True
1108 3b7ed473 Guido Trotter
      self.__lock.acquire()
1109 3b7ed473 Guido Trotter
1110 aaae9bc0 Guido Trotter
    try:
1111 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1112 aaae9bc0 Guido Trotter
      if invalid_names:
1113 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1114 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1115 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1116 7f93570a Iustin Pop
        raise errors.LockError("duplicate add(%s) on lockset %s" %
1117 7f93570a Iustin Pop
                               (invalid_names, self.name))
1118 aaae9bc0 Guido Trotter
1119 aaae9bc0 Guido Trotter
      for lockname in names:
1120 19b9ba9a Michael Hanselmann
        lock = SharedLock(self._GetLockName(lockname), monitor=self.__monitor)
1121 aaae9bc0 Guido Trotter
1122 aaae9bc0 Guido Trotter
        if acquired:
1123 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1124 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1125 aaae9bc0 Guido Trotter
          try:
1126 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1127 aaae9bc0 Guido Trotter
          except:
1128 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1129 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1130 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1131 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1132 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1133 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1134 aaae9bc0 Guido Trotter
            lock.release()
1135 aaae9bc0 Guido Trotter
            raise
1136 aaae9bc0 Guido Trotter
1137 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1138 aaae9bc0 Guido Trotter
1139 aaae9bc0 Guido Trotter
    finally:
1140 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1141 3b7ed473 Guido Trotter
      if release_lock:
1142 3b7ed473 Guido Trotter
        self.__lock.release()
1143 aaae9bc0 Guido Trotter
1144 aaae9bc0 Guido Trotter
    return True
1145 aaae9bc0 Guido Trotter
1146 5e0a6daf Michael Hanselmann
  def remove(self, names):
1147 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1148 aaae9bc0 Guido Trotter

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

1152 ec44d893 Guido Trotter
    @type names: list of strings
1153 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1154 aaae9bc0 Guido Trotter

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

1159 aaae9bc0 Guido Trotter
    """
1160 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1161 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1162 aaae9bc0 Guido Trotter
      names = [names]
1163 aaae9bc0 Guido Trotter
1164 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1165 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1166 aaae9bc0 Guido Trotter
    # by the lock itself.
1167 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
1168 7f93570a Iustin Pop
      "remove() on acquired lockset %s while not owning all elements" %
1169 7f93570a Iustin Pop
      self.name)
1170 aaae9bc0 Guido Trotter
1171 3f404fc5 Guido Trotter
    removed = []
1172 aaae9bc0 Guido Trotter
1173 aaae9bc0 Guido Trotter
    for lname in names:
1174 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1175 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1176 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1177 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1178 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1179 aaae9bc0 Guido Trotter
      try:
1180 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1181 3f404fc5 Guido Trotter
        removed.append(lname)
1182 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1183 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1184 7f93570a Iustin Pop
        assert not self._is_owned(), ("remove failed while holding lockset %s"
1185 7f93570a Iustin Pop
                                      % self.name)
1186 aaae9bc0 Guido Trotter
      else:
1187 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1188 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1189 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1190 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1191 aaae9bc0 Guido Trotter
        #
1192 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1193 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1194 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1195 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1196 aaae9bc0 Guido Trotter
        if self._is_owned():
1197 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1198 aaae9bc0 Guido Trotter
1199 3f404fc5 Guido Trotter
    return removed
1200 aaae9bc0 Guido Trotter
1201 7ee7c0c7 Guido Trotter
1202 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1203 7ee7c0c7 Guido Trotter
# Current rules are:
1204 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1205 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1206 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1207 7ee7c0c7 Guido Trotter
#   avoided.
1208 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1209 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1210 7ee7c0c7 Guido Trotter
#   the same time.
1211 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1212 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1213 04e1bfaf Guido Trotter
LEVEL_NODE = 2
1214 7ee7c0c7 Guido Trotter
1215 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1216 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1217 04e1bfaf Guido Trotter
          LEVEL_NODE]
1218 7ee7c0c7 Guido Trotter
1219 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1220 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
1221 7ee7c0c7 Guido Trotter
1222 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1223 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1224 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1225 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1226 ea205dbc Michael Hanselmann
  }
1227 ea205dbc Michael Hanselmann
1228 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1229 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1230 7ee7c0c7 Guido Trotter
1231 7ee7c0c7 Guido Trotter
1232 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1233 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1234 7ee7c0c7 Guido Trotter

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

1240 7ee7c0c7 Guido Trotter
  """
1241 7ee7c0c7 Guido Trotter
  _instance = None
1242 7ee7c0c7 Guido Trotter
1243 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1244 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1245 7ee7c0c7 Guido Trotter

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

1249 c41eea6e Iustin Pop
    @param nodes: list of node names
1250 c41eea6e Iustin Pop
    @param instances: list of instance names
1251 7ee7c0c7 Guido Trotter

1252 7ee7c0c7 Guido Trotter
    """
1253 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1254 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1255 c41eea6e Iustin Pop
1256 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1257 7ee7c0c7 Guido Trotter
1258 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1259 19b9ba9a Michael Hanselmann
1260 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1261 7ee7c0c7 Guido Trotter
    # locking order.
1262 7ee7c0c7 Guido Trotter
    self.__keyring = {
1263 19b9ba9a Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "BGL", monitor=self._monitor),
1264 19b9ba9a Michael Hanselmann
      LEVEL_NODE: LockSet(nodes, "nodes", monitor=self._monitor),
1265 19b9ba9a Michael Hanselmann
      LEVEL_INSTANCE: LockSet(instances, "instances",
1266 19b9ba9a Michael Hanselmann
                              monitor=self._monitor),
1267 19b9ba9a Michael Hanselmann
      }
1268 19b9ba9a Michael Hanselmann
1269 19b9ba9a Michael Hanselmann
  def QueryLocks(self, fields, sync):
1270 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1271 19b9ba9a Michael Hanselmann

1272 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1273 19b9ba9a Michael Hanselmann

1274 19b9ba9a Michael Hanselmann
    """
1275 19b9ba9a Michael Hanselmann
    return self._monitor.QueryLocks(fields, sync)
1276 7ee7c0c7 Guido Trotter
1277 7ee7c0c7 Guido Trotter
  def _names(self, level):
1278 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1279 7ee7c0c7 Guido Trotter

1280 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1281 c41eea6e Iustin Pop

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

1284 7ee7c0c7 Guido Trotter
    """
1285 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1286 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1287 7ee7c0c7 Guido Trotter
1288 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1289 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1290 7ee7c0c7 Guido Trotter

1291 7ee7c0c7 Guido Trotter
    """
1292 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1293 7ee7c0c7 Guido Trotter
1294 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1295 d4f4b3e7 Guido Trotter
1296 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1297 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1298 7ee7c0c7 Guido Trotter

1299 7ee7c0c7 Guido Trotter
    """
1300 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1301 7ee7c0c7 Guido Trotter
1302 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1303 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1304 7ee7c0c7 Guido Trotter

1305 7ee7c0c7 Guido Trotter
    """
1306 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1307 7ee7c0c7 Guido Trotter
    # the test cases.
1308 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1309 7ee7c0c7 Guido Trotter
1310 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1311 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1312 7ee7c0c7 Guido Trotter

1313 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1314 7ee7c0c7 Guido Trotter

1315 7ee7c0c7 Guido Trotter
    """
1316 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1317 7ee7c0c7 Guido Trotter
1318 c70d2d9b Iustin Pop
  @staticmethod
1319 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1320 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1321 c41eea6e Iustin Pop

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

1325 7ee7c0c7 Guido Trotter
    """
1326 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1327 7ee7c0c7 Guido Trotter
1328 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1329 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1330 7ee7c0c7 Guido Trotter

1331 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1332 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1333 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1334 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1335 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1336 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1337 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1338 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1339 5e0a6daf Michael Hanselmann
    @type timeout: float
1340 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1341 7ee7c0c7 Guido Trotter

1342 7ee7c0c7 Guido Trotter
    """
1343 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1344 7ee7c0c7 Guido Trotter
1345 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1346 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1347 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1348 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1349 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1350 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1351 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1352 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1353 7ee7c0c7 Guido Trotter
1354 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1355 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1356 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1357 7ee7c0c7 Guido Trotter
1358 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1359 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1360 7ee7c0c7 Guido Trotter
1361 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1362 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1363 7ee7c0c7 Guido Trotter

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

1367 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1368 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1369 ec44d893 Guido Trotter
    @type names: list of strings, or None
1370 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1371 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1372 7ee7c0c7 Guido Trotter

1373 7ee7c0c7 Guido Trotter
    """
1374 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1375 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1376 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1377 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1378 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1379 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1380 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1381 7ee7c0c7 Guido Trotter
1382 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1383 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1384 7ee7c0c7 Guido Trotter
1385 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1386 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1387 7ee7c0c7 Guido Trotter

1388 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1389 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1390 ec44d893 Guido Trotter
    @type names: list of strings
1391 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1392 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1393 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1394 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1395 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1396 c41eea6e Iustin Pop

1397 7ee7c0c7 Guido Trotter
    """
1398 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1399 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1400 7ee7c0c7 Guido Trotter
           " operations")
1401 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1402 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1403 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1404 7ee7c0c7 Guido Trotter
1405 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1406 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1407 7ee7c0c7 Guido Trotter

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

1411 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1412 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1413 ec44d893 Guido Trotter
    @type names: list of strings
1414 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1415 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1416 7ee7c0c7 Guido Trotter

1417 7ee7c0c7 Guido Trotter
    """
1418 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1419 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1420 7ee7c0c7 Guido Trotter
           " operations")
1421 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1422 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1423 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1424 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1425 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1426 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1427 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1428 19b9ba9a Michael Hanselmann
1429 19b9ba9a Michael Hanselmann
1430 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1431 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1432 19b9ba9a Michael Hanselmann
1433 19b9ba9a Michael Hanselmann
  def __init__(self):
1434 19b9ba9a Michael Hanselmann
    """Initializes this class.
1435 19b9ba9a Michael Hanselmann

1436 19b9ba9a Michael Hanselmann
    """
1437 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1438 19b9ba9a Michael Hanselmann
1439 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1440 19b9ba9a Michael Hanselmann
    # references and deletion.
1441 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1442 19b9ba9a Michael Hanselmann
1443 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1444 19b9ba9a Michael Hanselmann
  def RegisterLock(self, lock):
1445 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1446 19b9ba9a Michael Hanselmann

1447 19b9ba9a Michael Hanselmann
    """
1448 19b9ba9a Michael Hanselmann
    logging.debug("Registering lock %s", lock.name)
1449 19b9ba9a Michael Hanselmann
    assert lock not in self._locks, "Duplicate lock registration"
1450 19b9ba9a Michael Hanselmann
    assert not compat.any(lock.name == i.name for i in self._locks.keys()), \
1451 19b9ba9a Michael Hanselmann
           "Found duplicate lock name"
1452 19b9ba9a Michael Hanselmann
    self._locks[lock] = None
1453 19b9ba9a Michael Hanselmann
1454 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1455 19b9ba9a Michael Hanselmann
  def _GetLockInfo(self, fields):
1456 19b9ba9a Michael Hanselmann
    """Get information from all locks while the monitor lock is held.
1457 19b9ba9a Michael Hanselmann

1458 19b9ba9a Michael Hanselmann
    """
1459 19b9ba9a Michael Hanselmann
    result = {}
1460 19b9ba9a Michael Hanselmann
1461 19b9ba9a Michael Hanselmann
    for lock in self._locks.keys():
1462 19b9ba9a Michael Hanselmann
      assert lock.name not in result, "Found duplicate lock name"
1463 19b9ba9a Michael Hanselmann
      result[lock.name] = lock.GetInfo(fields)
1464 19b9ba9a Michael Hanselmann
1465 19b9ba9a Michael Hanselmann
    return result
1466 19b9ba9a Michael Hanselmann
1467 19b9ba9a Michael Hanselmann
  def QueryLocks(self, fields, sync):
1468 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1469 19b9ba9a Michael Hanselmann

1470 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1471 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1472 19b9ba9a Michael Hanselmann
    @type sync: boolean
1473 19b9ba9a Michael Hanselmann
    @param sync: Whether to operate in synchronous mode
1474 19b9ba9a Michael Hanselmann

1475 19b9ba9a Michael Hanselmann
    """
1476 19b9ba9a Michael Hanselmann
    if sync:
1477 19b9ba9a Michael Hanselmann
      raise NotImplementedError("Synchronous queries are not implemented")
1478 19b9ba9a Michael Hanselmann
1479 19b9ba9a Michael Hanselmann
    # Get all data without sorting
1480 19b9ba9a Michael Hanselmann
    result = self._GetLockInfo(fields)
1481 19b9ba9a Michael Hanselmann
1482 19b9ba9a Michael Hanselmann
    # Sort by name
1483 19b9ba9a Michael Hanselmann
    return [result[name] for name in utils.NiceSort(result.keys())]