Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 6915fe26

History | View | Annotate | Download (53.5 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

389 7f93570a Iustin Pop
  @type name: string
390 7f93570a Iustin Pop
  @ivar name: the name of the lock
391 7f93570a Iustin Pop

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

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

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

442 24d16f76 Michael Hanselmann
    @type requested: set
443 24d16f76 Michael Hanselmann
    @param requested: Requested information, see C{query.LQ_*}
444 19b9ba9a Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

597 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
598 887c7aa6 Michael Hanselmann

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

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

618 84e344d4 Michael Hanselmann
    """
619 113359fe Michael Hanselmann
    (_, prioqueue) = self.__find_first_pending_queue()
620 113359fe Michael Hanselmann
621 113359fe Michael Hanselmann
    return cond == prioqueue[0]
622 4d686df8 Guido Trotter
623 887c7aa6 Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout, priority):
624 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
625 9216a9f7 Michael Hanselmann

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

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

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

718 162c1c1f Guido Trotter
    """
719 7100c2fa Michael Hanselmann
    if priority is None:
720 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
721 7100c2fa Michael Hanselmann
722 162c1c1f Guido Trotter
    self.__lock.acquire()
723 162c1c1f Guido Trotter
    try:
724 008b92fa Michael Hanselmann
      # We already got the lock, notify now
725 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
726 008b92fa Michael Hanselmann
        test_notify()
727 008b92fa Michael Hanselmann
728 887c7aa6 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout, priority)
729 162c1c1f Guido Trotter
    finally:
730 162c1c1f Guido Trotter
      self.__lock.release()
731 162c1c1f Guido Trotter
732 3dbe3ddf Michael Hanselmann
  def downgrade(self):
733 3dbe3ddf Michael Hanselmann
    """Changes the lock mode from exclusive to shared.
734 3dbe3ddf Michael Hanselmann

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

737 3dbe3ddf Michael Hanselmann
    """
738 3dbe3ddf Michael Hanselmann
    self.__lock.acquire()
739 3dbe3ddf Michael Hanselmann
    try:
740 3dbe3ddf Michael Hanselmann
      assert self.__is_owned(), "Lock must be owned"
741 3dbe3ddf Michael Hanselmann
742 3dbe3ddf Michael Hanselmann
      if self.__is_exclusive():
743 3dbe3ddf Michael Hanselmann
        # Do nothing if the lock is already acquired in shared mode
744 3dbe3ddf Michael Hanselmann
        self.__exc = None
745 3dbe3ddf Michael Hanselmann
        self.__do_acquire(1)
746 3dbe3ddf Michael Hanselmann
747 3dbe3ddf Michael Hanselmann
        # Important: pending shared acquires should only jump ahead if there
748 3dbe3ddf Michael Hanselmann
        # was a transition from exclusive to shared, otherwise an owner of a
749 3dbe3ddf Michael Hanselmann
        # shared lock can keep calling this function to push incoming shared
750 3dbe3ddf Michael Hanselmann
        # acquires
751 3dbe3ddf Michael Hanselmann
        (priority, prioqueue) = self.__find_first_pending_queue()
752 3dbe3ddf Michael Hanselmann
        if prioqueue:
753 3dbe3ddf Michael Hanselmann
          # Is there a pending shared acquire on this priority?
754 3dbe3ddf Michael Hanselmann
          cond = self.__pending_shared.pop(priority, None)
755 3dbe3ddf Michael Hanselmann
          if cond:
756 3dbe3ddf Michael Hanselmann
            assert cond.shared
757 3dbe3ddf Michael Hanselmann
            assert cond in prioqueue
758 3dbe3ddf Michael Hanselmann
759 3dbe3ddf Michael Hanselmann
            # Ensure shared acquire is on top of queue
760 3dbe3ddf Michael Hanselmann
            if len(prioqueue) > 1:
761 3dbe3ddf Michael Hanselmann
              prioqueue.remove(cond)
762 3dbe3ddf Michael Hanselmann
              prioqueue.insert(0, cond)
763 3dbe3ddf Michael Hanselmann
764 3dbe3ddf Michael Hanselmann
            # Notify
765 3dbe3ddf Michael Hanselmann
            cond.notifyAll()
766 3dbe3ddf Michael Hanselmann
767 3dbe3ddf Michael Hanselmann
      assert not self.__is_exclusive()
768 3dbe3ddf Michael Hanselmann
      assert self.__is_sharer()
769 3dbe3ddf Michael Hanselmann
770 3dbe3ddf Michael Hanselmann
      return True
771 3dbe3ddf Michael Hanselmann
    finally:
772 3dbe3ddf Michael Hanselmann
      self.__lock.release()
773 3dbe3ddf Michael Hanselmann
774 162c1c1f Guido Trotter
  def release(self):
775 162c1c1f Guido Trotter
    """Release a Shared Lock.
776 162c1c1f Guido Trotter

777 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
778 162c1c1f Guido Trotter
    before calling this function.
779 162c1c1f Guido Trotter

780 162c1c1f Guido Trotter
    """
781 162c1c1f Guido Trotter
    self.__lock.acquire()
782 162c1c1f Guido Trotter
    try:
783 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
784 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
785 84e344d4 Michael Hanselmann
786 162c1c1f Guido Trotter
      # Autodetect release type
787 162c1c1f Guido Trotter
      if self.__is_exclusive():
788 162c1c1f Guido Trotter
        self.__exc = None
789 84e344d4 Michael Hanselmann
      else:
790 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
791 162c1c1f Guido Trotter
792 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
793 113359fe Michael Hanselmann
      (priority, prioqueue) = self.__find_first_pending_queue()
794 887c7aa6 Michael Hanselmann
      if prioqueue:
795 113359fe Michael Hanselmann
        cond = prioqueue[0]
796 113359fe Michael Hanselmann
        cond.notifyAll()
797 113359fe Michael Hanselmann
        if cond.shared:
798 113359fe Michael Hanselmann
          # Prevent further shared acquires from sneaking in while waiters are
799 113359fe Michael Hanselmann
          # notified
800 113359fe Michael Hanselmann
          self.__pending_shared.pop(priority, None)
801 162c1c1f Guido Trotter
802 162c1c1f Guido Trotter
    finally:
803 162c1c1f Guido Trotter
      self.__lock.release()
804 162c1c1f Guido Trotter
805 7100c2fa Michael Hanselmann
  def delete(self, timeout=None, priority=None):
806 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
807 a95fd5d7 Guido Trotter

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

812 84e344d4 Michael Hanselmann
    @type timeout: float
813 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
814 887c7aa6 Michael Hanselmann
    @type priority: integer
815 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
816 a95fd5d7 Guido Trotter

817 a95fd5d7 Guido Trotter
    """
818 7100c2fa Michael Hanselmann
    if priority is None:
819 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
820 7100c2fa Michael Hanselmann
821 a95fd5d7 Guido Trotter
    self.__lock.acquire()
822 a95fd5d7 Guido Trotter
    try:
823 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
824 84e344d4 Michael Hanselmann
825 84e344d4 Michael Hanselmann
      self.__check_deleted()
826 a95fd5d7 Guido Trotter
827 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
828 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
829 a95fd5d7 Guido Trotter
830 84e344d4 Michael Hanselmann
      if not acquired:
831 887c7aa6 Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout, priority)
832 a66bd91b Michael Hanselmann
833 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
834 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
835 84e344d4 Michael Hanselmann
836 84e344d4 Michael Hanselmann
      if acquired:
837 84e344d4 Michael Hanselmann
        self.__deleted = True
838 84e344d4 Michael Hanselmann
        self.__exc = None
839 a95fd5d7 Guido Trotter
840 19b9ba9a Michael Hanselmann
        assert not (self.__exc or self.__shr), "Found owner during deletion"
841 19b9ba9a Michael Hanselmann
842 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
843 887c7aa6 Michael Hanselmann
        for (_, prioqueue) in self.__pending:
844 887c7aa6 Michael Hanselmann
          for cond in prioqueue:
845 887c7aa6 Michael Hanselmann
            cond.notifyAll()
846 887c7aa6 Michael Hanselmann
847 887c7aa6 Michael Hanselmann
        assert self.__deleted
848 a95fd5d7 Guido Trotter
849 84e344d4 Michael Hanselmann
      return acquired
850 a95fd5d7 Guido Trotter
    finally:
851 a95fd5d7 Guido Trotter
      self.__lock.release()
852 a95fd5d7 Guido Trotter
853 1a4e32d0 Guido Trotter
  def _release_save(self):
854 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
855 1a4e32d0 Guido Trotter
    self.release()
856 1a4e32d0 Guido Trotter
    return shared
857 1a4e32d0 Guido Trotter
858 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
859 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
860 1a4e32d0 Guido Trotter
861 aaae9bc0 Guido Trotter
862 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
863 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
864 e310b019 Guido Trotter
ALL_SET = None
865 e310b019 Guido Trotter
866 e310b019 Guido Trotter
867 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
868 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
869 5aab242c Michael Hanselmann

870 5aab242c Michael Hanselmann
  """
871 5aab242c Michael Hanselmann
872 5aab242c Michael Hanselmann
873 aaae9bc0 Guido Trotter
class LockSet:
874 aaae9bc0 Guido Trotter
  """Implements a set of locks.
875 aaae9bc0 Guido Trotter

876 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
877 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
878 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
879 aaae9bc0 Guido Trotter
  preventing deadlock.
880 aaae9bc0 Guido Trotter

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

883 7f93570a Iustin Pop
  @type name: string
884 7f93570a Iustin Pop
  @ivar name: the name of the lockset
885 7f93570a Iustin Pop

886 aaae9bc0 Guido Trotter
  """
887 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
888 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
889 aaae9bc0 Guido Trotter

890 ec44d893 Guido Trotter
    @type members: list of strings
891 c41eea6e Iustin Pop
    @param members: initial members of the set
892 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
893 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
894 aaae9bc0 Guido Trotter

895 aaae9bc0 Guido Trotter
    """
896 7f93570a Iustin Pop
    assert members is not None, "members parameter is not a list"
897 7f93570a Iustin Pop
    self.name = name
898 7f93570a Iustin Pop
899 19b9ba9a Michael Hanselmann
    # Lock monitor
900 19b9ba9a Michael Hanselmann
    self.__monitor = monitor
901 19b9ba9a Michael Hanselmann
902 c307ee34 Michael Hanselmann
    # Used internally to guarantee coherency
903 c307ee34 Michael Hanselmann
    self.__lock = SharedLock(self._GetLockName("[lockset]"), monitor=monitor)
904 aaae9bc0 Guido Trotter
905 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
906 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
907 aaae9bc0 Guido Trotter
    self.__lockdict = {}
908 aaae9bc0 Guido Trotter
909 7f93570a Iustin Pop
    for mname in members:
910 19b9ba9a Michael Hanselmann
      self.__lockdict[mname] = SharedLock(self._GetLockName(mname),
911 19b9ba9a Michael Hanselmann
                                          monitor=monitor)
912 aaae9bc0 Guido Trotter
913 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
914 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
915 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
916 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
917 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
918 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
919 aaae9bc0 Guido Trotter
    # will be trouble.
920 aaae9bc0 Guido Trotter
    self.__owners = {}
921 aaae9bc0 Guido Trotter
922 4fb780d1 Michael Hanselmann
  def _GetLockName(self, mname):
923 4fb780d1 Michael Hanselmann
    """Returns the name for a member lock.
924 4fb780d1 Michael Hanselmann

925 4fb780d1 Michael Hanselmann
    """
926 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
927 4fb780d1 Michael Hanselmann
928 3dbe3ddf Michael Hanselmann
  def _get_lock(self):
929 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock.
930 3dbe3ddf Michael Hanselmann

931 3dbe3ddf Michael Hanselmann
    """
932 3dbe3ddf Michael Hanselmann
    return self.__lock
933 3dbe3ddf Michael Hanselmann
934 3dbe3ddf Michael Hanselmann
  def _get_lockdict(self):
935 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock dictionary.
936 3dbe3ddf Michael Hanselmann

937 3dbe3ddf Michael Hanselmann
    Accessing this structure is only safe in single-thread usage or when the
938 3dbe3ddf Michael Hanselmann
    lockset-internal lock is held.
939 3dbe3ddf Michael Hanselmann

940 3dbe3ddf Michael Hanselmann
    """
941 3dbe3ddf Michael Hanselmann
    return self.__lockdict
942 3dbe3ddf Michael Hanselmann
943 aaae9bc0 Guido Trotter
  def _is_owned(self):
944 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
945 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
946 aaae9bc0 Guido Trotter
947 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
948 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
949 b2dabfd6 Guido Trotter
    if name is None:
950 b2dabfd6 Guido Trotter
      if not self._is_owned():
951 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
952 aaae9bc0 Guido Trotter
    else:
953 b2dabfd6 Guido Trotter
      if self._is_owned():
954 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
955 b2dabfd6 Guido Trotter
      else:
956 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
957 b2dabfd6 Guido Trotter
958 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
959 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
960 aaae9bc0 Guido Trotter
961 e4335b5b Michael Hanselmann
    assert not (name is None and self.__lock._is_owned()), \
962 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
963 e4335b5b Michael Hanselmann
964 b2dabfd6 Guido Trotter
    if name is not None:
965 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
966 b2dabfd6 Guido Trotter
967 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
968 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
969 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
970 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
971 aaae9bc0 Guido Trotter
972 aaae9bc0 Guido Trotter
  def _list_owned(self):
973 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
974 aaae9bc0 Guido Trotter
    if self._is_owned():
975 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
976 aaae9bc0 Guido Trotter
    else:
977 aaae9bc0 Guido Trotter
      return set()
978 aaae9bc0 Guido Trotter
979 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
980 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
981 5aab242c Michael Hanselmann
    for lname in self._list_owned():
982 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
983 56452af7 Michael Hanselmann
      if lock._is_owned():
984 56452af7 Michael Hanselmann
        lock.release()
985 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
986 5aab242c Michael Hanselmann
987 aaae9bc0 Guido Trotter
  def __names(self):
988 aaae9bc0 Guido Trotter
    """Return the current set of names.
989 aaae9bc0 Guido Trotter

990 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
991 aaae9bc0 Guido Trotter
    result after releasing the lock.
992 aaae9bc0 Guido Trotter

993 aaae9bc0 Guido Trotter
    """
994 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
995 aaae9bc0 Guido Trotter
996 aaae9bc0 Guido Trotter
  def _names(self):
997 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
998 aaae9bc0 Guido Trotter

999 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
1000 cdb08f44 Michael Hanselmann

1001 aaae9bc0 Guido Trotter
    """
1002 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
1003 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
1004 d4803c24 Guido Trotter
    release_lock = False
1005 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
1006 d4803c24 Guido Trotter
      release_lock = True
1007 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
1008 aaae9bc0 Guido Trotter
    try:
1009 aaae9bc0 Guido Trotter
      result = self.__names()
1010 aaae9bc0 Guido Trotter
    finally:
1011 d4803c24 Guido Trotter
      if release_lock:
1012 d4803c24 Guido Trotter
        self.__lock.release()
1013 0cf257c5 Guido Trotter
    return set(result)
1014 aaae9bc0 Guido Trotter
1015 7100c2fa Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, priority=None,
1016 887c7aa6 Michael Hanselmann
              test_notify=None):
1017 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
1018 aaae9bc0 Guido Trotter

1019 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1020 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1021 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1022 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1023 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
1024 c41eea6e Iustin Pop
        exclusive lock will be acquired
1025 5aab242c Michael Hanselmann
    @type timeout: float or None
1026 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1027 887c7aa6 Michael Hanselmann
    @type priority: integer
1028 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1029 5aab242c Michael Hanselmann
    @type test_notify: callable or None
1030 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1031 aaae9bc0 Guido Trotter

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

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

1038 aaae9bc0 Guido Trotter
    """
1039 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
1040 aaae9bc0 Guido Trotter
1041 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
1042 7f93570a Iustin Pop
    assert not self._is_owned(), ("Cannot acquire locks in the same set twice"
1043 7f93570a Iustin Pop
                                  " (lockset %s)" % self.name)
1044 aaae9bc0 Guido Trotter
1045 7100c2fa Michael Hanselmann
    if priority is None:
1046 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
1047 7100c2fa Michael Hanselmann
1048 5aab242c Michael Hanselmann
    # We need to keep track of how long we spent waiting for a lock. The
1049 5aab242c Michael Hanselmann
    # timeout passed to this function is over all lock acquires.
1050 557838c1 Renรฉ Nussbaumer
    running_timeout = utils.RunningTimeout(timeout, False)
1051 5aab242c Michael Hanselmann
1052 806e20fd Guido Trotter
    try:
1053 76e2f08a Michael Hanselmann
      if names is not None:
1054 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
1055 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
1056 5aab242c Michael Hanselmann
          names = [names]
1057 5aab242c Michael Hanselmann
1058 887c7aa6 Michael Hanselmann
        return self.__acquire_inner(names, False, shared, priority,
1059 7e8841bd Michael Hanselmann
                                    running_timeout.Remaining, test_notify)
1060 76e2f08a Michael Hanselmann
1061 76e2f08a Michael Hanselmann
      else:
1062 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
1063 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
1064 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
1065 76e2f08a Michael Hanselmann
        #
1066 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
1067 887c7aa6 Michael Hanselmann
        # everybody else can use the instances at the same time. If we are
1068 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
1069 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
1070 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
1071 887c7aa6 Michael Hanselmann
        if not self.__lock.acquire(shared=shared, priority=priority,
1072 7e8841bd Michael Hanselmann
                                   timeout=running_timeout.Remaining()):
1073 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1074 76e2f08a Michael Hanselmann
        try:
1075 76e2f08a Michael Hanselmann
          # note we own the set-lock
1076 76e2f08a Michael Hanselmann
          self._add_owned()
1077 76e2f08a Michael Hanselmann
1078 887c7aa6 Michael Hanselmann
          return self.__acquire_inner(self.__names(), True, shared, priority,
1079 7e8841bd Michael Hanselmann
                                      running_timeout.Remaining, test_notify)
1080 76e2f08a Michael Hanselmann
        except:
1081 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1082 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1083 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
1084 5aab242c Michael Hanselmann
          self.__lock.release()
1085 76e2f08a Michael Hanselmann
          self._del_owned()
1086 76e2f08a Michael Hanselmann
          raise
1087 5aab242c Michael Hanselmann
1088 5aab242c Michael Hanselmann
    except _AcquireTimeout:
1089 5aab242c Michael Hanselmann
      return None
1090 aaae9bc0 Guido Trotter
1091 887c7aa6 Michael Hanselmann
  def __acquire_inner(self, names, want_all, shared, priority,
1092 887c7aa6 Michael Hanselmann
                      timeout_fn, test_notify):
1093 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
1094 7e8841bd Michael Hanselmann

1095 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
1096 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
1097 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
1098 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
1099 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1100 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1101 76e2f08a Michael Hanselmann

1102 76e2f08a Michael Hanselmann
    """
1103 76e2f08a Michael Hanselmann
    acquire_list = []
1104 76e2f08a Michael Hanselmann
1105 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
1106 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
1107 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
1108 71e1863e Michael Hanselmann
    # deadlocks.
1109 71e1863e Michael Hanselmann
    for lname in sorted(utils.UniqueSequence(names)):
1110 76e2f08a Michael Hanselmann
      try:
1111 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
1112 76e2f08a Michael Hanselmann
      except KeyError:
1113 76e2f08a Michael Hanselmann
        if want_all:
1114 76e2f08a Michael Hanselmann
          # We are acquiring all the set, it doesn't matter if this particular
1115 76e2f08a Michael Hanselmann
          # element is not there anymore.
1116 76e2f08a Michael Hanselmann
          continue
1117 76e2f08a Michael Hanselmann
1118 e1137eb6 Michael Hanselmann
        raise errors.LockError("Non-existing lock %s in set %s (it may have"
1119 e1137eb6 Michael Hanselmann
                               " been removed)" % (lname, self.name))
1120 76e2f08a Michael Hanselmann
1121 9b154270 Michael Hanselmann
      acquire_list.append((lname, lock))
1122 9b154270 Michael Hanselmann
1123 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
1124 76e2f08a Michael Hanselmann
    acquired = set()
1125 76e2f08a Michael Hanselmann
1126 76e2f08a Michael Hanselmann
    try:
1127 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
1128 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
1129 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
1130 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
1131 76e2f08a Michael Hanselmann
      # lock gets deleted.
1132 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
1133 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
1134 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
1135 76e2f08a Michael Hanselmann
        else:
1136 76e2f08a Michael Hanselmann
          test_notify_fn = None
1137 76e2f08a Michael Hanselmann
1138 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
1139 76e2f08a Michael Hanselmann
1140 76e2f08a Michael Hanselmann
        try:
1141 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
1142 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
1143 887c7aa6 Michael Hanselmann
                                     priority=priority,
1144 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
1145 76e2f08a Michael Hanselmann
        except errors.LockError:
1146 76e2f08a Michael Hanselmann
          if want_all:
1147 76e2f08a Michael Hanselmann
            # We are acquiring all the set, it doesn't matter if this
1148 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
1149 76e2f08a Michael Hanselmann
            continue
1150 76e2f08a Michael Hanselmann
1151 e1137eb6 Michael Hanselmann
          raise errors.LockError("Non-existing lock %s in set %s (it may"
1152 e1137eb6 Michael Hanselmann
                                 " have been removed)" % (lname, self.name))
1153 76e2f08a Michael Hanselmann
1154 76e2f08a Michael Hanselmann
        if not acq_success:
1155 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
1156 76e2f08a Michael Hanselmann
          if timeout is None:
1157 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
1158 76e2f08a Michael Hanselmann
            # blocking.
1159 7f93570a Iustin Pop
            raise errors.LockError("Failed to get lock %s (set %s)" %
1160 7f93570a Iustin Pop
                                   (lname, self.name))
1161 76e2f08a Michael Hanselmann
1162 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1163 76e2f08a Michael Hanselmann
1164 76e2f08a Michael Hanselmann
        try:
1165 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
1166 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
1167 76e2f08a Michael Hanselmann
          acquired.add(lname)
1168 76e2f08a Michael Hanselmann
1169 76e2f08a Michael Hanselmann
        except:
1170 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1171 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1172 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
1173 76e2f08a Michael Hanselmann
          if lock._is_owned():
1174 76e2f08a Michael Hanselmann
            lock.release()
1175 76e2f08a Michael Hanselmann
          raise
1176 76e2f08a Michael Hanselmann
1177 76e2f08a Michael Hanselmann
    except:
1178 76e2f08a Michael Hanselmann
      # Release all owned locks
1179 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
1180 76e2f08a Michael Hanselmann
      raise
1181 76e2f08a Michael Hanselmann
1182 0cc00929 Guido Trotter
    return acquired
1183 aaae9bc0 Guido Trotter
1184 3dbe3ddf Michael Hanselmann
  def downgrade(self, names=None):
1185 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1186 3dbe3ddf Michael Hanselmann

1187 3dbe3ddf Michael Hanselmann
    The locks must have been acquired in exclusive mode.
1188 3dbe3ddf Michael Hanselmann

1189 3dbe3ddf Michael Hanselmann
    """
1190 3dbe3ddf Michael Hanselmann
    assert self._is_owned(), ("downgrade on lockset %s while not owning any"
1191 3dbe3ddf Michael Hanselmann
                              " lock" % self.name)
1192 3dbe3ddf Michael Hanselmann
1193 3dbe3ddf Michael Hanselmann
    # Support passing in a single resource to downgrade rather than many
1194 3dbe3ddf Michael Hanselmann
    if isinstance(names, basestring):
1195 3dbe3ddf Michael Hanselmann
      names = [names]
1196 3dbe3ddf Michael Hanselmann
1197 3dbe3ddf Michael Hanselmann
    owned = self._list_owned()
1198 3dbe3ddf Michael Hanselmann
1199 3dbe3ddf Michael Hanselmann
    if names is None:
1200 3dbe3ddf Michael Hanselmann
      names = owned
1201 3dbe3ddf Michael Hanselmann
    else:
1202 3dbe3ddf Michael Hanselmann
      names = set(names)
1203 3dbe3ddf Michael Hanselmann
      assert owned.issuperset(names), \
1204 3dbe3ddf Michael Hanselmann
        ("downgrade() on unheld resources %s (set %s)" %
1205 3dbe3ddf Michael Hanselmann
         (names.difference(owned), self.name))
1206 3dbe3ddf Michael Hanselmann
1207 3dbe3ddf Michael Hanselmann
    for lockname in names:
1208 3dbe3ddf Michael Hanselmann
      self.__lockdict[lockname].downgrade()
1209 3dbe3ddf Michael Hanselmann
1210 3dbe3ddf Michael Hanselmann
    # Do we own the lockset in exclusive mode?
1211 3dbe3ddf Michael Hanselmann
    if self.__lock._is_owned(shared=0):
1212 3dbe3ddf Michael Hanselmann
      # Have all locks been downgraded?
1213 3dbe3ddf Michael Hanselmann
      if not compat.any(lock._is_owned(shared=0)
1214 3dbe3ddf Michael Hanselmann
                        for lock in self.__lockdict.values()):
1215 3dbe3ddf Michael Hanselmann
        self.__lock.downgrade()
1216 3dbe3ddf Michael Hanselmann
        assert self.__lock._is_owned(shared=1)
1217 3dbe3ddf Michael Hanselmann
1218 3dbe3ddf Michael Hanselmann
    return True
1219 3dbe3ddf Michael Hanselmann
1220 aaae9bc0 Guido Trotter
  def release(self, names=None):
1221 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
1222 aaae9bc0 Guido Trotter

1223 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1224 aaae9bc0 Guido Trotter
    before releasing them.
1225 aaae9bc0 Guido Trotter

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

1230 aaae9bc0 Guido Trotter
    """
1231 7f93570a Iustin Pop
    assert self._is_owned(), ("release() on lock set %s while not owner" %
1232 7f93570a Iustin Pop
                              self.name)
1233 aaae9bc0 Guido Trotter
1234 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1235 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1236 aaae9bc0 Guido Trotter
      names = [names]
1237 aaae9bc0 Guido Trotter
1238 aaae9bc0 Guido Trotter
    if names is None:
1239 aaae9bc0 Guido Trotter
      names = self._list_owned()
1240 aaae9bc0 Guido Trotter
    else:
1241 aaae9bc0 Guido Trotter
      names = set(names)
1242 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
1243 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1244 7f93570a Iustin Pop
               (names.difference(self._list_owned()), self.name))
1245 aaae9bc0 Guido Trotter
1246 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1247 3b7ed473 Guido Trotter
    # After this 'add' can work again
1248 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
1249 3b7ed473 Guido Trotter
      self.__lock.release()
1250 b2dabfd6 Guido Trotter
      self._del_owned()
1251 3b7ed473 Guido Trotter
1252 aaae9bc0 Guido Trotter
    for lockname in names:
1253 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1254 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1255 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1256 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1257 aaae9bc0 Guido Trotter
1258 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1259 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1260 aaae9bc0 Guido Trotter

1261 ec44d893 Guido Trotter
    @type names: list of strings
1262 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1263 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1264 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1265 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1266 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1267 aaae9bc0 Guido Trotter

1268 aaae9bc0 Guido Trotter
    """
1269 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1270 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
1271 7f93570a Iustin Pop
      ("Cannot add locks if the set %s is only partially owned, or shared" %
1272 7f93570a Iustin Pop
       self.name)
1273 3b7ed473 Guido Trotter
1274 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1275 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1276 aaae9bc0 Guido Trotter
      names = [names]
1277 aaae9bc0 Guido Trotter
1278 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1279 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1280 3b7ed473 Guido Trotter
    release_lock = False
1281 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
1282 3b7ed473 Guido Trotter
      release_lock = True
1283 3b7ed473 Guido Trotter
      self.__lock.acquire()
1284 3b7ed473 Guido Trotter
1285 aaae9bc0 Guido Trotter
    try:
1286 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1287 aaae9bc0 Guido Trotter
      if invalid_names:
1288 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1289 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1290 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1291 7f93570a Iustin Pop
        raise errors.LockError("duplicate add(%s) on lockset %s" %
1292 7f93570a Iustin Pop
                               (invalid_names, self.name))
1293 aaae9bc0 Guido Trotter
1294 aaae9bc0 Guido Trotter
      for lockname in names:
1295 19b9ba9a Michael Hanselmann
        lock = SharedLock(self._GetLockName(lockname), monitor=self.__monitor)
1296 aaae9bc0 Guido Trotter
1297 aaae9bc0 Guido Trotter
        if acquired:
1298 887c7aa6 Michael Hanselmann
          # No need for priority or timeout here as this lock has just been
1299 887c7aa6 Michael Hanselmann
          # created
1300 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1301 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1302 aaae9bc0 Guido Trotter
          try:
1303 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1304 aaae9bc0 Guido Trotter
          except:
1305 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1306 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1307 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1308 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1309 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1310 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1311 aaae9bc0 Guido Trotter
            lock.release()
1312 aaae9bc0 Guido Trotter
            raise
1313 aaae9bc0 Guido Trotter
1314 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1315 aaae9bc0 Guido Trotter
1316 aaae9bc0 Guido Trotter
    finally:
1317 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1318 3b7ed473 Guido Trotter
      if release_lock:
1319 3b7ed473 Guido Trotter
        self.__lock.release()
1320 aaae9bc0 Guido Trotter
1321 aaae9bc0 Guido Trotter
    return True
1322 aaae9bc0 Guido Trotter
1323 5e0a6daf Michael Hanselmann
  def remove(self, names):
1324 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1325 aaae9bc0 Guido Trotter

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

1329 ec44d893 Guido Trotter
    @type names: list of strings
1330 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1331 aaae9bc0 Guido Trotter

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

1336 aaae9bc0 Guido Trotter
    """
1337 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1338 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1339 aaae9bc0 Guido Trotter
      names = [names]
1340 aaae9bc0 Guido Trotter
1341 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1342 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1343 aaae9bc0 Guido Trotter
    # by the lock itself.
1344 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
1345 7f93570a Iustin Pop
      "remove() on acquired lockset %s while not owning all elements" %
1346 7f93570a Iustin Pop
      self.name)
1347 aaae9bc0 Guido Trotter
1348 3f404fc5 Guido Trotter
    removed = []
1349 aaae9bc0 Guido Trotter
1350 aaae9bc0 Guido Trotter
    for lname in names:
1351 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1352 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1353 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1354 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1355 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1356 aaae9bc0 Guido Trotter
      try:
1357 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1358 3f404fc5 Guido Trotter
        removed.append(lname)
1359 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1360 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1361 7f93570a Iustin Pop
        assert not self._is_owned(), ("remove failed while holding lockset %s"
1362 7f93570a Iustin Pop
                                      % self.name)
1363 aaae9bc0 Guido Trotter
      else:
1364 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1365 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1366 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1367 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1368 aaae9bc0 Guido Trotter
        #
1369 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1370 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1371 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1372 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1373 aaae9bc0 Guido Trotter
        if self._is_owned():
1374 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1375 aaae9bc0 Guido Trotter
1376 3f404fc5 Guido Trotter
    return removed
1377 aaae9bc0 Guido Trotter
1378 7ee7c0c7 Guido Trotter
1379 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1380 7ee7c0c7 Guido Trotter
# Current rules are:
1381 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1382 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1383 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1384 7ee7c0c7 Guido Trotter
#   avoided.
1385 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1386 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1387 7ee7c0c7 Guido Trotter
#   the same time.
1388 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1389 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1390 819ca990 Guido Trotter
LEVEL_NODEGROUP = 2
1391 819ca990 Guido Trotter
LEVEL_NODE = 3
1392 7ee7c0c7 Guido Trotter
1393 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1394 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1395 819ca990 Guido Trotter
          LEVEL_NODEGROUP,
1396 04e1bfaf Guido Trotter
          LEVEL_NODE]
1397 7ee7c0c7 Guido Trotter
1398 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1399 819ca990 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_NODEGROUP, LEVEL_INSTANCE]
1400 7ee7c0c7 Guido Trotter
1401 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1402 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1403 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1404 819ca990 Guido Trotter
  LEVEL_NODEGROUP: "nodegroup",
1405 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1406 ea205dbc Michael Hanselmann
  }
1407 ea205dbc Michael Hanselmann
1408 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1409 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1410 7ee7c0c7 Guido Trotter
1411 7ee7c0c7 Guido Trotter
1412 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1413 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1414 7ee7c0c7 Guido Trotter

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

1420 7ee7c0c7 Guido Trotter
  """
1421 7ee7c0c7 Guido Trotter
  _instance = None
1422 7ee7c0c7 Guido Trotter
1423 819ca990 Guido Trotter
  def __init__(self, nodes, nodegroups, instances):
1424 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1425 7ee7c0c7 Guido Trotter

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

1429 c41eea6e Iustin Pop
    @param nodes: list of node names
1430 819ca990 Guido Trotter
    @param nodegroups: list of nodegroup uuids
1431 c41eea6e Iustin Pop
    @param instances: list of instance names
1432 7ee7c0c7 Guido Trotter

1433 7ee7c0c7 Guido Trotter
    """
1434 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1435 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1436 c41eea6e Iustin Pop
1437 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1438 7ee7c0c7 Guido Trotter
1439 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1440 19b9ba9a Michael Hanselmann
1441 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1442 7ee7c0c7 Guido Trotter
    # locking order.
1443 7ee7c0c7 Guido Trotter
    self.__keyring = {
1444 19b9ba9a Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "BGL", monitor=self._monitor),
1445 19b9ba9a Michael Hanselmann
      LEVEL_NODE: LockSet(nodes, "nodes", monitor=self._monitor),
1446 819ca990 Guido Trotter
      LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroups", monitor=self._monitor),
1447 19b9ba9a Michael Hanselmann
      LEVEL_INSTANCE: LockSet(instances, "instances",
1448 19b9ba9a Michael Hanselmann
                              monitor=self._monitor),
1449 19b9ba9a Michael Hanselmann
      }
1450 19b9ba9a Michael Hanselmann
1451 4c03b2b5 Michael Hanselmann
  def AddToLockMonitor(self, provider):
1452 4c03b2b5 Michael Hanselmann
    """Registers a new lock with the monitor.
1453 4c03b2b5 Michael Hanselmann

1454 4c03b2b5 Michael Hanselmann
    See L{LockMonitor.RegisterLock}.
1455 4c03b2b5 Michael Hanselmann

1456 4c03b2b5 Michael Hanselmann
    """
1457 4c03b2b5 Michael Hanselmann
    return self._monitor.RegisterLock(provider)
1458 4c03b2b5 Michael Hanselmann
1459 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1460 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1461 19b9ba9a Michael Hanselmann

1462 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1463 19b9ba9a Michael Hanselmann

1464 19b9ba9a Michael Hanselmann
    """
1465 24d16f76 Michael Hanselmann
    return self._monitor.QueryLocks(fields)
1466 24d16f76 Michael Hanselmann
1467 24d16f76 Michael Hanselmann
  def OldStyleQueryLocks(self, fields):
1468 24d16f76 Michael Hanselmann
    """Queries information from all locks, returning old-style data.
1469 24d16f76 Michael Hanselmann

1470 24d16f76 Michael Hanselmann
    See L{LockMonitor.OldStyleQueryLocks}.
1471 24d16f76 Michael Hanselmann

1472 24d16f76 Michael Hanselmann
    """
1473 24d16f76 Michael Hanselmann
    return self._monitor.OldStyleQueryLocks(fields)
1474 7ee7c0c7 Guido Trotter
1475 7ee7c0c7 Guido Trotter
  def _names(self, level):
1476 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1477 7ee7c0c7 Guido Trotter

1478 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1479 c41eea6e Iustin Pop

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

1482 7ee7c0c7 Guido Trotter
    """
1483 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1484 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1485 7ee7c0c7 Guido Trotter
1486 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1487 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1488 7ee7c0c7 Guido Trotter

1489 7ee7c0c7 Guido Trotter
    """
1490 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1491 7ee7c0c7 Guido Trotter
1492 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1493 d4f4b3e7 Guido Trotter
1494 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1495 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1496 7ee7c0c7 Guido Trotter

1497 7ee7c0c7 Guido Trotter
    """
1498 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1499 7ee7c0c7 Guido Trotter
1500 07cba1bc Michael Hanselmann
  list_owned = _list_owned
1501 07cba1bc Michael Hanselmann
1502 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1503 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1504 7ee7c0c7 Guido Trotter

1505 7ee7c0c7 Guido Trotter
    """
1506 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1507 7ee7c0c7 Guido Trotter
    # the test cases.
1508 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1509 7ee7c0c7 Guido Trotter
1510 b459a848 Andrea Spadaccini
  def _BGL_owned(self): # pylint: disable=C0103
1511 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1512 7ee7c0c7 Guido Trotter

1513 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1514 7ee7c0c7 Guido Trotter

1515 7ee7c0c7 Guido Trotter
    """
1516 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1517 7ee7c0c7 Guido Trotter
1518 c70d2d9b Iustin Pop
  @staticmethod
1519 b459a848 Andrea Spadaccini
  def _contains_BGL(level, names): # pylint: disable=C0103
1520 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1521 c41eea6e Iustin Pop

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

1525 7ee7c0c7 Guido Trotter
    """
1526 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1527 7ee7c0c7 Guido Trotter
1528 b30d95b6 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None):
1529 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1530 7ee7c0c7 Guido Trotter

1531 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1532 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1533 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1534 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1535 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1536 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1537 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1538 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1539 5e0a6daf Michael Hanselmann
    @type timeout: float
1540 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1541 b30d95b6 Michael Hanselmann
    @type priority: integer
1542 b30d95b6 Michael Hanselmann
    @param priority: Priority for acquiring lock
1543 7ee7c0c7 Guido Trotter

1544 7ee7c0c7 Guido Trotter
    """
1545 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1546 7ee7c0c7 Guido Trotter
1547 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1548 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1549 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1550 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1551 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1552 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1553 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1554 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1555 7ee7c0c7 Guido Trotter
1556 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1557 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1558 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1559 7ee7c0c7 Guido Trotter
1560 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1561 b30d95b6 Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout,
1562 b30d95b6 Michael Hanselmann
                                         priority=priority)
1563 7ee7c0c7 Guido Trotter
1564 3dbe3ddf Michael Hanselmann
  def downgrade(self, level, names=None):
1565 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1566 3dbe3ddf Michael Hanselmann

1567 3dbe3ddf Michael Hanselmann
    You must have acquired the locks in exclusive mode.
1568 3dbe3ddf Michael Hanselmann

1569 3dbe3ddf Michael Hanselmann
    @type level: member of locking.LEVELS
1570 3dbe3ddf Michael Hanselmann
    @param level: the level at which the locks shall be downgraded
1571 3dbe3ddf Michael Hanselmann
    @type names: list of strings, or None
1572 3dbe3ddf Michael Hanselmann
    @param names: the names of the locks which shall be downgraded
1573 3dbe3ddf Michael Hanselmann
        (defaults to all the locks acquired at the level)
1574 3dbe3ddf Michael Hanselmann

1575 3dbe3ddf Michael Hanselmann
    """
1576 3dbe3ddf Michael Hanselmann
    assert level in LEVELS, "Invalid locking level %s" % level
1577 3dbe3ddf Michael Hanselmann
1578 3dbe3ddf Michael Hanselmann
    return self.__keyring[level].downgrade(names=names)
1579 3dbe3ddf Michael Hanselmann
1580 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1581 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1582 7ee7c0c7 Guido Trotter

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

1586 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1587 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1588 ec44d893 Guido Trotter
    @type names: list of strings, or None
1589 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1590 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1591 7ee7c0c7 Guido Trotter

1592 7ee7c0c7 Guido Trotter
    """
1593 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1594 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1595 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1596 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1597 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1598 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1599 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1600 7ee7c0c7 Guido Trotter
1601 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1602 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1603 7ee7c0c7 Guido Trotter
1604 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1605 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1606 7ee7c0c7 Guido Trotter

1607 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1608 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1609 ec44d893 Guido Trotter
    @type names: list of strings
1610 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1611 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1612 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1613 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1614 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1615 c41eea6e Iustin Pop

1616 7ee7c0c7 Guido Trotter
    """
1617 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1618 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1619 7ee7c0c7 Guido Trotter
           " operations")
1620 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1621 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1622 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1623 7ee7c0c7 Guido Trotter
1624 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1625 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1626 7ee7c0c7 Guido Trotter

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

1630 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1631 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1632 ec44d893 Guido Trotter
    @type names: list of strings
1633 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1634 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1635 7ee7c0c7 Guido Trotter

1636 7ee7c0c7 Guido Trotter
    """
1637 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1638 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1639 7ee7c0c7 Guido Trotter
           " operations")
1640 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1641 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1642 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1643 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1644 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1645 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1646 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1647 19b9ba9a Michael Hanselmann
1648 19b9ba9a Michael Hanselmann
1649 44b4eddc Michael Hanselmann
def _MonitorSortKey((item, idx, num)):
1650 e4e35357 Michael Hanselmann
  """Sorting key function.
1651 e4e35357 Michael Hanselmann

1652 44b4eddc Michael Hanselmann
  Sort by name, registration order and then order of information. This provides
1653 44b4eddc Michael Hanselmann
  a stable sort order over different providers, even if they return the same
1654 44b4eddc Michael Hanselmann
  name.
1655 e4e35357 Michael Hanselmann

1656 e4e35357 Michael Hanselmann
  """
1657 e4e35357 Michael Hanselmann
  (name, _, _, _) = item
1658 e4e35357 Michael Hanselmann
1659 44b4eddc Michael Hanselmann
  return (utils.NiceSortKey(name), num, idx)
1660 e4e35357 Michael Hanselmann
1661 e4e35357 Michael Hanselmann
1662 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1663 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1664 19b9ba9a Michael Hanselmann
1665 19b9ba9a Michael Hanselmann
  def __init__(self):
1666 19b9ba9a Michael Hanselmann
    """Initializes this class.
1667 19b9ba9a Michael Hanselmann

1668 19b9ba9a Michael Hanselmann
    """
1669 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1670 19b9ba9a Michael Hanselmann
1671 e4e35357 Michael Hanselmann
    # Counter for stable sorting
1672 e4e35357 Michael Hanselmann
    self._counter = itertools.count(0)
1673 e4e35357 Michael Hanselmann
1674 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1675 19b9ba9a Michael Hanselmann
    # references and deletion.
1676 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1677 19b9ba9a Michael Hanselmann
1678 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1679 44b4eddc Michael Hanselmann
  def RegisterLock(self, provider):
1680 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1681 19b9ba9a Michael Hanselmann

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

1690 19b9ba9a Michael Hanselmann
    """
1691 44b4eddc Michael Hanselmann
    assert provider not in self._locks, "Duplicate registration"
1692 e4e35357 Michael Hanselmann
1693 e4e35357 Michael Hanselmann
    # There used to be a check for duplicate names here. As it turned out, when
1694 e4e35357 Michael Hanselmann
    # a lock is re-created with the same name in a very short timeframe, the
1695 e4e35357 Michael Hanselmann
    # previous instance might not yet be removed from the weakref dictionary.
1696 e4e35357 Michael Hanselmann
    # By keeping track of the order of incoming registrations, a stable sort
1697 e4e35357 Michael Hanselmann
    # ordering can still be guaranteed.
1698 e4e35357 Michael Hanselmann
1699 44b4eddc Michael Hanselmann
    self._locks[provider] = self._counter.next()
1700 19b9ba9a Michael Hanselmann
1701 24d16f76 Michael Hanselmann
  def _GetLockInfo(self, requested):
1702 44b4eddc Michael Hanselmann
    """Get information from all locks.
1703 19b9ba9a Michael Hanselmann

1704 19b9ba9a Michael Hanselmann
    """
1705 44b4eddc Michael Hanselmann
    # Must hold lock while getting consistent list of tracked items
1706 44b4eddc Michael Hanselmann
    self._lock.acquire(shared=1)
1707 44b4eddc Michael Hanselmann
    try:
1708 44b4eddc Michael Hanselmann
      items = self._locks.items()
1709 44b4eddc Michael Hanselmann
    finally:
1710 44b4eddc Michael Hanselmann
      self._lock.release()
1711 44b4eddc Michael Hanselmann
1712 44b4eddc Michael Hanselmann
    return [(info, idx, num)
1713 44b4eddc Michael Hanselmann
            for (provider, num) in items
1714 44b4eddc Michael Hanselmann
            for (idx, info) in enumerate(provider.GetLockInfo(requested))]
1715 19b9ba9a Michael Hanselmann
1716 24d16f76 Michael Hanselmann
  def _Query(self, fields):
1717 24d16f76 Michael Hanselmann
    """Queries information from all locks.
1718 19b9ba9a Michael Hanselmann

1719 24d16f76 Michael Hanselmann
    @type fields: list of strings
1720 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1721 24d16f76 Michael Hanselmann

1722 24d16f76 Michael Hanselmann
    """
1723 24d16f76 Michael Hanselmann
    qobj = query.Query(query.LOCK_FIELDS, fields)
1724 24d16f76 Michael Hanselmann
1725 e4e35357 Michael Hanselmann
    # Get all data with internal lock held and then sort by name and incoming
1726 e4e35357 Michael Hanselmann
    # order
1727 e4e35357 Michael Hanselmann
    lockinfo = sorted(self._GetLockInfo(qobj.RequestedData()),
1728 e4e35357 Michael Hanselmann
                      key=_MonitorSortKey)
1729 24d16f76 Michael Hanselmann
1730 e4e35357 Michael Hanselmann
    # Extract lock information and build query data
1731 eb62069e Iustin Pop
    return (qobj, query.LockQueryData(map(compat.fst, lockinfo)))
1732 19b9ba9a Michael Hanselmann
1733 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1734 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1735 19b9ba9a Michael Hanselmann

1736 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1737 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1738 19b9ba9a Michael Hanselmann

1739 19b9ba9a Michael Hanselmann
    """
1740 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1741 19b9ba9a Michael Hanselmann
1742 24d16f76 Michael Hanselmann
    # Prepare query response
1743 24d16f76 Michael Hanselmann
    return query.GetQueryResponse(qobj, ctx)
1744 24d16f76 Michael Hanselmann
1745 24d16f76 Michael Hanselmann
  def OldStyleQueryLocks(self, fields):
1746 24d16f76 Michael Hanselmann
    """Queries information from all locks, returning old-style data.
1747 24d16f76 Michael Hanselmann

1748 24d16f76 Michael Hanselmann
    @type fields: list of strings
1749 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1750 24d16f76 Michael Hanselmann

1751 24d16f76 Michael Hanselmann
    """
1752 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1753 19b9ba9a Michael Hanselmann
1754 24d16f76 Michael Hanselmann
    return qobj.OldStyleQuery(ctx)