Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 6b9b18a2

History | View | Annotate | Download (48.2 kB)

1 162c1c1f Guido Trotter
#
2 162c1c1f Guido Trotter
#
3 162c1c1f Guido Trotter
4 7f93570a Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
5 162c1c1f Guido Trotter
#
6 162c1c1f Guido Trotter
# This program is free software; you can redistribute it and/or modify
7 162c1c1f Guido Trotter
# it under the terms of the GNU General Public License as published by
8 162c1c1f Guido Trotter
# the Free Software Foundation; either version 2 of the License, or
9 162c1c1f Guido Trotter
# (at your option) any later version.
10 162c1c1f Guido Trotter
#
11 162c1c1f Guido Trotter
# This program is distributed in the hope that it will be useful, but
12 162c1c1f Guido Trotter
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 162c1c1f Guido Trotter
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 162c1c1f Guido Trotter
# General Public License for more details.
15 162c1c1f Guido Trotter
#
16 162c1c1f Guido Trotter
# You should have received a copy of the GNU General Public License
17 162c1c1f Guido Trotter
# along with this program; if not, write to the Free Software
18 162c1c1f Guido Trotter
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 162c1c1f Guido Trotter
# 02110-1301, USA.
20 162c1c1f Guido Trotter
21 162c1c1f Guido Trotter
"""Module implementing the Ganeti locking code."""
22 162c1c1f Guido Trotter
23 c70d2d9b Iustin Pop
# pylint: disable-msg=W0212
24 c70d2d9b Iustin Pop
25 c70d2d9b Iustin Pop
# W0212 since e.g. LockSet methods use (a lot) the internals of
26 c70d2d9b Iustin Pop
# SharedLock
27 162c1c1f Guido Trotter
28 d76167a5 Michael Hanselmann
import os
29 d76167a5 Michael Hanselmann
import select
30 162c1c1f Guido Trotter
import threading
31 d76167a5 Michael Hanselmann
import errno
32 19b9ba9a Michael Hanselmann
import weakref
33 19b9ba9a Michael Hanselmann
import logging
34 887c7aa6 Michael Hanselmann
import heapq
35 24d16f76 Michael Hanselmann
import operator
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 34cb5617 Guido Trotter
  def wait(self, timeout=None):
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 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=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 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
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 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=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 19b9ba9a Michael Hanselmann
      monitor.RegisterLock(self)
437 19b9ba9a Michael Hanselmann
438 24d16f76 Michael Hanselmann
  def GetInfo(self, requested):
439 19b9ba9a Michael Hanselmann
    """Retrieves information for querying locks.
440 19b9ba9a Michael Hanselmann

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

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

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

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

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

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

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

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

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

546 84e344d4 Michael Hanselmann
    @rtype: int
547 a95fd5d7 Guido Trotter

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

558 887c7aa6 Michael Hanselmann
    @rtype: bool
559 887c7aa6 Michael Hanselmann

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

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

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

592 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
593 887c7aa6 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

828 7f93570a Iustin Pop
  @type name: string
829 7f93570a Iustin Pop
  @ivar name: the name of the lockset
830 7f93570a Iustin Pop

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

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

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

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

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

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

929 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
930 cdb08f44 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1348 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1349 19b9ba9a Michael Hanselmann

1350 19b9ba9a Michael Hanselmann
    """
1351 24d16f76 Michael Hanselmann
    return self._monitor.QueryLocks(fields)
1352 24d16f76 Michael Hanselmann
1353 24d16f76 Michael Hanselmann
  def OldStyleQueryLocks(self, fields):
1354 24d16f76 Michael Hanselmann
    """Queries information from all locks, returning old-style data.
1355 24d16f76 Michael Hanselmann

1356 24d16f76 Michael Hanselmann
    See L{LockMonitor.OldStyleQueryLocks}.
1357 24d16f76 Michael Hanselmann

1358 24d16f76 Michael Hanselmann
    """
1359 24d16f76 Michael Hanselmann
    return self._monitor.OldStyleQueryLocks(fields)
1360 7ee7c0c7 Guido Trotter
1361 7ee7c0c7 Guido Trotter
  def _names(self, level):
1362 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1363 7ee7c0c7 Guido Trotter

1364 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1365 c41eea6e Iustin Pop

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

1368 7ee7c0c7 Guido Trotter
    """
1369 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1370 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1371 7ee7c0c7 Guido Trotter
1372 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1373 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1374 7ee7c0c7 Guido Trotter

1375 7ee7c0c7 Guido Trotter
    """
1376 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1377 7ee7c0c7 Guido Trotter
1378 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1379 d4f4b3e7 Guido Trotter
1380 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1381 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1382 7ee7c0c7 Guido Trotter

1383 7ee7c0c7 Guido Trotter
    """
1384 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1385 7ee7c0c7 Guido Trotter
1386 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1387 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1388 7ee7c0c7 Guido Trotter

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

1397 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1398 7ee7c0c7 Guido Trotter

1399 7ee7c0c7 Guido Trotter
    """
1400 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1401 7ee7c0c7 Guido Trotter
1402 c70d2d9b Iustin Pop
  @staticmethod
1403 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1404 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1405 c41eea6e Iustin Pop

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

1409 7ee7c0c7 Guido Trotter
    """
1410 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1411 7ee7c0c7 Guido Trotter
1412 b30d95b6 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None):
1413 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1414 7ee7c0c7 Guido Trotter

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

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

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

1454 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1455 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1456 ec44d893 Guido Trotter
    @type names: list of strings, or None
1457 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1458 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1459 7ee7c0c7 Guido Trotter

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

1475 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1476 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1477 ec44d893 Guido Trotter
    @type names: list of strings
1478 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1479 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1480 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1481 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1482 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1483 c41eea6e Iustin Pop

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

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

1498 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1499 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1500 ec44d893 Guido Trotter
    @type names: list of strings
1501 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1502 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1503 7ee7c0c7 Guido Trotter

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

1523 19b9ba9a Michael Hanselmann
    """
1524 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1525 19b9ba9a Michael Hanselmann
1526 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1527 19b9ba9a Michael Hanselmann
    # references and deletion.
1528 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1529 19b9ba9a Michael Hanselmann
1530 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1531 19b9ba9a Michael Hanselmann
  def RegisterLock(self, lock):
1532 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1533 19b9ba9a Michael Hanselmann

1534 19b9ba9a Michael Hanselmann
    """
1535 19b9ba9a Michael Hanselmann
    logging.debug("Registering lock %s", lock.name)
1536 19b9ba9a Michael Hanselmann
    assert lock not in self._locks, "Duplicate lock registration"
1537 19b9ba9a Michael Hanselmann
    assert not compat.any(lock.name == i.name for i in self._locks.keys()), \
1538 19b9ba9a Michael Hanselmann
           "Found duplicate lock name"
1539 19b9ba9a Michael Hanselmann
    self._locks[lock] = None
1540 19b9ba9a Michael Hanselmann
1541 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1542 24d16f76 Michael Hanselmann
  def _GetLockInfo(self, requested):
1543 19b9ba9a Michael Hanselmann
    """Get information from all locks while the monitor lock is held.
1544 19b9ba9a Michael Hanselmann

1545 19b9ba9a Michael Hanselmann
    """
1546 24d16f76 Michael Hanselmann
    return [lock.GetInfo(requested) for lock in self._locks.keys()]
1547 19b9ba9a Michael Hanselmann
1548 24d16f76 Michael Hanselmann
  def _Query(self, fields):
1549 24d16f76 Michael Hanselmann
    """Queries information from all locks.
1550 19b9ba9a Michael Hanselmann

1551 24d16f76 Michael Hanselmann
    @type fields: list of strings
1552 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1553 24d16f76 Michael Hanselmann

1554 24d16f76 Michael Hanselmann
    """
1555 24d16f76 Michael Hanselmann
    qobj = query.Query(query.LOCK_FIELDS, fields)
1556 24d16f76 Michael Hanselmann
1557 24d16f76 Michael Hanselmann
    # Get all data and sort by name
1558 24d16f76 Michael Hanselmann
    lockinfo = utils.NiceSort(self._GetLockInfo(qobj.RequestedData()),
1559 24d16f76 Michael Hanselmann
                              key=operator.itemgetter(0))
1560 24d16f76 Michael Hanselmann
1561 24d16f76 Michael Hanselmann
    return (qobj, query.LockQueryData(lockinfo))
1562 19b9ba9a Michael Hanselmann
1563 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1564 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1565 19b9ba9a Michael Hanselmann

1566 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1567 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1568 19b9ba9a Michael Hanselmann

1569 19b9ba9a Michael Hanselmann
    """
1570 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1571 19b9ba9a Michael Hanselmann
1572 24d16f76 Michael Hanselmann
    # Prepare query response
1573 24d16f76 Michael Hanselmann
    return query.GetQueryResponse(qobj, ctx)
1574 24d16f76 Michael Hanselmann
1575 24d16f76 Michael Hanselmann
  def OldStyleQueryLocks(self, fields):
1576 24d16f76 Michael Hanselmann
    """Queries information from all locks, returning old-style data.
1577 24d16f76 Michael Hanselmann

1578 24d16f76 Michael Hanselmann
    @type fields: list of strings
1579 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1580 24d16f76 Michael Hanselmann

1581 24d16f76 Michael Hanselmann
    """
1582 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1583 19b9ba9a Michael Hanselmann
1584 24d16f76 Michael Hanselmann
    return qobj.OldStyleQuery(ctx)