Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 5224330e

History | View | Annotate | Download (45.4 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 c31825f7 Michael Hanselmann
_EXCLUSIVE_TEXT = "exclusive"
42 c31825f7 Michael Hanselmann
_SHARED_TEXT = "shared"
43 c31825f7 Michael Hanselmann
44 c31825f7 Michael Hanselmann
45 dbb11e8b Guido Trotter
def ssynchronized(mylock, shared=0):
46 42a999d1 Guido Trotter
  """Shared Synchronization decorator.
47 42a999d1 Guido Trotter

48 42a999d1 Guido Trotter
  Calls the function holding the given lock, either in exclusive or shared
49 42a999d1 Guido Trotter
  mode. It requires the passed lock to be a SharedLock (or support its
50 42a999d1 Guido Trotter
  semantics).
51 42a999d1 Guido Trotter

52 dbb11e8b Guido Trotter
  @type mylock: lockable object or string
53 dbb11e8b Guido Trotter
  @param mylock: lock to acquire or class member name of the lock to acquire
54 dbb11e8b Guido Trotter

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

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

87 7e8841bd Michael Hanselmann
    @type timeout: float
88 7e8841bd Michael Hanselmann
    @param timeout: Timeout duration
89 7e8841bd Michael Hanselmann
    @type allow_negative: bool
90 7e8841bd Michael Hanselmann
    @param allow_negative: Whether to return values below zero
91 7e8841bd Michael Hanselmann
    @param _time_fn: Time function for unittests
92 7e8841bd Michael Hanselmann

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

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

129 d76167a5 Michael Hanselmann
  """
130 d76167a5 Michael Hanselmann
  __slots__ = [
131 d76167a5 Michael Hanselmann
    "_fd",
132 d76167a5 Michael Hanselmann
    "_poller",
133 d76167a5 Michael Hanselmann
    ]
134 d76167a5 Michael Hanselmann
135 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
136 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
137 d76167a5 Michael Hanselmann

138 d76167a5 Michael Hanselmann
    @type poller: select.poll
139 d76167a5 Michael Hanselmann
    @param poller: Poller object
140 d76167a5 Michael Hanselmann
    @type fd: int
141 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
142 d76167a5 Michael Hanselmann

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

151 d76167a5 Michael Hanselmann
    @type timeout: float or None
152 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
153 d76167a5 Michael Hanselmann

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

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

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

197 69b99987 Michael Hanselmann
    @type lock: threading.Lock
198 2419060d Guido Trotter
    @param lock: condition base lock
199 2419060d Guido Trotter

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

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

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

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

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

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

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

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

300 34cb5617 Guido Trotter
    @type timeout: float or None
301 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
302 d76167a5 Michael Hanselmann

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

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

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

348 48dabc6a Michael Hanselmann
  """
349 154b9580 Balazs Lecz
  __slots__ = [
350 c31825f7 Michael Hanselmann
    "_waiters",
351 34cb5617 Guido Trotter
    "_single_condition",
352 48dabc6a Michael Hanselmann
    ]
353 48dabc6a Michael Hanselmann
354 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
355 48dabc6a Michael Hanselmann
356 48dabc6a Michael Hanselmann
  def __init__(self, lock):
357 48dabc6a Michael Hanselmann
    """Initializes this class.
358 48dabc6a Michael Hanselmann

359 48dabc6a Michael Hanselmann
    """
360 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
361 c31825f7 Michael Hanselmann
    self._waiters = set()
362 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
363 48dabc6a Michael Hanselmann
364 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
365 48dabc6a Michael Hanselmann
    """Wait for a notification.
366 48dabc6a Michael Hanselmann

367 48dabc6a Michael Hanselmann
    @type timeout: float or None
368 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
369 48dabc6a Michael Hanselmann

370 48dabc6a Michael Hanselmann
    """
371 48dabc6a Michael Hanselmann
    self._check_owned()
372 48dabc6a Michael Hanselmann
373 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
374 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
375 c31825f7 Michael Hanselmann
    cond = self._single_condition
376 48dabc6a Michael Hanselmann
377 c31825f7 Michael Hanselmann
    self._waiters.add(threading.currentThread())
378 48dabc6a Michael Hanselmann
    try:
379 c31825f7 Michael Hanselmann
      cond.wait(timeout)
380 48dabc6a Michael Hanselmann
    finally:
381 c31825f7 Michael Hanselmann
      self._check_owned()
382 c31825f7 Michael Hanselmann
      self._waiters.remove(threading.currentThread())
383 48dabc6a Michael Hanselmann
384 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
385 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
386 48dabc6a Michael Hanselmann

387 48dabc6a Michael Hanselmann
    """
388 48dabc6a Michael Hanselmann
    self._check_owned()
389 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
390 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
391 48dabc6a Michael Hanselmann
392 c31825f7 Michael Hanselmann
  def get_waiting(self):
393 c31825f7 Michael Hanselmann
    """Returns a list of all waiting threads.
394 c31825f7 Michael Hanselmann

395 c31825f7 Michael Hanselmann
    """
396 c31825f7 Michael Hanselmann
    self._check_owned()
397 c31825f7 Michael Hanselmann
398 c31825f7 Michael Hanselmann
    return self._waiters
399 c31825f7 Michael Hanselmann
400 48dabc6a Michael Hanselmann
  def has_waiting(self):
401 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
402 48dabc6a Michael Hanselmann

403 48dabc6a Michael Hanselmann
    """
404 48dabc6a Michael Hanselmann
    self._check_owned()
405 48dabc6a Michael Hanselmann
406 c31825f7 Michael Hanselmann
    return bool(self._waiters)
407 48dabc6a Michael Hanselmann
408 48dabc6a Michael Hanselmann
409 84e344d4 Michael Hanselmann
class SharedLock(object):
410 162c1c1f Guido Trotter
  """Implements a shared lock.
411 162c1c1f Guido Trotter

412 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
413 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
414 162c1c1f Guido Trotter
  can call acquire_exclusive().
415 162c1c1f Guido Trotter

416 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
417 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
418 162c1c1f Guido Trotter
  eventually do so.
419 162c1c1f Guido Trotter

420 7f93570a Iustin Pop
  @type name: string
421 7f93570a Iustin Pop
  @ivar name: the name of the lock
422 7f93570a Iustin Pop

423 162c1c1f Guido Trotter
  """
424 84e344d4 Michael Hanselmann
  __slots__ = [
425 19b9ba9a Michael Hanselmann
    "__weakref__",
426 84e344d4 Michael Hanselmann
    "__active_shr_c",
427 84e344d4 Michael Hanselmann
    "__inactive_shr_c",
428 84e344d4 Michael Hanselmann
    "__deleted",
429 84e344d4 Michael Hanselmann
    "__exc",
430 84e344d4 Michael Hanselmann
    "__lock",
431 84e344d4 Michael Hanselmann
    "__pending",
432 84e344d4 Michael Hanselmann
    "__shr",
433 7f93570a Iustin Pop
    "name",
434 84e344d4 Michael Hanselmann
    ]
435 84e344d4 Michael Hanselmann
436 34cb5617 Guido Trotter
  __condition_class = PipeCondition
437 84e344d4 Michael Hanselmann
438 19b9ba9a Michael Hanselmann
  def __init__(self, name, monitor=None):
439 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
440 84e344d4 Michael Hanselmann

441 7f93570a Iustin Pop
    @param name: the name of the lock
442 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
443 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register
444 7f93570a Iustin Pop

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

474 19b9ba9a Michael Hanselmann
    @type fields: list of strings
475 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
476 19b9ba9a Michael Hanselmann

477 19b9ba9a Michael Hanselmann
    """
478 19b9ba9a Michael Hanselmann
    self.__lock.acquire()
479 19b9ba9a Michael Hanselmann
    try:
480 19b9ba9a Michael Hanselmann
      info = []
481 19b9ba9a Michael Hanselmann
482 19b9ba9a Michael Hanselmann
      # Note: to avoid unintentional race conditions, no references to
483 19b9ba9a Michael Hanselmann
      # modifiable objects should be returned unless they were created in this
484 19b9ba9a Michael Hanselmann
      # function.
485 19b9ba9a Michael Hanselmann
      for fname in fields:
486 19b9ba9a Michael Hanselmann
        if fname == "name":
487 19b9ba9a Michael Hanselmann
          info.append(self.name)
488 19b9ba9a Michael Hanselmann
        elif fname == "mode":
489 19b9ba9a Michael Hanselmann
          if self.__deleted:
490 19b9ba9a Michael Hanselmann
            info.append("deleted")
491 19b9ba9a Michael Hanselmann
            assert not (self.__exc or self.__shr)
492 19b9ba9a Michael Hanselmann
          elif self.__exc:
493 c31825f7 Michael Hanselmann
            info.append(_EXCLUSIVE_TEXT)
494 19b9ba9a Michael Hanselmann
          elif self.__shr:
495 c31825f7 Michael Hanselmann
            info.append(_SHARED_TEXT)
496 19b9ba9a Michael Hanselmann
          else:
497 19b9ba9a Michael Hanselmann
            info.append(None)
498 19b9ba9a Michael Hanselmann
        elif fname == "owner":
499 19b9ba9a Michael Hanselmann
          if self.__exc:
500 19b9ba9a Michael Hanselmann
            owner = [self.__exc]
501 19b9ba9a Michael Hanselmann
          else:
502 19b9ba9a Michael Hanselmann
            owner = self.__shr
503 19b9ba9a Michael Hanselmann
504 19b9ba9a Michael Hanselmann
          if owner:
505 19b9ba9a Michael Hanselmann
            assert not self.__deleted
506 19b9ba9a Michael Hanselmann
            info.append([i.getName() for i in owner])
507 19b9ba9a Michael Hanselmann
          else:
508 19b9ba9a Michael Hanselmann
            info.append(None)
509 c31825f7 Michael Hanselmann
        elif fname == "pending":
510 c31825f7 Michael Hanselmann
          data = []
511 c31825f7 Michael Hanselmann
512 c31825f7 Michael Hanselmann
          for cond in self.__pending:
513 c31825f7 Michael Hanselmann
            if cond in (self.__active_shr_c, self.__inactive_shr_c):
514 c31825f7 Michael Hanselmann
              mode = _SHARED_TEXT
515 c31825f7 Michael Hanselmann
            else:
516 c31825f7 Michael Hanselmann
              mode = _EXCLUSIVE_TEXT
517 c31825f7 Michael Hanselmann
518 c31825f7 Michael Hanselmann
            # This function should be fast as it runs with the lock held. Hence
519 c31825f7 Michael Hanselmann
            # not using utils.NiceSort.
520 c31825f7 Michael Hanselmann
            data.append((mode, sorted([i.getName()
521 c31825f7 Michael Hanselmann
                                       for i in cond.get_waiting()])))
522 c31825f7 Michael Hanselmann
523 c31825f7 Michael Hanselmann
          info.append(data)
524 19b9ba9a Michael Hanselmann
        else:
525 19b9ba9a Michael Hanselmann
          raise errors.OpExecError("Invalid query field '%s'" % fname)
526 19b9ba9a Michael Hanselmann
527 19b9ba9a Michael Hanselmann
      return info
528 19b9ba9a Michael Hanselmann
    finally:
529 19b9ba9a Michael Hanselmann
      self.__lock.release()
530 19b9ba9a Michael Hanselmann
531 84e344d4 Michael Hanselmann
  def __check_deleted(self):
532 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
533 84e344d4 Michael Hanselmann

534 84e344d4 Michael Hanselmann
    """
535 84e344d4 Michael Hanselmann
    if self.__deleted:
536 7f93570a Iustin Pop
      raise errors.LockError("Deleted lock %s" % self.name)
537 84e344d4 Michael Hanselmann
538 162c1c1f Guido Trotter
  def __is_sharer(self):
539 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
540 84e344d4 Michael Hanselmann

541 84e344d4 Michael Hanselmann
    """
542 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
543 162c1c1f Guido Trotter
544 162c1c1f Guido Trotter
  def __is_exclusive(self):
545 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
546 84e344d4 Michael Hanselmann

547 84e344d4 Michael Hanselmann
    """
548 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
549 162c1c1f Guido Trotter
550 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
551 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
552 162c1c1f Guido Trotter

553 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
554 162c1c1f Guido Trotter
    the internal lock.
555 162c1c1f Guido Trotter

556 162c1c1f Guido Trotter
    """
557 162c1c1f Guido Trotter
    if shared < 0:
558 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
559 162c1c1f Guido Trotter
    elif shared:
560 162c1c1f Guido Trotter
      return self.__is_sharer()
561 162c1c1f Guido Trotter
    else:
562 162c1c1f Guido Trotter
      return self.__is_exclusive()
563 162c1c1f Guido Trotter
564 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
565 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
566 162c1c1f Guido Trotter

567 c41eea6e Iustin Pop
    @param shared:
568 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
569 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
570 c41eea6e Iustin Pop
        - > 0: check for shared ownership
571 162c1c1f Guido Trotter

572 162c1c1f Guido Trotter
    """
573 162c1c1f Guido Trotter
    self.__lock.acquire()
574 162c1c1f Guido Trotter
    try:
575 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
576 162c1c1f Guido Trotter
    finally:
577 162c1c1f Guido Trotter
      self.__lock.release()
578 162c1c1f Guido Trotter
579 84e344d4 Michael Hanselmann
  def _count_pending(self):
580 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
581 a95fd5d7 Guido Trotter

582 84e344d4 Michael Hanselmann
    @rtype: int
583 a95fd5d7 Guido Trotter

584 a95fd5d7 Guido Trotter
    """
585 84e344d4 Michael Hanselmann
    self.__lock.acquire()
586 84e344d4 Michael Hanselmann
    try:
587 84e344d4 Michael Hanselmann
      return len(self.__pending)
588 84e344d4 Michael Hanselmann
    finally:
589 84e344d4 Michael Hanselmann
      self.__lock.release()
590 a95fd5d7 Guido Trotter
591 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
592 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
593 84e344d4 Michael Hanselmann

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

603 a95fd5d7 Guido Trotter
    """
604 84e344d4 Michael Hanselmann
    if shared:
605 84e344d4 Michael Hanselmann
      return self.__exc is None
606 84e344d4 Michael Hanselmann
    else:
607 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
608 a95fd5d7 Guido Trotter
609 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
610 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
611 a95fd5d7 Guido Trotter

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

614 84e344d4 Michael Hanselmann
    """
615 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
616 4d686df8 Guido Trotter
617 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
618 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
619 9216a9f7 Michael Hanselmann

620 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
621 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
622 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
623 9216a9f7 Michael Hanselmann

624 9216a9f7 Michael Hanselmann
    """
625 84e344d4 Michael Hanselmann
    self.__check_deleted()
626 9216a9f7 Michael Hanselmann
627 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
628 7f93570a Iustin Pop
    assert not self.__is_owned(), ("double acquire() on a non-recursive lock"
629 7f93570a Iustin Pop
                                   " %s" % self.name)
630 84e344d4 Michael Hanselmann
631 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
632 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
633 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
634 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
635 84e344d4 Michael Hanselmann
      return True
636 9216a9f7 Michael Hanselmann
637 84e344d4 Michael Hanselmann
    if shared:
638 84e344d4 Michael Hanselmann
      wait_condition = self.__active_shr_c
639 9216a9f7 Michael Hanselmann
640 84e344d4 Michael Hanselmann
      # Check if we're not yet in the queue
641 84e344d4 Michael Hanselmann
      if wait_condition not in self.__pending:
642 84e344d4 Michael Hanselmann
        self.__pending.append(wait_condition)
643 84e344d4 Michael Hanselmann
    else:
644 84e344d4 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock)
645 84e344d4 Michael Hanselmann
      # Always add to queue
646 84e344d4 Michael Hanselmann
      self.__pending.append(wait_condition)
647 84e344d4 Michael Hanselmann
648 84e344d4 Michael Hanselmann
    try:
649 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
650 84e344d4 Michael Hanselmann
      # expires.
651 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
652 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
653 84e344d4 Michael Hanselmann
        # Wait for notification
654 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
655 84e344d4 Michael Hanselmann
        self.__check_deleted()
656 84e344d4 Michael Hanselmann
657 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
658 84e344d4 Michael Hanselmann
        # internally for that case.
659 84e344d4 Michael Hanselmann
        if timeout is not None:
660 84e344d4 Michael Hanselmann
          break
661 84e344d4 Michael Hanselmann
662 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
663 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
664 84e344d4 Michael Hanselmann
        return True
665 9216a9f7 Michael Hanselmann
    finally:
666 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
667 84e344d4 Michael Hanselmann
      if not wait_condition.has_waiting() and not self.__deleted:
668 84e344d4 Michael Hanselmann
        self.__pending.remove(wait_condition)
669 9216a9f7 Michael Hanselmann
670 84e344d4 Michael Hanselmann
    return False
671 9216a9f7 Michael Hanselmann
672 008b92fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, test_notify=None):
673 162c1c1f Guido Trotter
    """Acquire a shared lock.
674 162c1c1f Guido Trotter

675 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
676 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
677 c41eea6e Iustin Pop
        exclusive lock will be acquired
678 84e344d4 Michael Hanselmann
    @type timeout: float
679 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
680 008b92fa Michael Hanselmann
    @type test_notify: callable or None
681 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
682 162c1c1f Guido Trotter

683 162c1c1f Guido Trotter
    """
684 162c1c1f Guido Trotter
    self.__lock.acquire()
685 162c1c1f Guido Trotter
    try:
686 008b92fa Michael Hanselmann
      # We already got the lock, notify now
687 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
688 008b92fa Michael Hanselmann
        test_notify()
689 008b92fa Michael Hanselmann
690 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
691 162c1c1f Guido Trotter
    finally:
692 162c1c1f Guido Trotter
      self.__lock.release()
693 162c1c1f Guido Trotter
694 162c1c1f Guido Trotter
  def release(self):
695 162c1c1f Guido Trotter
    """Release a Shared Lock.
696 162c1c1f Guido Trotter

697 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
698 162c1c1f Guido Trotter
    before calling this function.
699 162c1c1f Guido Trotter

700 162c1c1f Guido Trotter
    """
701 162c1c1f Guido Trotter
    self.__lock.acquire()
702 162c1c1f Guido Trotter
    try:
703 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
704 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
705 84e344d4 Michael Hanselmann
706 162c1c1f Guido Trotter
      # Autodetect release type
707 162c1c1f Guido Trotter
      if self.__is_exclusive():
708 162c1c1f Guido Trotter
        self.__exc = None
709 84e344d4 Michael Hanselmann
      else:
710 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
711 162c1c1f Guido Trotter
712 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
713 84e344d4 Michael Hanselmann
      if self.__pending:
714 84e344d4 Michael Hanselmann
        first_condition = self.__pending[0]
715 84e344d4 Michael Hanselmann
        first_condition.notifyAll()
716 4d686df8 Guido Trotter
717 84e344d4 Michael Hanselmann
        if first_condition == self.__active_shr_c:
718 84e344d4 Michael Hanselmann
          self.__active_shr_c = self.__inactive_shr_c
719 84e344d4 Michael Hanselmann
          self.__inactive_shr_c = first_condition
720 162c1c1f Guido Trotter
721 162c1c1f Guido Trotter
    finally:
722 162c1c1f Guido Trotter
      self.__lock.release()
723 162c1c1f Guido Trotter
724 84e344d4 Michael Hanselmann
  def delete(self, timeout=None):
725 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
726 a95fd5d7 Guido Trotter

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

731 84e344d4 Michael Hanselmann
    @type timeout: float
732 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
733 a95fd5d7 Guido Trotter

734 a95fd5d7 Guido Trotter
    """
735 a95fd5d7 Guido Trotter
    self.__lock.acquire()
736 a95fd5d7 Guido Trotter
    try:
737 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
738 84e344d4 Michael Hanselmann
739 84e344d4 Michael Hanselmann
      self.__check_deleted()
740 a95fd5d7 Guido Trotter
741 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
742 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
743 a95fd5d7 Guido Trotter
744 84e344d4 Michael Hanselmann
      if not acquired:
745 a66bd91b Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout)
746 a66bd91b Michael Hanselmann
747 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
748 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
749 84e344d4 Michael Hanselmann
750 84e344d4 Michael Hanselmann
      if acquired:
751 84e344d4 Michael Hanselmann
        self.__deleted = True
752 84e344d4 Michael Hanselmann
        self.__exc = None
753 a95fd5d7 Guido Trotter
754 19b9ba9a Michael Hanselmann
        assert not (self.__exc or self.__shr), "Found owner during deletion"
755 19b9ba9a Michael Hanselmann
756 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
757 84e344d4 Michael Hanselmann
        while self.__pending:
758 84e344d4 Michael Hanselmann
          self.__pending.pop().notifyAll()
759 a95fd5d7 Guido Trotter
760 84e344d4 Michael Hanselmann
      return acquired
761 a95fd5d7 Guido Trotter
    finally:
762 a95fd5d7 Guido Trotter
      self.__lock.release()
763 a95fd5d7 Guido Trotter
764 1a4e32d0 Guido Trotter
  def _release_save(self):
765 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
766 1a4e32d0 Guido Trotter
    self.release()
767 1a4e32d0 Guido Trotter
    return shared
768 1a4e32d0 Guido Trotter
769 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
770 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
771 1a4e32d0 Guido Trotter
772 aaae9bc0 Guido Trotter
773 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
774 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
775 e310b019 Guido Trotter
ALL_SET = None
776 e310b019 Guido Trotter
777 e310b019 Guido Trotter
778 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
779 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
780 5aab242c Michael Hanselmann

781 5aab242c Michael Hanselmann
  """
782 5aab242c Michael Hanselmann
783 5aab242c Michael Hanselmann
784 aaae9bc0 Guido Trotter
class LockSet:
785 aaae9bc0 Guido Trotter
  """Implements a set of locks.
786 aaae9bc0 Guido Trotter

787 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
788 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
789 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
790 aaae9bc0 Guido Trotter
  preventing deadlock.
791 aaae9bc0 Guido Trotter

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

794 7f93570a Iustin Pop
  @type name: string
795 7f93570a Iustin Pop
  @ivar name: the name of the lockset
796 7f93570a Iustin Pop

797 aaae9bc0 Guido Trotter
  """
798 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
799 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
800 aaae9bc0 Guido Trotter

801 ec44d893 Guido Trotter
    @type members: list of strings
802 c41eea6e Iustin Pop
    @param members: initial members of the set
803 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
804 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
805 aaae9bc0 Guido Trotter

806 aaae9bc0 Guido Trotter
    """
807 7f93570a Iustin Pop
    assert members is not None, "members parameter is not a list"
808 7f93570a Iustin Pop
    self.name = name
809 7f93570a Iustin Pop
810 19b9ba9a Michael Hanselmann
    # Lock monitor
811 19b9ba9a Michael Hanselmann
    self.__monitor = monitor
812 19b9ba9a Michael Hanselmann
813 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
814 7f93570a Iustin Pop
    self.__lock = SharedLock(name)
815 aaae9bc0 Guido Trotter
816 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
817 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
818 aaae9bc0 Guido Trotter
    self.__lockdict = {}
819 aaae9bc0 Guido Trotter
820 7f93570a Iustin Pop
    for mname in members:
821 19b9ba9a Michael Hanselmann
      self.__lockdict[mname] = SharedLock(self._GetLockName(mname),
822 19b9ba9a Michael Hanselmann
                                          monitor=monitor)
823 aaae9bc0 Guido Trotter
824 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
825 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
826 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
827 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
828 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
829 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
830 aaae9bc0 Guido Trotter
    # will be trouble.
831 aaae9bc0 Guido Trotter
    self.__owners = {}
832 aaae9bc0 Guido Trotter
833 4fb780d1 Michael Hanselmann
  def _GetLockName(self, mname):
834 4fb780d1 Michael Hanselmann
    """Returns the name for a member lock.
835 4fb780d1 Michael Hanselmann

836 4fb780d1 Michael Hanselmann
    """
837 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
838 4fb780d1 Michael Hanselmann
839 aaae9bc0 Guido Trotter
  def _is_owned(self):
840 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
841 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
842 aaae9bc0 Guido Trotter
843 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
844 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
845 b2dabfd6 Guido Trotter
    if name is None:
846 b2dabfd6 Guido Trotter
      if not self._is_owned():
847 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
848 aaae9bc0 Guido Trotter
    else:
849 b2dabfd6 Guido Trotter
      if self._is_owned():
850 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
851 b2dabfd6 Guido Trotter
      else:
852 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
853 b2dabfd6 Guido Trotter
854 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
855 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
856 aaae9bc0 Guido Trotter
857 e4335b5b Michael Hanselmann
    assert not (name is None and self.__lock._is_owned()), \
858 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
859 e4335b5b Michael Hanselmann
860 b2dabfd6 Guido Trotter
    if name is not None:
861 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
862 b2dabfd6 Guido Trotter
863 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
864 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
865 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
866 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
867 aaae9bc0 Guido Trotter
868 aaae9bc0 Guido Trotter
  def _list_owned(self):
869 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
870 aaae9bc0 Guido Trotter
    if self._is_owned():
871 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
872 aaae9bc0 Guido Trotter
    else:
873 aaae9bc0 Guido Trotter
      return set()
874 aaae9bc0 Guido Trotter
875 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
876 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
877 5aab242c Michael Hanselmann
    for lname in self._list_owned():
878 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
879 56452af7 Michael Hanselmann
      if lock._is_owned():
880 56452af7 Michael Hanselmann
        lock.release()
881 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
882 5aab242c Michael Hanselmann
883 aaae9bc0 Guido Trotter
  def __names(self):
884 aaae9bc0 Guido Trotter
    """Return the current set of names.
885 aaae9bc0 Guido Trotter

886 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
887 aaae9bc0 Guido Trotter
    result after releasing the lock.
888 aaae9bc0 Guido Trotter

889 aaae9bc0 Guido Trotter
    """
890 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
891 aaae9bc0 Guido Trotter
892 aaae9bc0 Guido Trotter
  def _names(self):
893 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
894 aaae9bc0 Guido Trotter

895 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
896 cdb08f44 Michael Hanselmann

897 aaae9bc0 Guido Trotter
    """
898 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
899 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
900 d4803c24 Guido Trotter
    release_lock = False
901 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
902 d4803c24 Guido Trotter
      release_lock = True
903 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
904 aaae9bc0 Guido Trotter
    try:
905 aaae9bc0 Guido Trotter
      result = self.__names()
906 aaae9bc0 Guido Trotter
    finally:
907 d4803c24 Guido Trotter
      if release_lock:
908 d4803c24 Guido Trotter
        self.__lock.release()
909 0cf257c5 Guido Trotter
    return set(result)
910 aaae9bc0 Guido Trotter
911 5aab242c Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, test_notify=None):
912 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
913 aaae9bc0 Guido Trotter

914 ec44d893 Guido Trotter
    @type names: list of strings (or string)
915 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
916 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
917 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
918 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
919 c41eea6e Iustin Pop
        exclusive lock will be acquired
920 5aab242c Michael Hanselmann
    @type timeout: float or None
921 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
922 5aab242c Michael Hanselmann
    @type test_notify: callable or None
923 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
924 aaae9bc0 Guido Trotter

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

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

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

984 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
985 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
986 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
987 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
988 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
989 76e2f08a Michael Hanselmann

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

1074 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1075 aaae9bc0 Guido Trotter
    before releasing them.
1076 aaae9bc0 Guido Trotter

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

1081 aaae9bc0 Guido Trotter
    """
1082 7f93570a Iustin Pop
    assert self._is_owned(), ("release() on lock set %s while not owner" %
1083 7f93570a Iustin Pop
                              self.name)
1084 aaae9bc0 Guido Trotter
1085 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1086 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1087 aaae9bc0 Guido Trotter
      names = [names]
1088 aaae9bc0 Guido Trotter
1089 aaae9bc0 Guido Trotter
    if names is None:
1090 aaae9bc0 Guido Trotter
      names = self._list_owned()
1091 aaae9bc0 Guido Trotter
    else:
1092 aaae9bc0 Guido Trotter
      names = set(names)
1093 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
1094 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1095 7f93570a Iustin Pop
               (names.difference(self._list_owned()), self.name))
1096 aaae9bc0 Guido Trotter
1097 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1098 3b7ed473 Guido Trotter
    # After this 'add' can work again
1099 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
1100 3b7ed473 Guido Trotter
      self.__lock.release()
1101 b2dabfd6 Guido Trotter
      self._del_owned()
1102 3b7ed473 Guido Trotter
1103 aaae9bc0 Guido Trotter
    for lockname in names:
1104 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1105 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1106 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1107 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1108 aaae9bc0 Guido Trotter
1109 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1110 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1111 aaae9bc0 Guido Trotter

1112 ec44d893 Guido Trotter
    @type names: list of strings
1113 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1114 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1115 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1116 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1117 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1118 aaae9bc0 Guido Trotter

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

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

1178 ec44d893 Guido Trotter
    @type names: list of strings
1179 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1180 aaae9bc0 Guido Trotter

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

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

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

1266 7ee7c0c7 Guido Trotter
  """
1267 7ee7c0c7 Guido Trotter
  _instance = None
1268 7ee7c0c7 Guido Trotter
1269 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1270 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1271 7ee7c0c7 Guido Trotter

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

1275 c41eea6e Iustin Pop
    @param nodes: list of node names
1276 c41eea6e Iustin Pop
    @param instances: list of instance names
1277 7ee7c0c7 Guido Trotter

1278 7ee7c0c7 Guido Trotter
    """
1279 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1280 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1281 c41eea6e Iustin Pop
1282 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1283 7ee7c0c7 Guido Trotter
1284 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1285 19b9ba9a Michael Hanselmann
1286 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1287 7ee7c0c7 Guido Trotter
    # locking order.
1288 7ee7c0c7 Guido Trotter
    self.__keyring = {
1289 19b9ba9a Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "BGL", monitor=self._monitor),
1290 19b9ba9a Michael Hanselmann
      LEVEL_NODE: LockSet(nodes, "nodes", monitor=self._monitor),
1291 19b9ba9a Michael Hanselmann
      LEVEL_INSTANCE: LockSet(instances, "instances",
1292 19b9ba9a Michael Hanselmann
                              monitor=self._monitor),
1293 19b9ba9a Michael Hanselmann
      }
1294 19b9ba9a Michael Hanselmann
1295 19b9ba9a Michael Hanselmann
  def QueryLocks(self, fields, sync):
1296 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1297 19b9ba9a Michael Hanselmann

1298 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1299 19b9ba9a Michael Hanselmann

1300 19b9ba9a Michael Hanselmann
    """
1301 19b9ba9a Michael Hanselmann
    return self._monitor.QueryLocks(fields, sync)
1302 7ee7c0c7 Guido Trotter
1303 7ee7c0c7 Guido Trotter
  def _names(self, level):
1304 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1305 7ee7c0c7 Guido Trotter

1306 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1307 c41eea6e Iustin Pop

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

1310 7ee7c0c7 Guido Trotter
    """
1311 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1312 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1313 7ee7c0c7 Guido Trotter
1314 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1315 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1316 7ee7c0c7 Guido Trotter

1317 7ee7c0c7 Guido Trotter
    """
1318 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1319 7ee7c0c7 Guido Trotter
1320 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1321 d4f4b3e7 Guido Trotter
1322 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1323 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1324 7ee7c0c7 Guido Trotter

1325 7ee7c0c7 Guido Trotter
    """
1326 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1327 7ee7c0c7 Guido Trotter
1328 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1329 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1330 7ee7c0c7 Guido Trotter

1331 7ee7c0c7 Guido Trotter
    """
1332 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1333 7ee7c0c7 Guido Trotter
    # the test cases.
1334 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1335 7ee7c0c7 Guido Trotter
1336 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1337 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1338 7ee7c0c7 Guido Trotter

1339 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1340 7ee7c0c7 Guido Trotter

1341 7ee7c0c7 Guido Trotter
    """
1342 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1343 7ee7c0c7 Guido Trotter
1344 c70d2d9b Iustin Pop
  @staticmethod
1345 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1346 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1347 c41eea6e Iustin Pop

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

1351 7ee7c0c7 Guido Trotter
    """
1352 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1353 7ee7c0c7 Guido Trotter
1354 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1355 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1356 7ee7c0c7 Guido Trotter

1357 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1358 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1359 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1360 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1361 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1362 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1363 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1364 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1365 5e0a6daf Michael Hanselmann
    @type timeout: float
1366 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1367 7ee7c0c7 Guido Trotter

1368 7ee7c0c7 Guido Trotter
    """
1369 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1370 7ee7c0c7 Guido Trotter
1371 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1372 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1373 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1374 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1375 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1376 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1377 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1378 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1379 7ee7c0c7 Guido Trotter
1380 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1381 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1382 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1383 7ee7c0c7 Guido Trotter
1384 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1385 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1386 7ee7c0c7 Guido Trotter
1387 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1388 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1389 7ee7c0c7 Guido Trotter

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

1393 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1394 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1395 ec44d893 Guido Trotter
    @type names: list of strings, or None
1396 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1397 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1398 7ee7c0c7 Guido Trotter

1399 7ee7c0c7 Guido Trotter
    """
1400 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1401 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1402 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1403 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1404 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1405 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1406 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1407 7ee7c0c7 Guido Trotter
1408 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1409 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1410 7ee7c0c7 Guido Trotter
1411 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1412 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1413 7ee7c0c7 Guido Trotter

1414 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1415 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1416 ec44d893 Guido Trotter
    @type names: list of strings
1417 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1418 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1419 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1420 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1421 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1422 c41eea6e Iustin Pop

1423 7ee7c0c7 Guido Trotter
    """
1424 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1425 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1426 7ee7c0c7 Guido Trotter
           " operations")
1427 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1428 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1429 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1430 7ee7c0c7 Guido Trotter
1431 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1432 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1433 7ee7c0c7 Guido Trotter

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

1437 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1438 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1439 ec44d893 Guido Trotter
    @type names: list of strings
1440 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1441 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1442 7ee7c0c7 Guido Trotter

1443 7ee7c0c7 Guido Trotter
    """
1444 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1445 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1446 7ee7c0c7 Guido Trotter
           " operations")
1447 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1448 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1449 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1450 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1451 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1452 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1453 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1454 19b9ba9a Michael Hanselmann
1455 19b9ba9a Michael Hanselmann
1456 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1457 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1458 19b9ba9a Michael Hanselmann
1459 19b9ba9a Michael Hanselmann
  def __init__(self):
1460 19b9ba9a Michael Hanselmann
    """Initializes this class.
1461 19b9ba9a Michael Hanselmann

1462 19b9ba9a Michael Hanselmann
    """
1463 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1464 19b9ba9a Michael Hanselmann
1465 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1466 19b9ba9a Michael Hanselmann
    # references and deletion.
1467 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1468 19b9ba9a Michael Hanselmann
1469 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1470 19b9ba9a Michael Hanselmann
  def RegisterLock(self, lock):
1471 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1472 19b9ba9a Michael Hanselmann

1473 19b9ba9a Michael Hanselmann
    """
1474 19b9ba9a Michael Hanselmann
    logging.debug("Registering lock %s", lock.name)
1475 19b9ba9a Michael Hanselmann
    assert lock not in self._locks, "Duplicate lock registration"
1476 19b9ba9a Michael Hanselmann
    assert not compat.any(lock.name == i.name for i in self._locks.keys()), \
1477 19b9ba9a Michael Hanselmann
           "Found duplicate lock name"
1478 19b9ba9a Michael Hanselmann
    self._locks[lock] = None
1479 19b9ba9a Michael Hanselmann
1480 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1481 19b9ba9a Michael Hanselmann
  def _GetLockInfo(self, fields):
1482 19b9ba9a Michael Hanselmann
    """Get information from all locks while the monitor lock is held.
1483 19b9ba9a Michael Hanselmann

1484 19b9ba9a Michael Hanselmann
    """
1485 19b9ba9a Michael Hanselmann
    result = {}
1486 19b9ba9a Michael Hanselmann
1487 19b9ba9a Michael Hanselmann
    for lock in self._locks.keys():
1488 19b9ba9a Michael Hanselmann
      assert lock.name not in result, "Found duplicate lock name"
1489 19b9ba9a Michael Hanselmann
      result[lock.name] = lock.GetInfo(fields)
1490 19b9ba9a Michael Hanselmann
1491 19b9ba9a Michael Hanselmann
    return result
1492 19b9ba9a Michael Hanselmann
1493 19b9ba9a Michael Hanselmann
  def QueryLocks(self, fields, sync):
1494 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1495 19b9ba9a Michael Hanselmann

1496 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1497 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1498 19b9ba9a Michael Hanselmann
    @type sync: boolean
1499 19b9ba9a Michael Hanselmann
    @param sync: Whether to operate in synchronous mode
1500 19b9ba9a Michael Hanselmann

1501 19b9ba9a Michael Hanselmann
    """
1502 19b9ba9a Michael Hanselmann
    if sync:
1503 19b9ba9a Michael Hanselmann
      raise NotImplementedError("Synchronous queries are not implemented")
1504 19b9ba9a Michael Hanselmann
1505 19b9ba9a Michael Hanselmann
    # Get all data without sorting
1506 19b9ba9a Michael Hanselmann
    result = self._GetLockInfo(fields)
1507 19b9ba9a Michael Hanselmann
1508 19b9ba9a Michael Hanselmann
    # Sort by name
1509 19b9ba9a Michael Hanselmann
    return [result[name] for name in utils.NiceSort(result.keys())]