Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 66e884e1

History | View | Annotate | Download (47.8 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 errno
32 19b9ba9a Michael Hanselmann
import weakref
33 19b9ba9a Michael Hanselmann
import logging
34 887c7aa6 Michael Hanselmann
import heapq
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 887c7aa6 Michael Hanselmann
_DEFAULT_PRIORITY = 0
45 887c7aa6 Michael Hanselmann
46 c31825f7 Michael Hanselmann
47 dbb11e8b Guido Trotter
def ssynchronized(mylock, shared=0):
48 42a999d1 Guido Trotter
  """Shared Synchronization decorator.
49 42a999d1 Guido Trotter

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

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

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

78 d76167a5 Michael Hanselmann
  """
79 d76167a5 Michael Hanselmann
  __slots__ = [
80 d76167a5 Michael Hanselmann
    "_fd",
81 d76167a5 Michael Hanselmann
    "_poller",
82 d76167a5 Michael Hanselmann
    ]
83 d76167a5 Michael Hanselmann
84 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
85 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
86 d76167a5 Michael Hanselmann

87 d76167a5 Michael Hanselmann
    @type poller: select.poll
88 d76167a5 Michael Hanselmann
    @param poller: Poller object
89 d76167a5 Michael Hanselmann
    @type fd: int
90 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
91 d76167a5 Michael Hanselmann

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

100 d76167a5 Michael Hanselmann
    @type timeout: float or None
101 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
102 d76167a5 Michael Hanselmann

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

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

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

146 69b99987 Michael Hanselmann
    @type lock: threading.Lock
147 2419060d Guido Trotter
    @param lock: condition base lock
148 2419060d Guido Trotter

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

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

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

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

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

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

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

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

249 34cb5617 Guido Trotter
    @type timeout: float or None
250 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
251 d76167a5 Michael Hanselmann

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

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

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

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

308 48dabc6a Michael Hanselmann
    """
309 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
310 c31825f7 Michael Hanselmann
    self._waiters = set()
311 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
312 48dabc6a Michael Hanselmann
313 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
314 48dabc6a Michael Hanselmann
    """Wait for a notification.
315 48dabc6a Michael Hanselmann

316 48dabc6a Michael Hanselmann
    @type timeout: float or None
317 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
318 48dabc6a Michael Hanselmann

319 48dabc6a Michael Hanselmann
    """
320 48dabc6a Michael Hanselmann
    self._check_owned()
321 48dabc6a Michael Hanselmann
322 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
323 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
324 c31825f7 Michael Hanselmann
    cond = self._single_condition
325 48dabc6a Michael Hanselmann
326 c31825f7 Michael Hanselmann
    self._waiters.add(threading.currentThread())
327 48dabc6a Michael Hanselmann
    try:
328 c31825f7 Michael Hanselmann
      cond.wait(timeout)
329 48dabc6a Michael Hanselmann
    finally:
330 c31825f7 Michael Hanselmann
      self._check_owned()
331 c31825f7 Michael Hanselmann
      self._waiters.remove(threading.currentThread())
332 48dabc6a Michael Hanselmann
333 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
334 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
335 48dabc6a Michael Hanselmann

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

344 c31825f7 Michael Hanselmann
    """
345 c31825f7 Michael Hanselmann
    self._check_owned()
346 c31825f7 Michael Hanselmann
347 c31825f7 Michael Hanselmann
    return self._waiters
348 c31825f7 Michael Hanselmann
349 48dabc6a Michael Hanselmann
  def has_waiting(self):
350 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
351 48dabc6a Michael Hanselmann

352 48dabc6a Michael Hanselmann
    """
353 48dabc6a Michael Hanselmann
    self._check_owned()
354 48dabc6a Michael Hanselmann
355 c31825f7 Michael Hanselmann
    return bool(self._waiters)
356 48dabc6a Michael Hanselmann
357 48dabc6a Michael Hanselmann
358 887c7aa6 Michael Hanselmann
class _PipeConditionWithMode(PipeCondition):
359 887c7aa6 Michael Hanselmann
  __slots__ = [
360 887c7aa6 Michael Hanselmann
    "shared",
361 887c7aa6 Michael Hanselmann
    ]
362 887c7aa6 Michael Hanselmann
363 887c7aa6 Michael Hanselmann
  def __init__(self, lock, shared):
364 887c7aa6 Michael Hanselmann
    """Initializes this class.
365 887c7aa6 Michael Hanselmann

366 887c7aa6 Michael Hanselmann
    """
367 887c7aa6 Michael Hanselmann
    self.shared = shared
368 887c7aa6 Michael Hanselmann
    PipeCondition.__init__(self, lock)
369 887c7aa6 Michael Hanselmann
370 887c7aa6 Michael Hanselmann
371 84e344d4 Michael Hanselmann
class SharedLock(object):
372 162c1c1f Guido Trotter
  """Implements a shared lock.
373 162c1c1f Guido Trotter

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

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

386 7f93570a Iustin Pop
  @type name: string
387 7f93570a Iustin Pop
  @ivar name: the name of the lock
388 7f93570a Iustin Pop

389 162c1c1f Guido Trotter
  """
390 84e344d4 Michael Hanselmann
  __slots__ = [
391 19b9ba9a Michael Hanselmann
    "__weakref__",
392 84e344d4 Michael Hanselmann
    "__deleted",
393 84e344d4 Michael Hanselmann
    "__exc",
394 84e344d4 Michael Hanselmann
    "__lock",
395 84e344d4 Michael Hanselmann
    "__pending",
396 887c7aa6 Michael Hanselmann
    "__pending_by_prio",
397 887c7aa6 Michael Hanselmann
    "__pending_shared",
398 84e344d4 Michael Hanselmann
    "__shr",
399 7f93570a Iustin Pop
    "name",
400 84e344d4 Michael Hanselmann
    ]
401 84e344d4 Michael Hanselmann
402 887c7aa6 Michael Hanselmann
  __condition_class = _PipeConditionWithMode
403 84e344d4 Michael Hanselmann
404 19b9ba9a Michael Hanselmann
  def __init__(self, name, monitor=None):
405 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
406 84e344d4 Michael Hanselmann

407 7f93570a Iustin Pop
    @param name: the name of the lock
408 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
409 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register
410 7f93570a Iustin Pop

411 84e344d4 Michael Hanselmann
    """
412 84e344d4 Michael Hanselmann
    object.__init__(self)
413 84e344d4 Michael Hanselmann
414 7f93570a Iustin Pop
    self.name = name
415 7f93570a Iustin Pop
416 84e344d4 Michael Hanselmann
    # Internal lock
417 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
418 162c1c1f Guido Trotter
419 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
420 84e344d4 Michael Hanselmann
    self.__pending = []
421 887c7aa6 Michael Hanselmann
    self.__pending_by_prio = {}
422 887c7aa6 Michael Hanselmann
    self.__pending_shared = {}
423 84e344d4 Michael Hanselmann
424 84e344d4 Michael Hanselmann
    # Current lock holders
425 162c1c1f Guido Trotter
    self.__shr = set()
426 162c1c1f Guido Trotter
    self.__exc = None
427 162c1c1f Guido Trotter
428 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
429 a95fd5d7 Guido Trotter
    self.__deleted = False
430 a95fd5d7 Guido Trotter
431 19b9ba9a Michael Hanselmann
    # Register with lock monitor
432 19b9ba9a Michael Hanselmann
    if monitor:
433 19b9ba9a Michael Hanselmann
      monitor.RegisterLock(self)
434 19b9ba9a Michael Hanselmann
435 19b9ba9a Michael Hanselmann
  def GetInfo(self, fields):
436 19b9ba9a Michael Hanselmann
    """Retrieves information for querying locks.
437 19b9ba9a Michael Hanselmann

438 19b9ba9a Michael Hanselmann
    @type fields: list of strings
439 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
440 19b9ba9a Michael Hanselmann

441 19b9ba9a Michael Hanselmann
    """
442 19b9ba9a Michael Hanselmann
    self.__lock.acquire()
443 19b9ba9a Michael Hanselmann
    try:
444 19b9ba9a Michael Hanselmann
      info = []
445 19b9ba9a Michael Hanselmann
446 19b9ba9a Michael Hanselmann
      # Note: to avoid unintentional race conditions, no references to
447 19b9ba9a Michael Hanselmann
      # modifiable objects should be returned unless they were created in this
448 19b9ba9a Michael Hanselmann
      # function.
449 19b9ba9a Michael Hanselmann
      for fname in fields:
450 19b9ba9a Michael Hanselmann
        if fname == "name":
451 19b9ba9a Michael Hanselmann
          info.append(self.name)
452 19b9ba9a Michael Hanselmann
        elif fname == "mode":
453 19b9ba9a Michael Hanselmann
          if self.__deleted:
454 19b9ba9a Michael Hanselmann
            info.append("deleted")
455 19b9ba9a Michael Hanselmann
            assert not (self.__exc or self.__shr)
456 19b9ba9a Michael Hanselmann
          elif self.__exc:
457 c31825f7 Michael Hanselmann
            info.append(_EXCLUSIVE_TEXT)
458 19b9ba9a Michael Hanselmann
          elif self.__shr:
459 c31825f7 Michael Hanselmann
            info.append(_SHARED_TEXT)
460 19b9ba9a Michael Hanselmann
          else:
461 19b9ba9a Michael Hanselmann
            info.append(None)
462 19b9ba9a Michael Hanselmann
        elif fname == "owner":
463 19b9ba9a Michael Hanselmann
          if self.__exc:
464 19b9ba9a Michael Hanselmann
            owner = [self.__exc]
465 19b9ba9a Michael Hanselmann
          else:
466 19b9ba9a Michael Hanselmann
            owner = self.__shr
467 19b9ba9a Michael Hanselmann
468 19b9ba9a Michael Hanselmann
          if owner:
469 19b9ba9a Michael Hanselmann
            assert not self.__deleted
470 19b9ba9a Michael Hanselmann
            info.append([i.getName() for i in owner])
471 19b9ba9a Michael Hanselmann
          else:
472 19b9ba9a Michael Hanselmann
            info.append(None)
473 c31825f7 Michael Hanselmann
        elif fname == "pending":
474 c31825f7 Michael Hanselmann
          data = []
475 c31825f7 Michael Hanselmann
476 887c7aa6 Michael Hanselmann
          # Sorting instead of copying and using heaq functions for simplicity
477 887c7aa6 Michael Hanselmann
          for (_, prioqueue) in sorted(self.__pending):
478 887c7aa6 Michael Hanselmann
            for cond in prioqueue:
479 887c7aa6 Michael Hanselmann
              if cond.shared:
480 887c7aa6 Michael Hanselmann
                mode = _SHARED_TEXT
481 887c7aa6 Michael Hanselmann
              else:
482 887c7aa6 Michael Hanselmann
                mode = _EXCLUSIVE_TEXT
483 c31825f7 Michael Hanselmann
484 887c7aa6 Michael Hanselmann
              # This function should be fast as it runs with the lock held.
485 887c7aa6 Michael Hanselmann
              # Hence not using utils.NiceSort.
486 887c7aa6 Michael Hanselmann
              data.append((mode, sorted(i.getName()
487 887c7aa6 Michael Hanselmann
                                        for i in cond.get_waiting())))
488 c31825f7 Michael Hanselmann
489 c31825f7 Michael Hanselmann
          info.append(data)
490 19b9ba9a Michael Hanselmann
        else:
491 19b9ba9a Michael Hanselmann
          raise errors.OpExecError("Invalid query field '%s'" % fname)
492 19b9ba9a Michael Hanselmann
493 19b9ba9a Michael Hanselmann
      return info
494 19b9ba9a Michael Hanselmann
    finally:
495 19b9ba9a Michael Hanselmann
      self.__lock.release()
496 19b9ba9a Michael Hanselmann
497 84e344d4 Michael Hanselmann
  def __check_deleted(self):
498 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
499 84e344d4 Michael Hanselmann

500 84e344d4 Michael Hanselmann
    """
501 84e344d4 Michael Hanselmann
    if self.__deleted:
502 7f93570a Iustin Pop
      raise errors.LockError("Deleted lock %s" % self.name)
503 84e344d4 Michael Hanselmann
504 162c1c1f Guido Trotter
  def __is_sharer(self):
505 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
506 84e344d4 Michael Hanselmann

507 84e344d4 Michael Hanselmann
    """
508 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
509 162c1c1f Guido Trotter
510 162c1c1f Guido Trotter
  def __is_exclusive(self):
511 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
512 84e344d4 Michael Hanselmann

513 84e344d4 Michael Hanselmann
    """
514 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
515 162c1c1f Guido Trotter
516 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
517 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
518 162c1c1f Guido Trotter

519 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
520 162c1c1f Guido Trotter
    the internal lock.
521 162c1c1f Guido Trotter

522 162c1c1f Guido Trotter
    """
523 162c1c1f Guido Trotter
    if shared < 0:
524 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
525 162c1c1f Guido Trotter
    elif shared:
526 162c1c1f Guido Trotter
      return self.__is_sharer()
527 162c1c1f Guido Trotter
    else:
528 162c1c1f Guido Trotter
      return self.__is_exclusive()
529 162c1c1f Guido Trotter
530 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
531 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
532 162c1c1f Guido Trotter

533 c41eea6e Iustin Pop
    @param shared:
534 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
535 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
536 c41eea6e Iustin Pop
        - > 0: check for shared ownership
537 162c1c1f Guido Trotter

538 162c1c1f Guido Trotter
    """
539 162c1c1f Guido Trotter
    self.__lock.acquire()
540 162c1c1f Guido Trotter
    try:
541 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
542 162c1c1f Guido Trotter
    finally:
543 162c1c1f Guido Trotter
      self.__lock.release()
544 162c1c1f Guido Trotter
545 84e344d4 Michael Hanselmann
  def _count_pending(self):
546 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
547 a95fd5d7 Guido Trotter

548 84e344d4 Michael Hanselmann
    @rtype: int
549 a95fd5d7 Guido Trotter

550 a95fd5d7 Guido Trotter
    """
551 84e344d4 Michael Hanselmann
    self.__lock.acquire()
552 84e344d4 Michael Hanselmann
    try:
553 887c7aa6 Michael Hanselmann
      return sum(len(prioqueue) for (_, prioqueue) in self.__pending)
554 887c7aa6 Michael Hanselmann
    finally:
555 887c7aa6 Michael Hanselmann
      self.__lock.release()
556 887c7aa6 Michael Hanselmann
557 887c7aa6 Michael Hanselmann
  def _check_empty(self):
558 887c7aa6 Michael Hanselmann
    """Checks whether there are any pending acquires.
559 887c7aa6 Michael Hanselmann

560 887c7aa6 Michael Hanselmann
    @rtype: bool
561 887c7aa6 Michael Hanselmann

562 887c7aa6 Michael Hanselmann
    """
563 887c7aa6 Michael Hanselmann
    self.__lock.acquire()
564 887c7aa6 Michael Hanselmann
    try:
565 887c7aa6 Michael Hanselmann
      # Order is important: __find_first_pending_queue modifies __pending
566 887c7aa6 Michael Hanselmann
      return not (self.__find_first_pending_queue() or
567 887c7aa6 Michael Hanselmann
                  self.__pending or
568 887c7aa6 Michael Hanselmann
                  self.__pending_by_prio or
569 887c7aa6 Michael Hanselmann
                  self.__pending_shared)
570 84e344d4 Michael Hanselmann
    finally:
571 84e344d4 Michael Hanselmann
      self.__lock.release()
572 a95fd5d7 Guido Trotter
573 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
574 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
575 84e344d4 Michael Hanselmann

576 84e344d4 Michael Hanselmann
    """
577 84e344d4 Michael Hanselmann
    if shared:
578 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
579 84e344d4 Michael Hanselmann
    else:
580 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
581 a95fd5d7 Guido Trotter
582 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
583 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
584 a95fd5d7 Guido Trotter

585 a95fd5d7 Guido Trotter
    """
586 84e344d4 Michael Hanselmann
    if shared:
587 84e344d4 Michael Hanselmann
      return self.__exc is None
588 84e344d4 Michael Hanselmann
    else:
589 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
590 a95fd5d7 Guido Trotter
591 887c7aa6 Michael Hanselmann
  def __find_first_pending_queue(self):
592 887c7aa6 Michael Hanselmann
    """Tries to find the topmost queued entry with pending acquires.
593 887c7aa6 Michael Hanselmann

594 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
595 887c7aa6 Michael Hanselmann

596 887c7aa6 Michael Hanselmann
    """
597 887c7aa6 Michael Hanselmann
    while self.__pending:
598 887c7aa6 Michael Hanselmann
      (priority, prioqueue) = self.__pending[0]
599 887c7aa6 Michael Hanselmann
600 887c7aa6 Michael Hanselmann
      if not prioqueue:
601 887c7aa6 Michael Hanselmann
        heapq.heappop(self.__pending)
602 887c7aa6 Michael Hanselmann
        del self.__pending_by_prio[priority]
603 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_shared
604 887c7aa6 Michael Hanselmann
        continue
605 887c7aa6 Michael Hanselmann
606 887c7aa6 Michael Hanselmann
      if prioqueue:
607 887c7aa6 Michael Hanselmann
        return prioqueue
608 887c7aa6 Michael Hanselmann
609 887c7aa6 Michael Hanselmann
    return None
610 887c7aa6 Michael Hanselmann
611 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
612 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
613 a95fd5d7 Guido Trotter

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

616 84e344d4 Michael Hanselmann
    """
617 887c7aa6 Michael Hanselmann
    return cond == self.__find_first_pending_queue()[0]
618 4d686df8 Guido Trotter
619 887c7aa6 Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout, priority):
620 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
621 9216a9f7 Michael Hanselmann

622 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
623 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
624 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
625 887c7aa6 Michael Hanselmann
    @type priority: integer
626 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
627 9216a9f7 Michael Hanselmann

628 9216a9f7 Michael Hanselmann
    """
629 84e344d4 Michael Hanselmann
    self.__check_deleted()
630 9216a9f7 Michael Hanselmann
631 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
632 7f93570a Iustin Pop
    assert not self.__is_owned(), ("double acquire() on a non-recursive lock"
633 7f93570a Iustin Pop
                                   " %s" % self.name)
634 84e344d4 Michael Hanselmann
635 887c7aa6 Michael Hanselmann
    # Remove empty entries from queue
636 887c7aa6 Michael Hanselmann
    self.__find_first_pending_queue()
637 887c7aa6 Michael Hanselmann
638 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
639 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
640 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
641 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
642 84e344d4 Michael Hanselmann
      return True
643 9216a9f7 Michael Hanselmann
644 887c7aa6 Michael Hanselmann
    prioqueue = self.__pending_by_prio.get(priority, None)
645 9216a9f7 Michael Hanselmann
646 887c7aa6 Michael Hanselmann
    if shared:
647 887c7aa6 Michael Hanselmann
      # Try to re-use condition for shared acquire
648 887c7aa6 Michael Hanselmann
      wait_condition = self.__pending_shared.get(priority, None)
649 887c7aa6 Michael Hanselmann
      assert (wait_condition is None or
650 887c7aa6 Michael Hanselmann
              (wait_condition.shared and wait_condition in prioqueue))
651 84e344d4 Michael Hanselmann
    else:
652 887c7aa6 Michael Hanselmann
      wait_condition = None
653 887c7aa6 Michael Hanselmann
654 887c7aa6 Michael Hanselmann
    if wait_condition is None:
655 887c7aa6 Michael Hanselmann
      if prioqueue is None:
656 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_by_prio
657 887c7aa6 Michael Hanselmann
658 887c7aa6 Michael Hanselmann
        prioqueue = []
659 887c7aa6 Michael Hanselmann
        heapq.heappush(self.__pending, (priority, prioqueue))
660 887c7aa6 Michael Hanselmann
        self.__pending_by_prio[priority] = prioqueue
661 887c7aa6 Michael Hanselmann
662 887c7aa6 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock, shared)
663 887c7aa6 Michael Hanselmann
      prioqueue.append(wait_condition)
664 887c7aa6 Michael Hanselmann
665 887c7aa6 Michael Hanselmann
      if shared:
666 887c7aa6 Michael Hanselmann
        # Keep reference for further shared acquires on same priority. This is
667 887c7aa6 Michael Hanselmann
        # better than trying to find it in the list of pending acquires.
668 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_shared
669 887c7aa6 Michael Hanselmann
        self.__pending_shared[priority] = wait_condition
670 84e344d4 Michael Hanselmann
671 84e344d4 Michael Hanselmann
    try:
672 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
673 84e344d4 Michael Hanselmann
      # expires.
674 887c7aa6 Michael Hanselmann
      # TODO: Decrease timeout with spurious notifications
675 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
676 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
677 84e344d4 Michael Hanselmann
        # Wait for notification
678 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
679 84e344d4 Michael Hanselmann
        self.__check_deleted()
680 84e344d4 Michael Hanselmann
681 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
682 84e344d4 Michael Hanselmann
        # internally for that case.
683 84e344d4 Michael Hanselmann
        if timeout is not None:
684 84e344d4 Michael Hanselmann
          break
685 84e344d4 Michael Hanselmann
686 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
687 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
688 84e344d4 Michael Hanselmann
        return True
689 9216a9f7 Michael Hanselmann
    finally:
690 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
691 887c7aa6 Michael Hanselmann
      if not wait_condition.has_waiting():
692 887c7aa6 Michael Hanselmann
        prioqueue.remove(wait_condition)
693 887c7aa6 Michael Hanselmann
        if wait_condition.shared:
694 887c7aa6 Michael Hanselmann
          del self.__pending_shared[priority]
695 9216a9f7 Michael Hanselmann
696 84e344d4 Michael Hanselmann
    return False
697 9216a9f7 Michael Hanselmann
698 7100c2fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, priority=None,
699 887c7aa6 Michael Hanselmann
              test_notify=None):
700 162c1c1f Guido Trotter
    """Acquire a shared lock.
701 162c1c1f Guido Trotter

702 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
703 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
704 c41eea6e Iustin Pop
        exclusive lock will be acquired
705 84e344d4 Michael Hanselmann
    @type timeout: float
706 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
707 887c7aa6 Michael Hanselmann
    @type priority: integer
708 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
709 008b92fa Michael Hanselmann
    @type test_notify: callable or None
710 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
711 162c1c1f Guido Trotter

712 162c1c1f Guido Trotter
    """
713 7100c2fa Michael Hanselmann
    if priority is None:
714 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
715 7100c2fa Michael Hanselmann
716 162c1c1f Guido Trotter
    self.__lock.acquire()
717 162c1c1f Guido Trotter
    try:
718 008b92fa Michael Hanselmann
      # We already got the lock, notify now
719 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
720 008b92fa Michael Hanselmann
        test_notify()
721 008b92fa Michael Hanselmann
722 887c7aa6 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout, priority)
723 162c1c1f Guido Trotter
    finally:
724 162c1c1f Guido Trotter
      self.__lock.release()
725 162c1c1f Guido Trotter
726 162c1c1f Guido Trotter
  def release(self):
727 162c1c1f Guido Trotter
    """Release a Shared Lock.
728 162c1c1f Guido Trotter

729 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
730 162c1c1f Guido Trotter
    before calling this function.
731 162c1c1f Guido Trotter

732 162c1c1f Guido Trotter
    """
733 162c1c1f Guido Trotter
    self.__lock.acquire()
734 162c1c1f Guido Trotter
    try:
735 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
736 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
737 84e344d4 Michael Hanselmann
738 162c1c1f Guido Trotter
      # Autodetect release type
739 162c1c1f Guido Trotter
      if self.__is_exclusive():
740 162c1c1f Guido Trotter
        self.__exc = None
741 84e344d4 Michael Hanselmann
      else:
742 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
743 162c1c1f Guido Trotter
744 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
745 887c7aa6 Michael Hanselmann
      prioqueue = self.__find_first_pending_queue()
746 887c7aa6 Michael Hanselmann
      if prioqueue:
747 887c7aa6 Michael Hanselmann
        prioqueue[0].notifyAll()
748 162c1c1f Guido Trotter
749 162c1c1f Guido Trotter
    finally:
750 162c1c1f Guido Trotter
      self.__lock.release()
751 162c1c1f Guido Trotter
752 7100c2fa Michael Hanselmann
  def delete(self, timeout=None, priority=None):
753 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
754 a95fd5d7 Guido Trotter

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

759 84e344d4 Michael Hanselmann
    @type timeout: float
760 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
761 887c7aa6 Michael Hanselmann
    @type priority: integer
762 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
763 a95fd5d7 Guido Trotter

764 a95fd5d7 Guido Trotter
    """
765 7100c2fa Michael Hanselmann
    if priority is None:
766 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
767 7100c2fa Michael Hanselmann
768 a95fd5d7 Guido Trotter
    self.__lock.acquire()
769 a95fd5d7 Guido Trotter
    try:
770 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
771 84e344d4 Michael Hanselmann
772 84e344d4 Michael Hanselmann
      self.__check_deleted()
773 a95fd5d7 Guido Trotter
774 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
775 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
776 a95fd5d7 Guido Trotter
777 84e344d4 Michael Hanselmann
      if not acquired:
778 887c7aa6 Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout, priority)
779 a66bd91b Michael Hanselmann
780 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
781 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
782 84e344d4 Michael Hanselmann
783 84e344d4 Michael Hanselmann
      if acquired:
784 84e344d4 Michael Hanselmann
        self.__deleted = True
785 84e344d4 Michael Hanselmann
        self.__exc = None
786 a95fd5d7 Guido Trotter
787 19b9ba9a Michael Hanselmann
        assert not (self.__exc or self.__shr), "Found owner during deletion"
788 19b9ba9a Michael Hanselmann
789 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
790 887c7aa6 Michael Hanselmann
        for (_, prioqueue) in self.__pending:
791 887c7aa6 Michael Hanselmann
          for cond in prioqueue:
792 887c7aa6 Michael Hanselmann
            cond.notifyAll()
793 887c7aa6 Michael Hanselmann
794 887c7aa6 Michael Hanselmann
        assert self.__deleted
795 a95fd5d7 Guido Trotter
796 84e344d4 Michael Hanselmann
      return acquired
797 a95fd5d7 Guido Trotter
    finally:
798 a95fd5d7 Guido Trotter
      self.__lock.release()
799 a95fd5d7 Guido Trotter
800 1a4e32d0 Guido Trotter
  def _release_save(self):
801 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
802 1a4e32d0 Guido Trotter
    self.release()
803 1a4e32d0 Guido Trotter
    return shared
804 1a4e32d0 Guido Trotter
805 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
806 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
807 1a4e32d0 Guido Trotter
808 aaae9bc0 Guido Trotter
809 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
810 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
811 e310b019 Guido Trotter
ALL_SET = None
812 e310b019 Guido Trotter
813 e310b019 Guido Trotter
814 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
815 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
816 5aab242c Michael Hanselmann

817 5aab242c Michael Hanselmann
  """
818 5aab242c Michael Hanselmann
819 5aab242c Michael Hanselmann
820 aaae9bc0 Guido Trotter
class LockSet:
821 aaae9bc0 Guido Trotter
  """Implements a set of locks.
822 aaae9bc0 Guido Trotter

823 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
824 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
825 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
826 aaae9bc0 Guido Trotter
  preventing deadlock.
827 aaae9bc0 Guido Trotter

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

830 7f93570a Iustin Pop
  @type name: string
831 7f93570a Iustin Pop
  @ivar name: the name of the lockset
832 7f93570a Iustin Pop

833 aaae9bc0 Guido Trotter
  """
834 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
835 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
836 aaae9bc0 Guido Trotter

837 ec44d893 Guido Trotter
    @type members: list of strings
838 c41eea6e Iustin Pop
    @param members: initial members of the set
839 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
840 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
841 aaae9bc0 Guido Trotter

842 aaae9bc0 Guido Trotter
    """
843 7f93570a Iustin Pop
    assert members is not None, "members parameter is not a list"
844 7f93570a Iustin Pop
    self.name = name
845 7f93570a Iustin Pop
846 19b9ba9a Michael Hanselmann
    # Lock monitor
847 19b9ba9a Michael Hanselmann
    self.__monitor = monitor
848 19b9ba9a Michael Hanselmann
849 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
850 7f93570a Iustin Pop
    self.__lock = SharedLock(name)
851 aaae9bc0 Guido Trotter
852 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
853 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
854 aaae9bc0 Guido Trotter
    self.__lockdict = {}
855 aaae9bc0 Guido Trotter
856 7f93570a Iustin Pop
    for mname in members:
857 19b9ba9a Michael Hanselmann
      self.__lockdict[mname] = SharedLock(self._GetLockName(mname),
858 19b9ba9a Michael Hanselmann
                                          monitor=monitor)
859 aaae9bc0 Guido Trotter
860 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
861 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
862 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
863 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
864 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
865 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
866 aaae9bc0 Guido Trotter
    # will be trouble.
867 aaae9bc0 Guido Trotter
    self.__owners = {}
868 aaae9bc0 Guido Trotter
869 4fb780d1 Michael Hanselmann
  def _GetLockName(self, mname):
870 4fb780d1 Michael Hanselmann
    """Returns the name for a member lock.
871 4fb780d1 Michael Hanselmann

872 4fb780d1 Michael Hanselmann
    """
873 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
874 4fb780d1 Michael Hanselmann
875 aaae9bc0 Guido Trotter
  def _is_owned(self):
876 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
877 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
878 aaae9bc0 Guido Trotter
879 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
880 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
881 b2dabfd6 Guido Trotter
    if name is None:
882 b2dabfd6 Guido Trotter
      if not self._is_owned():
883 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
884 aaae9bc0 Guido Trotter
    else:
885 b2dabfd6 Guido Trotter
      if self._is_owned():
886 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
887 b2dabfd6 Guido Trotter
      else:
888 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
889 b2dabfd6 Guido Trotter
890 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
891 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
892 aaae9bc0 Guido Trotter
893 e4335b5b Michael Hanselmann
    assert not (name is None and self.__lock._is_owned()), \
894 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
895 e4335b5b Michael Hanselmann
896 b2dabfd6 Guido Trotter
    if name is not None:
897 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
898 b2dabfd6 Guido Trotter
899 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
900 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
901 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
902 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
903 aaae9bc0 Guido Trotter
904 aaae9bc0 Guido Trotter
  def _list_owned(self):
905 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
906 aaae9bc0 Guido Trotter
    if self._is_owned():
907 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
908 aaae9bc0 Guido Trotter
    else:
909 aaae9bc0 Guido Trotter
      return set()
910 aaae9bc0 Guido Trotter
911 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
912 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
913 5aab242c Michael Hanselmann
    for lname in self._list_owned():
914 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
915 56452af7 Michael Hanselmann
      if lock._is_owned():
916 56452af7 Michael Hanselmann
        lock.release()
917 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
918 5aab242c Michael Hanselmann
919 aaae9bc0 Guido Trotter
  def __names(self):
920 aaae9bc0 Guido Trotter
    """Return the current set of names.
921 aaae9bc0 Guido Trotter

922 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
923 aaae9bc0 Guido Trotter
    result after releasing the lock.
924 aaae9bc0 Guido Trotter

925 aaae9bc0 Guido Trotter
    """
926 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
927 aaae9bc0 Guido Trotter
928 aaae9bc0 Guido Trotter
  def _names(self):
929 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
930 aaae9bc0 Guido Trotter

931 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
932 cdb08f44 Michael Hanselmann

933 aaae9bc0 Guido Trotter
    """
934 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
935 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
936 d4803c24 Guido Trotter
    release_lock = False
937 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
938 d4803c24 Guido Trotter
      release_lock = True
939 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
940 aaae9bc0 Guido Trotter
    try:
941 aaae9bc0 Guido Trotter
      result = self.__names()
942 aaae9bc0 Guido Trotter
    finally:
943 d4803c24 Guido Trotter
      if release_lock:
944 d4803c24 Guido Trotter
        self.__lock.release()
945 0cf257c5 Guido Trotter
    return set(result)
946 aaae9bc0 Guido Trotter
947 7100c2fa Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, priority=None,
948 887c7aa6 Michael Hanselmann
              test_notify=None):
949 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
950 aaae9bc0 Guido Trotter

951 ec44d893 Guido Trotter
    @type names: list of strings (or string)
952 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
953 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
954 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
955 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
956 c41eea6e Iustin Pop
        exclusive lock will be acquired
957 5aab242c Michael Hanselmann
    @type timeout: float or None
958 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
959 887c7aa6 Michael Hanselmann
    @type priority: integer
960 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
961 5aab242c Michael Hanselmann
    @type test_notify: callable or None
962 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
963 aaae9bc0 Guido Trotter

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

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

970 aaae9bc0 Guido Trotter
    """
971 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
972 aaae9bc0 Guido Trotter
973 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
974 7f93570a Iustin Pop
    assert not self._is_owned(), ("Cannot acquire locks in the same set twice"
975 7f93570a Iustin Pop
                                  " (lockset %s)" % self.name)
976 aaae9bc0 Guido Trotter
977 7100c2fa Michael Hanselmann
    if priority is None:
978 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
979 7100c2fa Michael Hanselmann
980 5aab242c Michael Hanselmann
    # We need to keep track of how long we spent waiting for a lock. The
981 5aab242c Michael Hanselmann
    # timeout passed to this function is over all lock acquires.
982 557838c1 Renรฉ Nussbaumer
    running_timeout = utils.RunningTimeout(timeout, False)
983 5aab242c Michael Hanselmann
984 806e20fd Guido Trotter
    try:
985 76e2f08a Michael Hanselmann
      if names is not None:
986 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
987 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
988 5aab242c Michael Hanselmann
          names = [names]
989 5aab242c Michael Hanselmann
990 887c7aa6 Michael Hanselmann
        return self.__acquire_inner(names, False, shared, priority,
991 7e8841bd Michael Hanselmann
                                    running_timeout.Remaining, test_notify)
992 76e2f08a Michael Hanselmann
993 76e2f08a Michael Hanselmann
      else:
994 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
995 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
996 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
997 76e2f08a Michael Hanselmann
        #
998 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
999 887c7aa6 Michael Hanselmann
        # everybody else can use the instances at the same time. If we are
1000 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
1001 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
1002 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
1003 887c7aa6 Michael Hanselmann
        if not self.__lock.acquire(shared=shared, priority=priority,
1004 7e8841bd Michael Hanselmann
                                   timeout=running_timeout.Remaining()):
1005 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1006 76e2f08a Michael Hanselmann
        try:
1007 76e2f08a Michael Hanselmann
          # note we own the set-lock
1008 76e2f08a Michael Hanselmann
          self._add_owned()
1009 76e2f08a Michael Hanselmann
1010 887c7aa6 Michael Hanselmann
          return self.__acquire_inner(self.__names(), True, shared, priority,
1011 7e8841bd Michael Hanselmann
                                      running_timeout.Remaining, test_notify)
1012 76e2f08a Michael Hanselmann
        except:
1013 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1014 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1015 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
1016 5aab242c Michael Hanselmann
          self.__lock.release()
1017 76e2f08a Michael Hanselmann
          self._del_owned()
1018 76e2f08a Michael Hanselmann
          raise
1019 5aab242c Michael Hanselmann
1020 5aab242c Michael Hanselmann
    except _AcquireTimeout:
1021 5aab242c Michael Hanselmann
      return None
1022 aaae9bc0 Guido Trotter
1023 887c7aa6 Michael Hanselmann
  def __acquire_inner(self, names, want_all, shared, priority,
1024 887c7aa6 Michael Hanselmann
                      timeout_fn, test_notify):
1025 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
1026 7e8841bd Michael Hanselmann

1027 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
1028 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
1029 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
1030 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
1031 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1032 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1033 76e2f08a Michael Hanselmann

1034 76e2f08a Michael Hanselmann
    """
1035 76e2f08a Michael Hanselmann
    acquire_list = []
1036 76e2f08a Michael Hanselmann
1037 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
1038 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
1039 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
1040 71e1863e Michael Hanselmann
    # deadlocks.
1041 71e1863e Michael Hanselmann
    for lname in sorted(utils.UniqueSequence(names)):
1042 76e2f08a Michael Hanselmann
      try:
1043 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
1044 76e2f08a Michael Hanselmann
      except KeyError:
1045 76e2f08a Michael Hanselmann
        if want_all:
1046 76e2f08a Michael Hanselmann
          # We are acquiring all the set, it doesn't matter if this particular
1047 76e2f08a Michael Hanselmann
          # element is not there anymore.
1048 76e2f08a Michael Hanselmann
          continue
1049 76e2f08a Michael Hanselmann
1050 e1137eb6 Michael Hanselmann
        raise errors.LockError("Non-existing lock %s in set %s (it may have"
1051 e1137eb6 Michael Hanselmann
                               " been removed)" % (lname, self.name))
1052 76e2f08a Michael Hanselmann
1053 9b154270 Michael Hanselmann
      acquire_list.append((lname, lock))
1054 9b154270 Michael Hanselmann
1055 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
1056 76e2f08a Michael Hanselmann
    acquired = set()
1057 76e2f08a Michael Hanselmann
1058 76e2f08a Michael Hanselmann
    try:
1059 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
1060 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
1061 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
1062 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
1063 76e2f08a Michael Hanselmann
      # lock gets deleted.
1064 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
1065 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
1066 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
1067 76e2f08a Michael Hanselmann
        else:
1068 76e2f08a Michael Hanselmann
          test_notify_fn = None
1069 76e2f08a Michael Hanselmann
1070 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
1071 76e2f08a Michael Hanselmann
1072 76e2f08a Michael Hanselmann
        try:
1073 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
1074 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
1075 887c7aa6 Michael Hanselmann
                                     priority=priority,
1076 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
1077 76e2f08a Michael Hanselmann
        except errors.LockError:
1078 76e2f08a Michael Hanselmann
          if want_all:
1079 76e2f08a Michael Hanselmann
            # We are acquiring all the set, it doesn't matter if this
1080 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
1081 76e2f08a Michael Hanselmann
            continue
1082 76e2f08a Michael Hanselmann
1083 e1137eb6 Michael Hanselmann
          raise errors.LockError("Non-existing lock %s in set %s (it may"
1084 e1137eb6 Michael Hanselmann
                                 " have been removed)" % (lname, self.name))
1085 76e2f08a Michael Hanselmann
1086 76e2f08a Michael Hanselmann
        if not acq_success:
1087 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
1088 76e2f08a Michael Hanselmann
          if timeout is None:
1089 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
1090 76e2f08a Michael Hanselmann
            # blocking.
1091 7f93570a Iustin Pop
            raise errors.LockError("Failed to get lock %s (set %s)" %
1092 7f93570a Iustin Pop
                                   (lname, self.name))
1093 76e2f08a Michael Hanselmann
1094 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1095 76e2f08a Michael Hanselmann
1096 76e2f08a Michael Hanselmann
        try:
1097 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
1098 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
1099 76e2f08a Michael Hanselmann
          acquired.add(lname)
1100 76e2f08a Michael Hanselmann
1101 76e2f08a Michael Hanselmann
        except:
1102 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1103 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1104 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
1105 76e2f08a Michael Hanselmann
          if lock._is_owned():
1106 76e2f08a Michael Hanselmann
            lock.release()
1107 76e2f08a Michael Hanselmann
          raise
1108 76e2f08a Michael Hanselmann
1109 76e2f08a Michael Hanselmann
    except:
1110 76e2f08a Michael Hanselmann
      # Release all owned locks
1111 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
1112 76e2f08a Michael Hanselmann
      raise
1113 76e2f08a Michael Hanselmann
1114 0cc00929 Guido Trotter
    return acquired
1115 aaae9bc0 Guido Trotter
1116 aaae9bc0 Guido Trotter
  def release(self, names=None):
1117 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
1118 aaae9bc0 Guido Trotter

1119 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1120 aaae9bc0 Guido Trotter
    before releasing them.
1121 aaae9bc0 Guido Trotter

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

1126 aaae9bc0 Guido Trotter
    """
1127 7f93570a Iustin Pop
    assert self._is_owned(), ("release() on lock set %s while not owner" %
1128 7f93570a Iustin Pop
                              self.name)
1129 aaae9bc0 Guido Trotter
1130 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1131 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1132 aaae9bc0 Guido Trotter
      names = [names]
1133 aaae9bc0 Guido Trotter
1134 aaae9bc0 Guido Trotter
    if names is None:
1135 aaae9bc0 Guido Trotter
      names = self._list_owned()
1136 aaae9bc0 Guido Trotter
    else:
1137 aaae9bc0 Guido Trotter
      names = set(names)
1138 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
1139 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1140 7f93570a Iustin Pop
               (names.difference(self._list_owned()), self.name))
1141 aaae9bc0 Guido Trotter
1142 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1143 3b7ed473 Guido Trotter
    # After this 'add' can work again
1144 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
1145 3b7ed473 Guido Trotter
      self.__lock.release()
1146 b2dabfd6 Guido Trotter
      self._del_owned()
1147 3b7ed473 Guido Trotter
1148 aaae9bc0 Guido Trotter
    for lockname in names:
1149 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1150 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1151 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1152 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1153 aaae9bc0 Guido Trotter
1154 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1155 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1156 aaae9bc0 Guido Trotter

1157 ec44d893 Guido Trotter
    @type names: list of strings
1158 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1159 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1160 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1161 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1162 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1163 aaae9bc0 Guido Trotter

1164 aaae9bc0 Guido Trotter
    """
1165 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1166 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
1167 7f93570a Iustin Pop
      ("Cannot add locks if the set %s is only partially owned, or shared" %
1168 7f93570a Iustin Pop
       self.name)
1169 3b7ed473 Guido Trotter
1170 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1171 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1172 aaae9bc0 Guido Trotter
      names = [names]
1173 aaae9bc0 Guido Trotter
1174 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1175 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1176 3b7ed473 Guido Trotter
    release_lock = False
1177 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
1178 3b7ed473 Guido Trotter
      release_lock = True
1179 3b7ed473 Guido Trotter
      self.__lock.acquire()
1180 3b7ed473 Guido Trotter
1181 aaae9bc0 Guido Trotter
    try:
1182 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1183 aaae9bc0 Guido Trotter
      if invalid_names:
1184 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1185 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1186 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1187 7f93570a Iustin Pop
        raise errors.LockError("duplicate add(%s) on lockset %s" %
1188 7f93570a Iustin Pop
                               (invalid_names, self.name))
1189 aaae9bc0 Guido Trotter
1190 aaae9bc0 Guido Trotter
      for lockname in names:
1191 19b9ba9a Michael Hanselmann
        lock = SharedLock(self._GetLockName(lockname), monitor=self.__monitor)
1192 aaae9bc0 Guido Trotter
1193 aaae9bc0 Guido Trotter
        if acquired:
1194 887c7aa6 Michael Hanselmann
          # No need for priority or timeout here as this lock has just been
1195 887c7aa6 Michael Hanselmann
          # created
1196 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1197 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1198 aaae9bc0 Guido Trotter
          try:
1199 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1200 aaae9bc0 Guido Trotter
          except:
1201 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1202 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1203 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1204 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1205 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1206 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1207 aaae9bc0 Guido Trotter
            lock.release()
1208 aaae9bc0 Guido Trotter
            raise
1209 aaae9bc0 Guido Trotter
1210 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1211 aaae9bc0 Guido Trotter
1212 aaae9bc0 Guido Trotter
    finally:
1213 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1214 3b7ed473 Guido Trotter
      if release_lock:
1215 3b7ed473 Guido Trotter
        self.__lock.release()
1216 aaae9bc0 Guido Trotter
1217 aaae9bc0 Guido Trotter
    return True
1218 aaae9bc0 Guido Trotter
1219 5e0a6daf Michael Hanselmann
  def remove(self, names):
1220 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1221 aaae9bc0 Guido Trotter

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

1225 ec44d893 Guido Trotter
    @type names: list of strings
1226 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1227 aaae9bc0 Guido Trotter

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

1232 aaae9bc0 Guido Trotter
    """
1233 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1234 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1235 aaae9bc0 Guido Trotter
      names = [names]
1236 aaae9bc0 Guido Trotter
1237 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1238 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1239 aaae9bc0 Guido Trotter
    # by the lock itself.
1240 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
1241 7f93570a Iustin Pop
      "remove() on acquired lockset %s while not owning all elements" %
1242 7f93570a Iustin Pop
      self.name)
1243 aaae9bc0 Guido Trotter
1244 3f404fc5 Guido Trotter
    removed = []
1245 aaae9bc0 Guido Trotter
1246 aaae9bc0 Guido Trotter
    for lname in names:
1247 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1248 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1249 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1250 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1251 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1252 aaae9bc0 Guido Trotter
      try:
1253 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1254 3f404fc5 Guido Trotter
        removed.append(lname)
1255 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1256 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1257 7f93570a Iustin Pop
        assert not self._is_owned(), ("remove failed while holding lockset %s"
1258 7f93570a Iustin Pop
                                      % self.name)
1259 aaae9bc0 Guido Trotter
      else:
1260 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1261 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1262 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1263 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1264 aaae9bc0 Guido Trotter
        #
1265 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1266 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1267 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1268 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1269 aaae9bc0 Guido Trotter
        if self._is_owned():
1270 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1271 aaae9bc0 Guido Trotter
1272 3f404fc5 Guido Trotter
    return removed
1273 aaae9bc0 Guido Trotter
1274 7ee7c0c7 Guido Trotter
1275 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1276 7ee7c0c7 Guido Trotter
# Current rules are:
1277 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1278 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1279 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1280 7ee7c0c7 Guido Trotter
#   avoided.
1281 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1282 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1283 7ee7c0c7 Guido Trotter
#   the same time.
1284 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1285 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1286 819ca990 Guido Trotter
LEVEL_NODEGROUP = 2
1287 819ca990 Guido Trotter
LEVEL_NODE = 3
1288 7ee7c0c7 Guido Trotter
1289 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1290 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1291 819ca990 Guido Trotter
          LEVEL_NODEGROUP,
1292 04e1bfaf Guido Trotter
          LEVEL_NODE]
1293 7ee7c0c7 Guido Trotter
1294 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1295 819ca990 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_NODEGROUP, LEVEL_INSTANCE]
1296 7ee7c0c7 Guido Trotter
1297 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1298 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1299 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1300 819ca990 Guido Trotter
  LEVEL_NODEGROUP: "nodegroup",
1301 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1302 ea205dbc Michael Hanselmann
  }
1303 ea205dbc Michael Hanselmann
1304 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1305 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1306 7ee7c0c7 Guido Trotter
1307 7ee7c0c7 Guido Trotter
1308 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1309 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1310 7ee7c0c7 Guido Trotter

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

1316 7ee7c0c7 Guido Trotter
  """
1317 7ee7c0c7 Guido Trotter
  _instance = None
1318 7ee7c0c7 Guido Trotter
1319 819ca990 Guido Trotter
  def __init__(self, nodes, nodegroups, instances):
1320 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1321 7ee7c0c7 Guido Trotter

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

1325 c41eea6e Iustin Pop
    @param nodes: list of node names
1326 819ca990 Guido Trotter
    @param nodegroups: list of nodegroup uuids
1327 c41eea6e Iustin Pop
    @param instances: list of instance names
1328 7ee7c0c7 Guido Trotter

1329 7ee7c0c7 Guido Trotter
    """
1330 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1331 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1332 c41eea6e Iustin Pop
1333 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1334 7ee7c0c7 Guido Trotter
1335 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1336 19b9ba9a Michael Hanselmann
1337 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1338 7ee7c0c7 Guido Trotter
    # locking order.
1339 7ee7c0c7 Guido Trotter
    self.__keyring = {
1340 19b9ba9a Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "BGL", monitor=self._monitor),
1341 19b9ba9a Michael Hanselmann
      LEVEL_NODE: LockSet(nodes, "nodes", monitor=self._monitor),
1342 819ca990 Guido Trotter
      LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroups", monitor=self._monitor),
1343 19b9ba9a Michael Hanselmann
      LEVEL_INSTANCE: LockSet(instances, "instances",
1344 19b9ba9a Michael Hanselmann
                              monitor=self._monitor),
1345 19b9ba9a Michael Hanselmann
      }
1346 19b9ba9a Michael Hanselmann
1347 19b9ba9a Michael Hanselmann
  def QueryLocks(self, fields, sync):
1348 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1349 19b9ba9a Michael Hanselmann

1350 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1351 19b9ba9a Michael Hanselmann

1352 19b9ba9a Michael Hanselmann
    """
1353 19b9ba9a Michael Hanselmann
    return self._monitor.QueryLocks(fields, sync)
1354 7ee7c0c7 Guido Trotter
1355 7ee7c0c7 Guido Trotter
  def _names(self, level):
1356 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1357 7ee7c0c7 Guido Trotter

1358 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1359 c41eea6e Iustin Pop

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

1362 7ee7c0c7 Guido Trotter
    """
1363 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1364 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1365 7ee7c0c7 Guido Trotter
1366 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1367 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1368 7ee7c0c7 Guido Trotter

1369 7ee7c0c7 Guido Trotter
    """
1370 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1371 7ee7c0c7 Guido Trotter
1372 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1373 d4f4b3e7 Guido Trotter
1374 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1375 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1376 7ee7c0c7 Guido Trotter

1377 7ee7c0c7 Guido Trotter
    """
1378 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1379 7ee7c0c7 Guido Trotter
1380 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1381 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1382 7ee7c0c7 Guido Trotter

1383 7ee7c0c7 Guido Trotter
    """
1384 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1385 7ee7c0c7 Guido Trotter
    # the test cases.
1386 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1387 7ee7c0c7 Guido Trotter
1388 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1389 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1390 7ee7c0c7 Guido Trotter

1391 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1392 7ee7c0c7 Guido Trotter

1393 7ee7c0c7 Guido Trotter
    """
1394 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1395 7ee7c0c7 Guido Trotter
1396 c70d2d9b Iustin Pop
  @staticmethod
1397 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1398 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1399 c41eea6e Iustin Pop

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

1403 7ee7c0c7 Guido Trotter
    """
1404 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1405 7ee7c0c7 Guido Trotter
1406 b30d95b6 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None):
1407 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1408 7ee7c0c7 Guido Trotter

1409 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1410 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1411 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1412 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1413 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1414 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1415 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1416 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1417 5e0a6daf Michael Hanselmann
    @type timeout: float
1418 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1419 b30d95b6 Michael Hanselmann
    @type priority: integer
1420 b30d95b6 Michael Hanselmann
    @param priority: Priority for acquiring lock
1421 7ee7c0c7 Guido Trotter

1422 7ee7c0c7 Guido Trotter
    """
1423 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1424 7ee7c0c7 Guido Trotter
1425 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1426 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1427 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1428 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1429 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1430 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1431 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1432 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1433 7ee7c0c7 Guido Trotter
1434 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1435 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1436 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1437 7ee7c0c7 Guido Trotter
1438 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1439 b30d95b6 Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout,
1440 b30d95b6 Michael Hanselmann
                                         priority=priority)
1441 7ee7c0c7 Guido Trotter
1442 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1443 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1444 7ee7c0c7 Guido Trotter

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

1448 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1449 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1450 ec44d893 Guido Trotter
    @type names: list of strings, or None
1451 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1452 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1453 7ee7c0c7 Guido Trotter

1454 7ee7c0c7 Guido Trotter
    """
1455 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1456 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1457 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1458 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1459 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1460 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1461 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1462 7ee7c0c7 Guido Trotter
1463 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1464 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1465 7ee7c0c7 Guido Trotter
1466 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1467 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1468 7ee7c0c7 Guido Trotter

1469 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1470 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1471 ec44d893 Guido Trotter
    @type names: list of strings
1472 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1473 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1474 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1475 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1476 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1477 c41eea6e Iustin Pop

1478 7ee7c0c7 Guido Trotter
    """
1479 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1480 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1481 7ee7c0c7 Guido Trotter
           " operations")
1482 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1483 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1484 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1485 7ee7c0c7 Guido Trotter
1486 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1487 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1488 7ee7c0c7 Guido Trotter

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

1492 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1493 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1494 ec44d893 Guido Trotter
    @type names: list of strings
1495 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1496 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1497 7ee7c0c7 Guido Trotter

1498 7ee7c0c7 Guido Trotter
    """
1499 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1500 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1501 7ee7c0c7 Guido Trotter
           " operations")
1502 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1503 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1504 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1505 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1506 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1507 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1508 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1509 19b9ba9a Michael Hanselmann
1510 19b9ba9a Michael Hanselmann
1511 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1512 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1513 19b9ba9a Michael Hanselmann
1514 19b9ba9a Michael Hanselmann
  def __init__(self):
1515 19b9ba9a Michael Hanselmann
    """Initializes this class.
1516 19b9ba9a Michael Hanselmann

1517 19b9ba9a Michael Hanselmann
    """
1518 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1519 19b9ba9a Michael Hanselmann
1520 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1521 19b9ba9a Michael Hanselmann
    # references and deletion.
1522 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1523 19b9ba9a Michael Hanselmann
1524 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1525 19b9ba9a Michael Hanselmann
  def RegisterLock(self, lock):
1526 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1527 19b9ba9a Michael Hanselmann

1528 19b9ba9a Michael Hanselmann
    """
1529 19b9ba9a Michael Hanselmann
    logging.debug("Registering lock %s", lock.name)
1530 19b9ba9a Michael Hanselmann
    assert lock not in self._locks, "Duplicate lock registration"
1531 19b9ba9a Michael Hanselmann
    assert not compat.any(lock.name == i.name for i in self._locks.keys()), \
1532 19b9ba9a Michael Hanselmann
           "Found duplicate lock name"
1533 19b9ba9a Michael Hanselmann
    self._locks[lock] = None
1534 19b9ba9a Michael Hanselmann
1535 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1536 19b9ba9a Michael Hanselmann
  def _GetLockInfo(self, fields):
1537 19b9ba9a Michael Hanselmann
    """Get information from all locks while the monitor lock is held.
1538 19b9ba9a Michael Hanselmann

1539 19b9ba9a Michael Hanselmann
    """
1540 19b9ba9a Michael Hanselmann
    result = {}
1541 19b9ba9a Michael Hanselmann
1542 19b9ba9a Michael Hanselmann
    for lock in self._locks.keys():
1543 19b9ba9a Michael Hanselmann
      assert lock.name not in result, "Found duplicate lock name"
1544 19b9ba9a Michael Hanselmann
      result[lock.name] = lock.GetInfo(fields)
1545 19b9ba9a Michael Hanselmann
1546 19b9ba9a Michael Hanselmann
    return result
1547 19b9ba9a Michael Hanselmann
1548 19b9ba9a Michael Hanselmann
  def QueryLocks(self, fields, sync):
1549 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1550 19b9ba9a Michael Hanselmann

1551 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1552 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1553 19b9ba9a Michael Hanselmann
    @type sync: boolean
1554 19b9ba9a Michael Hanselmann
    @param sync: Whether to operate in synchronous mode
1555 19b9ba9a Michael Hanselmann

1556 19b9ba9a Michael Hanselmann
    """
1557 19b9ba9a Michael Hanselmann
    if sync:
1558 19b9ba9a Michael Hanselmann
      raise NotImplementedError("Synchronous queries are not implemented")
1559 19b9ba9a Michael Hanselmann
1560 19b9ba9a Michael Hanselmann
    # Get all data without sorting
1561 19b9ba9a Michael Hanselmann
    result = self._GetLockInfo(fields)
1562 19b9ba9a Michael Hanselmann
1563 19b9ba9a Michael Hanselmann
    # Sort by name
1564 19b9ba9a Michael Hanselmann
    return [result[name] for name in utils.NiceSort(result.keys())]