Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ f7f03738

History | View | Annotate | Download (61.1 kB)

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

69 42a999d1 Guido Trotter
  Calls the function holding the given lock, either in exclusive or shared
70 42a999d1 Guido Trotter
  mode. It requires the passed lock to be a SharedLock (or support its
71 42a999d1 Guido Trotter
  semantics).
72 42a999d1 Guido Trotter

73 dbb11e8b Guido Trotter
  @type mylock: lockable object or string
74 dbb11e8b Guido Trotter
  @param mylock: lock to acquire or class member name of the lock to acquire
75 dbb11e8b Guido Trotter

76 42a999d1 Guido Trotter
  """
77 42a999d1 Guido Trotter
  def wrap(fn):
78 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
79 dbb11e8b Guido Trotter
      if isinstance(mylock, basestring):
80 dbb11e8b Guido Trotter
        assert args, "cannot ssynchronize on non-class method: self not found"
81 dbb11e8b Guido Trotter
        # args[0] is "self"
82 dbb11e8b Guido Trotter
        lock = getattr(args[0], mylock)
83 dbb11e8b Guido Trotter
      else:
84 dbb11e8b Guido Trotter
        lock = mylock
85 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
86 42a999d1 Guido Trotter
      try:
87 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
88 42a999d1 Guido Trotter
      finally:
89 42a999d1 Guido Trotter
        lock.release()
90 42a999d1 Guido Trotter
    return sync_function
91 42a999d1 Guido Trotter
  return wrap
92 42a999d1 Guido Trotter
93 42a999d1 Guido Trotter
94 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
95 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
96 d76167a5 Michael Hanselmann

97 d76167a5 Michael Hanselmann
  """
98 d76167a5 Michael Hanselmann
  __slots__ = [
99 d76167a5 Michael Hanselmann
    "_fd",
100 d76167a5 Michael Hanselmann
    "_poller",
101 d76167a5 Michael Hanselmann
    ]
102 d76167a5 Michael Hanselmann
103 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
104 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
105 d76167a5 Michael Hanselmann

106 d76167a5 Michael Hanselmann
    @type poller: select.poll
107 d76167a5 Michael Hanselmann
    @param poller: Poller object
108 d76167a5 Michael Hanselmann
    @type fd: int
109 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
110 d76167a5 Michael Hanselmann

111 d76167a5 Michael Hanselmann
    """
112 d76167a5 Michael Hanselmann
    object.__init__(self)
113 d76167a5 Michael Hanselmann
    self._poller = poller
114 d76167a5 Michael Hanselmann
    self._fd = fd
115 d76167a5 Michael Hanselmann
116 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
117 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
118 d76167a5 Michael Hanselmann

119 d76167a5 Michael Hanselmann
    @type timeout: float or None
120 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
121 d76167a5 Michael Hanselmann

122 d76167a5 Michael Hanselmann
    """
123 557838c1 Renรฉ Nussbaumer
    running_timeout = utils.RunningTimeout(timeout, True)
124 f4e673fb Michael Hanselmann
125 f4e673fb Michael Hanselmann
    while True:
126 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
127 f4e673fb Michael Hanselmann
128 b44b0141 Michael Hanselmann
      if remaining_time is not None:
129 b44b0141 Michael Hanselmann
        if remaining_time < 0.0:
130 b44b0141 Michael Hanselmann
          break
131 d76167a5 Michael Hanselmann
132 413b7472 Michael Hanselmann
        # Our calculation uses seconds, poll() wants milliseconds
133 b44b0141 Michael Hanselmann
        remaining_time *= 1000
134 d76167a5 Michael Hanselmann
135 d76167a5 Michael Hanselmann
      try:
136 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
137 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
138 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
139 d76167a5 Michael Hanselmann
          raise
140 d76167a5 Michael Hanselmann
        result = None
141 d76167a5 Michael Hanselmann
142 d76167a5 Michael Hanselmann
      # Check whether we were notified
143 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
144 d76167a5 Michael Hanselmann
        break
145 d76167a5 Michael Hanselmann
146 d76167a5 Michael Hanselmann
147 2419060d Guido Trotter
class _BaseCondition(object):
148 2419060d Guido Trotter
  """Base class containing common code for conditions.
149 2419060d Guido Trotter

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

152 2419060d Guido Trotter
  """
153 2419060d Guido Trotter
  __slots__ = [
154 2419060d Guido Trotter
    "_lock",
155 2419060d Guido Trotter
    "acquire",
156 2419060d Guido Trotter
    "release",
157 7f890059 Guido Trotter
    "_is_owned",
158 7f890059 Guido Trotter
    "_acquire_restore",
159 7f890059 Guido Trotter
    "_release_save",
160 2419060d Guido Trotter
    ]
161 2419060d Guido Trotter
162 2419060d Guido Trotter
  def __init__(self, lock):
163 2419060d Guido Trotter
    """Constructor for _BaseCondition.
164 2419060d Guido Trotter

165 69b99987 Michael Hanselmann
    @type lock: threading.Lock
166 2419060d Guido Trotter
    @param lock: condition base lock
167 2419060d Guido Trotter

168 2419060d Guido Trotter
    """
169 2419060d Guido Trotter
    object.__init__(self)
170 2419060d Guido Trotter
171 7f890059 Guido Trotter
    try:
172 7f890059 Guido Trotter
      self._release_save = lock._release_save
173 7f890059 Guido Trotter
    except AttributeError:
174 7f890059 Guido Trotter
      self._release_save = self._base_release_save
175 7f890059 Guido Trotter
    try:
176 7f890059 Guido Trotter
      self._acquire_restore = lock._acquire_restore
177 7f890059 Guido Trotter
    except AttributeError:
178 7f890059 Guido Trotter
      self._acquire_restore = self._base_acquire_restore
179 7f890059 Guido Trotter
    try:
180 ee2b99e3 Michael Hanselmann
      self._is_owned = lock.is_owned
181 7f890059 Guido Trotter
    except AttributeError:
182 7f890059 Guido Trotter
      self._is_owned = self._base_is_owned
183 2419060d Guido Trotter
184 2419060d Guido Trotter
    self._lock = lock
185 2419060d Guido Trotter
186 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
187 2419060d Guido Trotter
    self.acquire = lock.acquire
188 2419060d Guido Trotter
    self.release = lock.release
189 2419060d Guido Trotter
190 7f890059 Guido Trotter
  def _base_is_owned(self):
191 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
192 2419060d Guido Trotter

193 2419060d Guido Trotter
    """
194 2419060d Guido Trotter
    if self._lock.acquire(0):
195 2419060d Guido Trotter
      self._lock.release()
196 2419060d Guido Trotter
      return False
197 2419060d Guido Trotter
    return True
198 2419060d Guido Trotter
199 7f890059 Guido Trotter
  def _base_release_save(self):
200 7f890059 Guido Trotter
    self._lock.release()
201 7f890059 Guido Trotter
202 7f890059 Guido Trotter
  def _base_acquire_restore(self, _):
203 7f890059 Guido Trotter
    self._lock.acquire()
204 7f890059 Guido Trotter
205 2419060d Guido Trotter
  def _check_owned(self):
206 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
207 2419060d Guido Trotter

208 2419060d Guido Trotter
    """
209 2419060d Guido Trotter
    if not self._is_owned():
210 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
211 2419060d Guido Trotter
212 2419060d Guido Trotter
213 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
214 34cb5617 Guido Trotter
  """Condition which can only be notified once.
215 d76167a5 Michael Hanselmann

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

222 d76167a5 Michael Hanselmann
  """
223 34cb5617 Guido Trotter
224 154b9580 Balazs Lecz
  __slots__ = [
225 d76167a5 Michael Hanselmann
    "_poller",
226 d76167a5 Michael Hanselmann
    "_read_fd",
227 d76167a5 Michael Hanselmann
    "_write_fd",
228 d76167a5 Michael Hanselmann
    "_nwaiters",
229 34cb5617 Guido Trotter
    "_notified",
230 d76167a5 Michael Hanselmann
    ]
231 d76167a5 Michael Hanselmann
232 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
233 d76167a5 Michael Hanselmann
234 34cb5617 Guido Trotter
  def __init__(self, lock):
235 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
236 d76167a5 Michael Hanselmann

237 d76167a5 Michael Hanselmann
    """
238 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
239 d76167a5 Michael Hanselmann
    self._nwaiters = 0
240 34cb5617 Guido Trotter
    self._notified = False
241 34cb5617 Guido Trotter
    self._read_fd = None
242 34cb5617 Guido Trotter
    self._write_fd = None
243 34cb5617 Guido Trotter
    self._poller = None
244 d76167a5 Michael Hanselmann
245 34cb5617 Guido Trotter
  def _check_unnotified(self):
246 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
247 69b99987 Michael Hanselmann

248 69b99987 Michael Hanselmann
    """
249 34cb5617 Guido Trotter
    if self._notified:
250 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
251 d76167a5 Michael Hanselmann
252 34cb5617 Guido Trotter
  def _Cleanup(self):
253 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
254 d76167a5 Michael Hanselmann

255 d76167a5 Michael Hanselmann
    """
256 34cb5617 Guido Trotter
    if self._read_fd is not None:
257 34cb5617 Guido Trotter
      os.close(self._read_fd)
258 34cb5617 Guido Trotter
      self._read_fd = None
259 d76167a5 Michael Hanselmann
260 34cb5617 Guido Trotter
    if self._write_fd is not None:
261 34cb5617 Guido Trotter
      os.close(self._write_fd)
262 34cb5617 Guido Trotter
      self._write_fd = None
263 34cb5617 Guido Trotter
    self._poller = None
264 d76167a5 Michael Hanselmann
265 83f2d5f6 Michael Hanselmann
  def wait(self, timeout):
266 34cb5617 Guido Trotter
    """Wait for a notification.
267 d76167a5 Michael Hanselmann

268 34cb5617 Guido Trotter
    @type timeout: float or None
269 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
270 d76167a5 Michael Hanselmann

271 d76167a5 Michael Hanselmann
    """
272 34cb5617 Guido Trotter
    self._check_owned()
273 34cb5617 Guido Trotter
    self._check_unnotified()
274 d76167a5 Michael Hanselmann
275 34cb5617 Guido Trotter
    self._nwaiters += 1
276 34cb5617 Guido Trotter
    try:
277 34cb5617 Guido Trotter
      if self._poller is None:
278 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
279 34cb5617 Guido Trotter
        self._poller = select.poll()
280 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
281 d76167a5 Michael Hanselmann
282 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
283 7f890059 Guido Trotter
      state = self._release_save()
284 34cb5617 Guido Trotter
      try:
285 34cb5617 Guido Trotter
        # Wait for notification
286 34cb5617 Guido Trotter
        wait_fn(timeout)
287 34cb5617 Guido Trotter
      finally:
288 34cb5617 Guido Trotter
        # Re-acquire lock
289 7f890059 Guido Trotter
        self._acquire_restore(state)
290 34cb5617 Guido Trotter
    finally:
291 34cb5617 Guido Trotter
      self._nwaiters -= 1
292 34cb5617 Guido Trotter
      if self._nwaiters == 0:
293 34cb5617 Guido Trotter
        self._Cleanup()
294 d76167a5 Michael Hanselmann
295 b459a848 Andrea Spadaccini
  def notifyAll(self): # pylint: disable=C0103
296 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
297 d76167a5 Michael Hanselmann

298 d76167a5 Michael Hanselmann
    """
299 34cb5617 Guido Trotter
    self._check_owned()
300 34cb5617 Guido Trotter
    self._check_unnotified()
301 34cb5617 Guido Trotter
    self._notified = True
302 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
303 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
304 d76167a5 Michael Hanselmann
      self._write_fd = None
305 d76167a5 Michael Hanselmann
306 d76167a5 Michael Hanselmann
307 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
308 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
309 48dabc6a Michael Hanselmann

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

316 48dabc6a Michael Hanselmann
  """
317 154b9580 Balazs Lecz
  __slots__ = [
318 c31825f7 Michael Hanselmann
    "_waiters",
319 34cb5617 Guido Trotter
    "_single_condition",
320 48dabc6a Michael Hanselmann
    ]
321 48dabc6a Michael Hanselmann
322 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
323 48dabc6a Michael Hanselmann
324 48dabc6a Michael Hanselmann
  def __init__(self, lock):
325 48dabc6a Michael Hanselmann
    """Initializes this class.
326 48dabc6a Michael Hanselmann

327 48dabc6a Michael Hanselmann
    """
328 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
329 c31825f7 Michael Hanselmann
    self._waiters = set()
330 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
331 48dabc6a Michael Hanselmann
332 83f2d5f6 Michael Hanselmann
  def wait(self, timeout):
333 48dabc6a Michael Hanselmann
    """Wait for a notification.
334 48dabc6a Michael Hanselmann

335 48dabc6a Michael Hanselmann
    @type timeout: float or None
336 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
337 48dabc6a Michael Hanselmann

338 48dabc6a Michael Hanselmann
    """
339 48dabc6a Michael Hanselmann
    self._check_owned()
340 48dabc6a Michael Hanselmann
341 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
342 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
343 c31825f7 Michael Hanselmann
    cond = self._single_condition
344 48dabc6a Michael Hanselmann
345 c31825f7 Michael Hanselmann
    self._waiters.add(threading.currentThread())
346 48dabc6a Michael Hanselmann
    try:
347 c31825f7 Michael Hanselmann
      cond.wait(timeout)
348 48dabc6a Michael Hanselmann
    finally:
349 c31825f7 Michael Hanselmann
      self._check_owned()
350 c31825f7 Michael Hanselmann
      self._waiters.remove(threading.currentThread())
351 48dabc6a Michael Hanselmann
352 b459a848 Andrea Spadaccini
  def notifyAll(self): # pylint: disable=C0103
353 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
354 48dabc6a Michael Hanselmann

355 48dabc6a Michael Hanselmann
    """
356 48dabc6a Michael Hanselmann
    self._check_owned()
357 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
358 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
359 48dabc6a Michael Hanselmann
360 c31825f7 Michael Hanselmann
  def get_waiting(self):
361 c31825f7 Michael Hanselmann
    """Returns a list of all waiting threads.
362 c31825f7 Michael Hanselmann

363 c31825f7 Michael Hanselmann
    """
364 c31825f7 Michael Hanselmann
    self._check_owned()
365 c31825f7 Michael Hanselmann
366 c31825f7 Michael Hanselmann
    return self._waiters
367 c31825f7 Michael Hanselmann
368 48dabc6a Michael Hanselmann
  def has_waiting(self):
369 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
370 48dabc6a Michael Hanselmann

371 48dabc6a Michael Hanselmann
    """
372 48dabc6a Michael Hanselmann
    self._check_owned()
373 48dabc6a Michael Hanselmann
374 c31825f7 Michael Hanselmann
    return bool(self._waiters)
375 48dabc6a Michael Hanselmann
376 20699809 Michael Hanselmann
  def __repr__(self):
377 20699809 Michael Hanselmann
    return ("<%s.%s waiters=%s at %#x>" %
378 20699809 Michael Hanselmann
            (self.__class__.__module__, self.__class__.__name__,
379 20699809 Michael Hanselmann
             self._waiters, id(self)))
380 20699809 Michael Hanselmann
381 48dabc6a Michael Hanselmann
382 887c7aa6 Michael Hanselmann
class _PipeConditionWithMode(PipeCondition):
383 887c7aa6 Michael Hanselmann
  __slots__ = [
384 887c7aa6 Michael Hanselmann
    "shared",
385 887c7aa6 Michael Hanselmann
    ]
386 887c7aa6 Michael Hanselmann
387 887c7aa6 Michael Hanselmann
  def __init__(self, lock, shared):
388 887c7aa6 Michael Hanselmann
    """Initializes this class.
389 887c7aa6 Michael Hanselmann

390 887c7aa6 Michael Hanselmann
    """
391 887c7aa6 Michael Hanselmann
    self.shared = shared
392 887c7aa6 Michael Hanselmann
    PipeCondition.__init__(self, lock)
393 887c7aa6 Michael Hanselmann
394 887c7aa6 Michael Hanselmann
395 84e344d4 Michael Hanselmann
class SharedLock(object):
396 162c1c1f Guido Trotter
  """Implements a shared lock.
397 162c1c1f Guido Trotter

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

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

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

413 162c1c1f Guido Trotter
  """
414 84e344d4 Michael Hanselmann
  __slots__ = [
415 19b9ba9a Michael Hanselmann
    "__weakref__",
416 84e344d4 Michael Hanselmann
    "__deleted",
417 84e344d4 Michael Hanselmann
    "__exc",
418 84e344d4 Michael Hanselmann
    "__lock",
419 84e344d4 Michael Hanselmann
    "__pending",
420 887c7aa6 Michael Hanselmann
    "__pending_by_prio",
421 887c7aa6 Michael Hanselmann
    "__pending_shared",
422 84e344d4 Michael Hanselmann
    "__shr",
423 8d7d8b57 Michael Hanselmann
    "__time_fn",
424 7f93570a Iustin Pop
    "name",
425 84e344d4 Michael Hanselmann
    ]
426 84e344d4 Michael Hanselmann
427 887c7aa6 Michael Hanselmann
  __condition_class = _PipeConditionWithMode
428 84e344d4 Michael Hanselmann
429 8d7d8b57 Michael Hanselmann
  def __init__(self, name, monitor=None, _time_fn=time.time):
430 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
431 84e344d4 Michael Hanselmann

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

436 84e344d4 Michael Hanselmann
    """
437 84e344d4 Michael Hanselmann
    object.__init__(self)
438 84e344d4 Michael Hanselmann
439 7f93570a Iustin Pop
    self.name = name
440 7f93570a Iustin Pop
441 8d7d8b57 Michael Hanselmann
    # Used for unittesting
442 8d7d8b57 Michael Hanselmann
    self.__time_fn = _time_fn
443 8d7d8b57 Michael Hanselmann
444 84e344d4 Michael Hanselmann
    # Internal lock
445 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
446 162c1c1f Guido Trotter
447 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
448 84e344d4 Michael Hanselmann
    self.__pending = []
449 887c7aa6 Michael Hanselmann
    self.__pending_by_prio = {}
450 887c7aa6 Michael Hanselmann
    self.__pending_shared = {}
451 84e344d4 Michael Hanselmann
452 84e344d4 Michael Hanselmann
    # Current lock holders
453 162c1c1f Guido Trotter
    self.__shr = set()
454 162c1c1f Guido Trotter
    self.__exc = None
455 162c1c1f Guido Trotter
456 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
457 a95fd5d7 Guido Trotter
    self.__deleted = False
458 a95fd5d7 Guido Trotter
459 19b9ba9a Michael Hanselmann
    # Register with lock monitor
460 19b9ba9a Michael Hanselmann
    if monitor:
461 44b4eddc Michael Hanselmann
      logging.debug("Adding lock %s to monitor", name)
462 19b9ba9a Michael Hanselmann
      monitor.RegisterLock(self)
463 19b9ba9a Michael Hanselmann
464 20699809 Michael Hanselmann
  def __repr__(self):
465 20699809 Michael Hanselmann
    return ("<%s.%s name=%s at %#x>" %
466 20699809 Michael Hanselmann
            (self.__class__.__module__, self.__class__.__name__,
467 20699809 Michael Hanselmann
             self.name, id(self)))
468 20699809 Michael Hanselmann
469 44b4eddc Michael Hanselmann
  def GetLockInfo(self, requested):
470 19b9ba9a Michael Hanselmann
    """Retrieves information for querying locks.
471 19b9ba9a Michael Hanselmann

472 24d16f76 Michael Hanselmann
    @type requested: set
473 24d16f76 Michael Hanselmann
    @param requested: Requested information, see C{query.LQ_*}
474 19b9ba9a Michael Hanselmann

475 19b9ba9a Michael Hanselmann
    """
476 19b9ba9a Michael Hanselmann
    self.__lock.acquire()
477 19b9ba9a Michael Hanselmann
    try:
478 19b9ba9a Michael Hanselmann
      # Note: to avoid unintentional race conditions, no references to
479 19b9ba9a Michael Hanselmann
      # modifiable objects should be returned unless they were created in this
480 19b9ba9a Michael Hanselmann
      # function.
481 24d16f76 Michael Hanselmann
      mode = None
482 24d16f76 Michael Hanselmann
      owner_names = None
483 24d16f76 Michael Hanselmann
484 24d16f76 Michael Hanselmann
      if query.LQ_MODE in requested:
485 24d16f76 Michael Hanselmann
        if self.__deleted:
486 24d16f76 Michael Hanselmann
          mode = _DELETED_TEXT
487 24d16f76 Michael Hanselmann
          assert not (self.__exc or self.__shr)
488 24d16f76 Michael Hanselmann
        elif self.__exc:
489 24d16f76 Michael Hanselmann
          mode = _EXCLUSIVE_TEXT
490 24d16f76 Michael Hanselmann
        elif self.__shr:
491 24d16f76 Michael Hanselmann
          mode = _SHARED_TEXT
492 24d16f76 Michael Hanselmann
493 24d16f76 Michael Hanselmann
      # Current owner(s) are wanted
494 24d16f76 Michael Hanselmann
      if query.LQ_OWNER in requested:
495 24d16f76 Michael Hanselmann
        if self.__exc:
496 24d16f76 Michael Hanselmann
          owner = [self.__exc]
497 19b9ba9a Michael Hanselmann
        else:
498 24d16f76 Michael Hanselmann
          owner = self.__shr
499 24d16f76 Michael Hanselmann
500 24d16f76 Michael Hanselmann
        if owner:
501 24d16f76 Michael Hanselmann
          assert not self.__deleted
502 24d16f76 Michael Hanselmann
          owner_names = [i.getName() for i in owner]
503 19b9ba9a Michael Hanselmann
504 24d16f76 Michael Hanselmann
      # Pending acquires are wanted
505 24d16f76 Michael Hanselmann
      if query.LQ_PENDING in requested:
506 24d16f76 Michael Hanselmann
        pending = []
507 24d16f76 Michael Hanselmann
508 24d16f76 Michael Hanselmann
        # Sorting instead of copying and using heaq functions for simplicity
509 24d16f76 Michael Hanselmann
        for (_, prioqueue) in sorted(self.__pending):
510 24d16f76 Michael Hanselmann
          for cond in prioqueue:
511 24d16f76 Michael Hanselmann
            if cond.shared:
512 24d16f76 Michael Hanselmann
              pendmode = _SHARED_TEXT
513 24d16f76 Michael Hanselmann
            else:
514 24d16f76 Michael Hanselmann
              pendmode = _EXCLUSIVE_TEXT
515 24d16f76 Michael Hanselmann
516 24d16f76 Michael Hanselmann
            # List of names will be sorted in L{query._GetLockPending}
517 24d16f76 Michael Hanselmann
            pending.append((pendmode, [i.getName()
518 24d16f76 Michael Hanselmann
                                       for i in cond.get_waiting()]))
519 24d16f76 Michael Hanselmann
      else:
520 24d16f76 Michael Hanselmann
        pending = None
521 24d16f76 Michael Hanselmann
522 44b4eddc Michael Hanselmann
      return [(self.name, mode, owner_names, pending)]
523 19b9ba9a Michael Hanselmann
    finally:
524 19b9ba9a Michael Hanselmann
      self.__lock.release()
525 19b9ba9a Michael Hanselmann
526 84e344d4 Michael Hanselmann
  def __check_deleted(self):
527 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
528 84e344d4 Michael Hanselmann

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

536 84e344d4 Michael Hanselmann
    """
537 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
538 162c1c1f Guido Trotter
539 162c1c1f Guido Trotter
  def __is_exclusive(self):
540 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
541 84e344d4 Michael Hanselmann

542 84e344d4 Michael Hanselmann
    """
543 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
544 162c1c1f Guido Trotter
545 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
546 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
547 162c1c1f Guido Trotter

548 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
549 162c1c1f Guido Trotter
    the internal lock.
550 162c1c1f Guido Trotter

551 162c1c1f Guido Trotter
    """
552 162c1c1f Guido Trotter
    if shared < 0:
553 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
554 162c1c1f Guido Trotter
    elif shared:
555 162c1c1f Guido Trotter
      return self.__is_sharer()
556 162c1c1f Guido Trotter
    else:
557 162c1c1f Guido Trotter
      return self.__is_exclusive()
558 162c1c1f Guido Trotter
559 ee2b99e3 Michael Hanselmann
  def is_owned(self, shared=-1):
560 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
561 162c1c1f Guido Trotter

562 c41eea6e Iustin Pop
    @param shared:
563 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
564 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
565 c41eea6e Iustin Pop
        - > 0: check for shared ownership
566 162c1c1f Guido Trotter

567 162c1c1f Guido Trotter
    """
568 162c1c1f Guido Trotter
    self.__lock.acquire()
569 162c1c1f Guido Trotter
    try:
570 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
571 162c1c1f Guido Trotter
    finally:
572 162c1c1f Guido Trotter
      self.__lock.release()
573 162c1c1f Guido Trotter
574 ee2b99e3 Michael Hanselmann
  #: Necessary to remain compatible with threading.Condition, which tries to
575 ee2b99e3 Michael Hanselmann
  #: retrieve a locks' "_is_owned" attribute
576 ee2b99e3 Michael Hanselmann
  _is_owned = is_owned
577 fdfe88b1 Michael Hanselmann
578 84e344d4 Michael Hanselmann
  def _count_pending(self):
579 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
580 a95fd5d7 Guido Trotter

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

583 a95fd5d7 Guido Trotter
    """
584 84e344d4 Michael Hanselmann
    self.__lock.acquire()
585 84e344d4 Michael Hanselmann
    try:
586 887c7aa6 Michael Hanselmann
      return sum(len(prioqueue) for (_, prioqueue) in self.__pending)
587 887c7aa6 Michael Hanselmann
    finally:
588 887c7aa6 Michael Hanselmann
      self.__lock.release()
589 887c7aa6 Michael Hanselmann
590 887c7aa6 Michael Hanselmann
  def _check_empty(self):
591 887c7aa6 Michael Hanselmann
    """Checks whether there are any pending acquires.
592 887c7aa6 Michael Hanselmann

593 887c7aa6 Michael Hanselmann
    @rtype: bool
594 887c7aa6 Michael Hanselmann

595 887c7aa6 Michael Hanselmann
    """
596 887c7aa6 Michael Hanselmann
    self.__lock.acquire()
597 887c7aa6 Michael Hanselmann
    try:
598 887c7aa6 Michael Hanselmann
      # Order is important: __find_first_pending_queue modifies __pending
599 113359fe Michael Hanselmann
      (_, prioqueue) = self.__find_first_pending_queue()
600 113359fe Michael Hanselmann
601 113359fe Michael Hanselmann
      return not (prioqueue or
602 887c7aa6 Michael Hanselmann
                  self.__pending or
603 887c7aa6 Michael Hanselmann
                  self.__pending_by_prio or
604 887c7aa6 Michael Hanselmann
                  self.__pending_shared)
605 84e344d4 Michael Hanselmann
    finally:
606 84e344d4 Michael Hanselmann
      self.__lock.release()
607 a95fd5d7 Guido Trotter
608 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
609 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
610 84e344d4 Michael Hanselmann

611 84e344d4 Michael Hanselmann
    """
612 84e344d4 Michael Hanselmann
    if shared:
613 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
614 84e344d4 Michael Hanselmann
    else:
615 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
616 a95fd5d7 Guido Trotter
617 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
618 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
619 a95fd5d7 Guido Trotter

620 a95fd5d7 Guido Trotter
    """
621 84e344d4 Michael Hanselmann
    if shared:
622 84e344d4 Michael Hanselmann
      return self.__exc is None
623 84e344d4 Michael Hanselmann
    else:
624 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
625 a95fd5d7 Guido Trotter
626 887c7aa6 Michael Hanselmann
  def __find_first_pending_queue(self):
627 887c7aa6 Michael Hanselmann
    """Tries to find the topmost queued entry with pending acquires.
628 887c7aa6 Michael Hanselmann

629 887c7aa6 Michael Hanselmann
    Removes empty entries while going through the list.
630 887c7aa6 Michael Hanselmann

631 887c7aa6 Michael Hanselmann
    """
632 887c7aa6 Michael Hanselmann
    while self.__pending:
633 887c7aa6 Michael Hanselmann
      (priority, prioqueue) = self.__pending[0]
634 887c7aa6 Michael Hanselmann
635 887c7aa6 Michael Hanselmann
      if prioqueue:
636 113359fe Michael Hanselmann
        return (priority, prioqueue)
637 887c7aa6 Michael Hanselmann
638 113359fe Michael Hanselmann
      # Remove empty queue
639 113359fe Michael Hanselmann
      heapq.heappop(self.__pending)
640 113359fe Michael Hanselmann
      del self.__pending_by_prio[priority]
641 113359fe Michael Hanselmann
      assert priority not in self.__pending_shared
642 113359fe Michael Hanselmann
643 113359fe Michael Hanselmann
    return (None, None)
644 887c7aa6 Michael Hanselmann
645 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
646 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
647 a95fd5d7 Guido Trotter

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

650 84e344d4 Michael Hanselmann
    """
651 113359fe Michael Hanselmann
    (_, prioqueue) = self.__find_first_pending_queue()
652 113359fe Michael Hanselmann
653 113359fe Michael Hanselmann
    return cond == prioqueue[0]
654 4d686df8 Guido Trotter
655 887c7aa6 Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout, priority):
656 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
657 9216a9f7 Michael Hanselmann

658 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
659 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
660 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
661 887c7aa6 Michael Hanselmann
    @type priority: integer
662 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
663 9216a9f7 Michael Hanselmann

664 9216a9f7 Michael Hanselmann
    """
665 84e344d4 Michael Hanselmann
    self.__check_deleted()
666 9216a9f7 Michael Hanselmann
667 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
668 7f93570a Iustin Pop
    assert not self.__is_owned(), ("double acquire() on a non-recursive lock"
669 7f93570a Iustin Pop
                                   " %s" % self.name)
670 84e344d4 Michael Hanselmann
671 887c7aa6 Michael Hanselmann
    # Remove empty entries from queue
672 887c7aa6 Michael Hanselmann
    self.__find_first_pending_queue()
673 887c7aa6 Michael Hanselmann
674 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
675 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
676 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
677 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
678 84e344d4 Michael Hanselmann
      return True
679 9216a9f7 Michael Hanselmann
680 03c5291c Michael Hanselmann
    # The lock couldn't be acquired right away, so if a timeout is given and is
681 03c5291c Michael Hanselmann
    # considered too short, return right away as scheduling a pending
682 03c5291c Michael Hanselmann
    # acquisition is quite expensive
683 03c5291c Michael Hanselmann
    if timeout is not None and timeout < _LOCK_ACQUIRE_MIN_TIMEOUT:
684 03c5291c Michael Hanselmann
      return False
685 03c5291c Michael Hanselmann
686 887c7aa6 Michael Hanselmann
    prioqueue = self.__pending_by_prio.get(priority, None)
687 9216a9f7 Michael Hanselmann
688 887c7aa6 Michael Hanselmann
    if shared:
689 887c7aa6 Michael Hanselmann
      # Try to re-use condition for shared acquire
690 887c7aa6 Michael Hanselmann
      wait_condition = self.__pending_shared.get(priority, None)
691 887c7aa6 Michael Hanselmann
      assert (wait_condition is None or
692 887c7aa6 Michael Hanselmann
              (wait_condition.shared and wait_condition in prioqueue))
693 84e344d4 Michael Hanselmann
    else:
694 887c7aa6 Michael Hanselmann
      wait_condition = None
695 887c7aa6 Michael Hanselmann
696 887c7aa6 Michael Hanselmann
    if wait_condition is None:
697 887c7aa6 Michael Hanselmann
      if prioqueue is None:
698 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_by_prio
699 887c7aa6 Michael Hanselmann
700 887c7aa6 Michael Hanselmann
        prioqueue = []
701 887c7aa6 Michael Hanselmann
        heapq.heappush(self.__pending, (priority, prioqueue))
702 887c7aa6 Michael Hanselmann
        self.__pending_by_prio[priority] = prioqueue
703 887c7aa6 Michael Hanselmann
704 887c7aa6 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock, shared)
705 887c7aa6 Michael Hanselmann
      prioqueue.append(wait_condition)
706 887c7aa6 Michael Hanselmann
707 887c7aa6 Michael Hanselmann
      if shared:
708 887c7aa6 Michael Hanselmann
        # Keep reference for further shared acquires on same priority. This is
709 887c7aa6 Michael Hanselmann
        # better than trying to find it in the list of pending acquires.
710 887c7aa6 Michael Hanselmann
        assert priority not in self.__pending_shared
711 887c7aa6 Michael Hanselmann
        self.__pending_shared[priority] = wait_condition
712 84e344d4 Michael Hanselmann
713 8d7d8b57 Michael Hanselmann
    wait_start = self.__time_fn()
714 8d7d8b57 Michael Hanselmann
    acquired = False
715 8d7d8b57 Michael Hanselmann
716 84e344d4 Michael Hanselmann
    try:
717 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
718 84e344d4 Michael Hanselmann
      # expires.
719 8d7d8b57 Michael Hanselmann
      while True:
720 8d7d8b57 Michael Hanselmann
        if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
721 8d7d8b57 Michael Hanselmann
          self.__do_acquire(shared)
722 8d7d8b57 Michael Hanselmann
          acquired = True
723 8d7d8b57 Michael Hanselmann
          break
724 84e344d4 Michael Hanselmann
725 8d7d8b57 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed, therefore we
726 8d7d8b57 Michael Hanselmann
        # can never return False for a blocking acquire
727 8d7d8b57 Michael Hanselmann
        if (timeout is not None and
728 8d7d8b57 Michael Hanselmann
            utils.TimeoutExpired(wait_start, timeout, _time_fn=self.__time_fn)):
729 84e344d4 Michael Hanselmann
          break
730 84e344d4 Michael Hanselmann
731 8d7d8b57 Michael Hanselmann
        # Wait for notification
732 8d7d8b57 Michael Hanselmann
        wait_condition.wait(timeout)
733 8d7d8b57 Michael Hanselmann
        self.__check_deleted()
734 9216a9f7 Michael Hanselmann
    finally:
735 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
736 887c7aa6 Michael Hanselmann
      if not wait_condition.has_waiting():
737 887c7aa6 Michael Hanselmann
        prioqueue.remove(wait_condition)
738 887c7aa6 Michael Hanselmann
        if wait_condition.shared:
739 113359fe Michael Hanselmann
          # Remove from list of shared acquires if it wasn't while releasing
740 113359fe Michael Hanselmann
          # (e.g. on lock deletion)
741 113359fe Michael Hanselmann
          self.__pending_shared.pop(priority, None)
742 9216a9f7 Michael Hanselmann
743 8d7d8b57 Michael Hanselmann
    return acquired
744 9216a9f7 Michael Hanselmann
745 7100c2fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, priority=None,
746 887c7aa6 Michael Hanselmann
              test_notify=None):
747 162c1c1f Guido Trotter
    """Acquire a shared lock.
748 162c1c1f Guido Trotter

749 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
750 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
751 c41eea6e Iustin Pop
        exclusive lock will be acquired
752 84e344d4 Michael Hanselmann
    @type timeout: float
753 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
754 887c7aa6 Michael Hanselmann
    @type priority: integer
755 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
756 008b92fa Michael Hanselmann
    @type test_notify: callable or None
757 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
758 162c1c1f Guido Trotter

759 162c1c1f Guido Trotter
    """
760 7100c2fa Michael Hanselmann
    if priority is None:
761 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
762 7100c2fa Michael Hanselmann
763 162c1c1f Guido Trotter
    self.__lock.acquire()
764 162c1c1f Guido Trotter
    try:
765 008b92fa Michael Hanselmann
      # We already got the lock, notify now
766 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
767 008b92fa Michael Hanselmann
        test_notify()
768 008b92fa Michael Hanselmann
769 887c7aa6 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout, priority)
770 162c1c1f Guido Trotter
    finally:
771 162c1c1f Guido Trotter
      self.__lock.release()
772 162c1c1f Guido Trotter
773 3dbe3ddf Michael Hanselmann
  def downgrade(self):
774 3dbe3ddf Michael Hanselmann
    """Changes the lock mode from exclusive to shared.
775 3dbe3ddf Michael Hanselmann

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

778 3dbe3ddf Michael Hanselmann
    """
779 3dbe3ddf Michael Hanselmann
    self.__lock.acquire()
780 3dbe3ddf Michael Hanselmann
    try:
781 3dbe3ddf Michael Hanselmann
      assert self.__is_owned(), "Lock must be owned"
782 3dbe3ddf Michael Hanselmann
783 3dbe3ddf Michael Hanselmann
      if self.__is_exclusive():
784 3dbe3ddf Michael Hanselmann
        # Do nothing if the lock is already acquired in shared mode
785 3dbe3ddf Michael Hanselmann
        self.__exc = None
786 3dbe3ddf Michael Hanselmann
        self.__do_acquire(1)
787 3dbe3ddf Michael Hanselmann
788 3dbe3ddf Michael Hanselmann
        # Important: pending shared acquires should only jump ahead if there
789 3dbe3ddf Michael Hanselmann
        # was a transition from exclusive to shared, otherwise an owner of a
790 3dbe3ddf Michael Hanselmann
        # shared lock can keep calling this function to push incoming shared
791 3dbe3ddf Michael Hanselmann
        # acquires
792 3dbe3ddf Michael Hanselmann
        (priority, prioqueue) = self.__find_first_pending_queue()
793 3dbe3ddf Michael Hanselmann
        if prioqueue:
794 3dbe3ddf Michael Hanselmann
          # Is there a pending shared acquire on this priority?
795 3dbe3ddf Michael Hanselmann
          cond = self.__pending_shared.pop(priority, None)
796 3dbe3ddf Michael Hanselmann
          if cond:
797 3dbe3ddf Michael Hanselmann
            assert cond.shared
798 3dbe3ddf Michael Hanselmann
            assert cond in prioqueue
799 3dbe3ddf Michael Hanselmann
800 3dbe3ddf Michael Hanselmann
            # Ensure shared acquire is on top of queue
801 3dbe3ddf Michael Hanselmann
            if len(prioqueue) > 1:
802 3dbe3ddf Michael Hanselmann
              prioqueue.remove(cond)
803 3dbe3ddf Michael Hanselmann
              prioqueue.insert(0, cond)
804 3dbe3ddf Michael Hanselmann
805 3dbe3ddf Michael Hanselmann
            # Notify
806 3dbe3ddf Michael Hanselmann
            cond.notifyAll()
807 3dbe3ddf Michael Hanselmann
808 3dbe3ddf Michael Hanselmann
      assert not self.__is_exclusive()
809 3dbe3ddf Michael Hanselmann
      assert self.__is_sharer()
810 3dbe3ddf Michael Hanselmann
811 3dbe3ddf Michael Hanselmann
      return True
812 3dbe3ddf Michael Hanselmann
    finally:
813 3dbe3ddf Michael Hanselmann
      self.__lock.release()
814 3dbe3ddf Michael Hanselmann
815 162c1c1f Guido Trotter
  def release(self):
816 162c1c1f Guido Trotter
    """Release a Shared Lock.
817 162c1c1f Guido Trotter

818 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
819 162c1c1f Guido Trotter
    before calling this function.
820 162c1c1f Guido Trotter

821 162c1c1f Guido Trotter
    """
822 162c1c1f Guido Trotter
    self.__lock.acquire()
823 162c1c1f Guido Trotter
    try:
824 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
825 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
826 84e344d4 Michael Hanselmann
827 162c1c1f Guido Trotter
      # Autodetect release type
828 162c1c1f Guido Trotter
      if self.__is_exclusive():
829 162c1c1f Guido Trotter
        self.__exc = None
830 70567db0 Michael Hanselmann
        notify = True
831 84e344d4 Michael Hanselmann
      else:
832 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
833 70567db0 Michael Hanselmann
        notify = not self.__shr
834 162c1c1f Guido Trotter
835 70567db0 Michael Hanselmann
      # Notify topmost condition in queue if there are no owners left (for
836 70567db0 Michael Hanselmann
      # shared locks)
837 70567db0 Michael Hanselmann
      if notify:
838 70567db0 Michael Hanselmann
        self.__notify_topmost()
839 8d7d8b57 Michael Hanselmann
    finally:
840 8d7d8b57 Michael Hanselmann
      self.__lock.release()
841 8d7d8b57 Michael Hanselmann
842 8d7d8b57 Michael Hanselmann
  def __notify_topmost(self):
843 8d7d8b57 Michael Hanselmann
    """Notifies topmost condition in queue of pending acquires.
844 8d7d8b57 Michael Hanselmann

845 8d7d8b57 Michael Hanselmann
    """
846 8d7d8b57 Michael Hanselmann
    (priority, prioqueue) = self.__find_first_pending_queue()
847 8d7d8b57 Michael Hanselmann
    if prioqueue:
848 8d7d8b57 Michael Hanselmann
      cond = prioqueue[0]
849 8d7d8b57 Michael Hanselmann
      cond.notifyAll()
850 8d7d8b57 Michael Hanselmann
      if cond.shared:
851 8d7d8b57 Michael Hanselmann
        # Prevent further shared acquires from sneaking in while waiters are
852 8d7d8b57 Michael Hanselmann
        # notified
853 8d7d8b57 Michael Hanselmann
        self.__pending_shared.pop(priority, None)
854 8d7d8b57 Michael Hanselmann
855 8d7d8b57 Michael Hanselmann
  def _notify_topmost(self):
856 8d7d8b57 Michael Hanselmann
    """Exported version of L{__notify_topmost}.
857 162c1c1f Guido Trotter

858 8d7d8b57 Michael Hanselmann
    """
859 8d7d8b57 Michael Hanselmann
    self.__lock.acquire()
860 8d7d8b57 Michael Hanselmann
    try:
861 8d7d8b57 Michael Hanselmann
      return self.__notify_topmost()
862 162c1c1f Guido Trotter
    finally:
863 162c1c1f Guido Trotter
      self.__lock.release()
864 162c1c1f Guido Trotter
865 7100c2fa Michael Hanselmann
  def delete(self, timeout=None, priority=None):
866 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
867 a95fd5d7 Guido Trotter

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

872 84e344d4 Michael Hanselmann
    @type timeout: float
873 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
874 887c7aa6 Michael Hanselmann
    @type priority: integer
875 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring lock
876 a95fd5d7 Guido Trotter

877 a95fd5d7 Guido Trotter
    """
878 7100c2fa Michael Hanselmann
    if priority is None:
879 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
880 7100c2fa Michael Hanselmann
881 a95fd5d7 Guido Trotter
    self.__lock.acquire()
882 a95fd5d7 Guido Trotter
    try:
883 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
884 84e344d4 Michael Hanselmann
885 84e344d4 Michael Hanselmann
      self.__check_deleted()
886 a95fd5d7 Guido Trotter
887 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
888 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
889 a95fd5d7 Guido Trotter
890 84e344d4 Michael Hanselmann
      if not acquired:
891 887c7aa6 Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout, priority)
892 a66bd91b Michael Hanselmann
893 26082b7e Michael Hanselmann
      if acquired:
894 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
895 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
896 84e344d4 Michael Hanselmann
897 84e344d4 Michael Hanselmann
        self.__deleted = True
898 84e344d4 Michael Hanselmann
        self.__exc = None
899 a95fd5d7 Guido Trotter
900 19b9ba9a Michael Hanselmann
        assert not (self.__exc or self.__shr), "Found owner during deletion"
901 19b9ba9a Michael Hanselmann
902 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
903 887c7aa6 Michael Hanselmann
        for (_, prioqueue) in self.__pending:
904 887c7aa6 Michael Hanselmann
          for cond in prioqueue:
905 887c7aa6 Michael Hanselmann
            cond.notifyAll()
906 887c7aa6 Michael Hanselmann
907 887c7aa6 Michael Hanselmann
        assert self.__deleted
908 a95fd5d7 Guido Trotter
909 84e344d4 Michael Hanselmann
      return acquired
910 a95fd5d7 Guido Trotter
    finally:
911 a95fd5d7 Guido Trotter
      self.__lock.release()
912 a95fd5d7 Guido Trotter
913 1a4e32d0 Guido Trotter
  def _release_save(self):
914 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
915 1a4e32d0 Guido Trotter
    self.release()
916 1a4e32d0 Guido Trotter
    return shared
917 1a4e32d0 Guido Trotter
918 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
919 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
920 1a4e32d0 Guido Trotter
921 aaae9bc0 Guido Trotter
922 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
923 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
924 e310b019 Guido Trotter
ALL_SET = None
925 e310b019 Guido Trotter
926 e310b019 Guido Trotter
927 a95c53ea Michael Hanselmann
def _TimeoutZero():
928 a95c53ea Michael Hanselmann
  """Returns the number zero.
929 a95c53ea Michael Hanselmann

930 a95c53ea Michael Hanselmann
  """
931 a95c53ea Michael Hanselmann
  return 0
932 a95c53ea Michael Hanselmann
933 a95c53ea Michael Hanselmann
934 a95c53ea Michael Hanselmann
def _GetLsAcquireModeAndTimeouts(want_all, timeout, opportunistic):
935 a95c53ea Michael Hanselmann
  """Determines modes and timeouts for L{LockSet.acquire}.
936 a95c53ea Michael Hanselmann

937 a95c53ea Michael Hanselmann
  @type want_all: boolean
938 a95c53ea Michael Hanselmann
  @param want_all: Whether all locks in set should be acquired
939 a95c53ea Michael Hanselmann
  @param timeout: Timeout in seconds or C{None}
940 a95c53ea Michael Hanselmann
  @param opportunistic: Whther locks should be acquired opportunistically
941 a95c53ea Michael Hanselmann
  @rtype: tuple
942 a95c53ea Michael Hanselmann
  @return: Tuple containing mode to be passed to L{LockSet.__acquire_inner}
943 a95c53ea Michael Hanselmann
    (one of L{_LS_ACQUIRE_MODES}), a function to calculate timeout for
944 a95c53ea Michael Hanselmann
    acquiring the lockset-internal lock (might be C{None}) and a function to
945 a95c53ea Michael Hanselmann
    calculate the timeout for acquiring individual locks
946 a95c53ea Michael Hanselmann

947 a95c53ea Michael Hanselmann
  """
948 a95c53ea Michael Hanselmann
  # Short circuit when no running timeout is needed
949 a95c53ea Michael Hanselmann
  if opportunistic and not want_all:
950 a95c53ea Michael Hanselmann
    assert timeout is None, "Got timeout for an opportunistic acquisition"
951 a95c53ea Michael Hanselmann
    return (_LS_ACQUIRE_OPPORTUNISTIC, None, _TimeoutZero)
952 a95c53ea Michael Hanselmann
953 a95c53ea Michael Hanselmann
  # We need to keep track of how long we spent waiting for a lock. The
954 a95c53ea Michael Hanselmann
  # timeout passed to this function is over all lock acquisitions.
955 a95c53ea Michael Hanselmann
  running_timeout = utils.RunningTimeout(timeout, False)
956 a95c53ea Michael Hanselmann
957 a95c53ea Michael Hanselmann
  if want_all:
958 a95c53ea Michael Hanselmann
    mode = _LS_ACQUIRE_ALL
959 a95c53ea Michael Hanselmann
    ls_timeout_fn = running_timeout.Remaining
960 a95c53ea Michael Hanselmann
  else:
961 a95c53ea Michael Hanselmann
    mode = _LS_ACQUIRE_EXACT
962 a95c53ea Michael Hanselmann
    ls_timeout_fn = None
963 a95c53ea Michael Hanselmann
964 a95c53ea Michael Hanselmann
  if opportunistic:
965 a95c53ea Michael Hanselmann
    mode = _LS_ACQUIRE_OPPORTUNISTIC
966 a95c53ea Michael Hanselmann
    timeout_fn = _TimeoutZero
967 a95c53ea Michael Hanselmann
  else:
968 a95c53ea Michael Hanselmann
    timeout_fn = running_timeout.Remaining
969 a95c53ea Michael Hanselmann
970 a95c53ea Michael Hanselmann
  return (mode, ls_timeout_fn, timeout_fn)
971 a95c53ea Michael Hanselmann
972 a95c53ea Michael Hanselmann
973 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
974 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
975 5aab242c Michael Hanselmann

976 5aab242c Michael Hanselmann
  """
977 5aab242c Michael Hanselmann
978 5aab242c Michael Hanselmann
979 aaae9bc0 Guido Trotter
class LockSet:
980 aaae9bc0 Guido Trotter
  """Implements a set of locks.
981 aaae9bc0 Guido Trotter

982 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
983 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
984 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
985 aaae9bc0 Guido Trotter
  preventing deadlock.
986 aaae9bc0 Guido Trotter

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

989 7f93570a Iustin Pop
  @type name: string
990 7f93570a Iustin Pop
  @ivar name: the name of the lockset
991 7f93570a Iustin Pop

992 aaae9bc0 Guido Trotter
  """
993 19b9ba9a Michael Hanselmann
  def __init__(self, members, name, monitor=None):
994 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
995 aaae9bc0 Guido Trotter

996 ec44d893 Guido Trotter
    @type members: list of strings
997 c41eea6e Iustin Pop
    @param members: initial members of the set
998 19b9ba9a Michael Hanselmann
    @type monitor: L{LockMonitor}
999 19b9ba9a Michael Hanselmann
    @param monitor: Lock monitor with which to register member locks
1000 aaae9bc0 Guido Trotter

1001 aaae9bc0 Guido Trotter
    """
1002 7f93570a Iustin Pop
    assert members is not None, "members parameter is not a list"
1003 7f93570a Iustin Pop
    self.name = name
1004 7f93570a Iustin Pop
1005 19b9ba9a Michael Hanselmann
    # Lock monitor
1006 19b9ba9a Michael Hanselmann
    self.__monitor = monitor
1007 19b9ba9a Michael Hanselmann
1008 c307ee34 Michael Hanselmann
    # Used internally to guarantee coherency
1009 c307ee34 Michael Hanselmann
    self.__lock = SharedLock(self._GetLockName("[lockset]"), monitor=monitor)
1010 aaae9bc0 Guido Trotter
1011 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
1012 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
1013 aaae9bc0 Guido Trotter
    self.__lockdict = {}
1014 aaae9bc0 Guido Trotter
1015 7f93570a Iustin Pop
    for mname in members:
1016 19b9ba9a Michael Hanselmann
      self.__lockdict[mname] = SharedLock(self._GetLockName(mname),
1017 19b9ba9a Michael Hanselmann
                                          monitor=monitor)
1018 aaae9bc0 Guido Trotter
1019 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
1020 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
1021 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
1022 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
1023 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
1024 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
1025 aaae9bc0 Guido Trotter
    # will be trouble.
1026 aaae9bc0 Guido Trotter
    self.__owners = {}
1027 aaae9bc0 Guido Trotter
1028 4fb780d1 Michael Hanselmann
  def _GetLockName(self, mname):
1029 4fb780d1 Michael Hanselmann
    """Returns the name for a member lock.
1030 4fb780d1 Michael Hanselmann

1031 4fb780d1 Michael Hanselmann
    """
1032 4fb780d1 Michael Hanselmann
    return "%s/%s" % (self.name, mname)
1033 4fb780d1 Michael Hanselmann
1034 3dbe3ddf Michael Hanselmann
  def _get_lock(self):
1035 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock.
1036 3dbe3ddf Michael Hanselmann

1037 3dbe3ddf Michael Hanselmann
    """
1038 3dbe3ddf Michael Hanselmann
    return self.__lock
1039 3dbe3ddf Michael Hanselmann
1040 3dbe3ddf Michael Hanselmann
  def _get_lockdict(self):
1041 3dbe3ddf Michael Hanselmann
    """Returns the lockset-internal lock dictionary.
1042 3dbe3ddf Michael Hanselmann

1043 3dbe3ddf Michael Hanselmann
    Accessing this structure is only safe in single-thread usage or when the
1044 3dbe3ddf Michael Hanselmann
    lockset-internal lock is held.
1045 3dbe3ddf Michael Hanselmann

1046 3dbe3ddf Michael Hanselmann
    """
1047 3dbe3ddf Michael Hanselmann
    return self.__lockdict
1048 3dbe3ddf Michael Hanselmann
1049 ee2b99e3 Michael Hanselmann
  def is_owned(self):
1050 c6a622cf Michael Hanselmann
    """Is the current thread a current level owner?
1051 c6a622cf Michael Hanselmann

1052 c6a622cf Michael Hanselmann
    @note: Use L{check_owned} to check if a specific lock is held
1053 c6a622cf Michael Hanselmann

1054 c6a622cf Michael Hanselmann
    """
1055 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
1056 aaae9bc0 Guido Trotter
1057 c6a622cf Michael Hanselmann
  def check_owned(self, names, shared=-1):
1058 c6a622cf Michael Hanselmann
    """Check if locks are owned in a specific mode.
1059 c6a622cf Michael Hanselmann

1060 c6a622cf Michael Hanselmann
    @type names: sequence or string
1061 c6a622cf Michael Hanselmann
    @param names: Lock names (or a single lock name)
1062 c6a622cf Michael Hanselmann
    @param shared: See L{SharedLock.is_owned}
1063 c6a622cf Michael Hanselmann
    @rtype: bool
1064 c6a622cf Michael Hanselmann
    @note: Use L{is_owned} to check if the current thread holds I{any} lock and
1065 c6a622cf Michael Hanselmann
      L{list_owned} to get the names of all owned locks
1066 c6a622cf Michael Hanselmann

1067 c6a622cf Michael Hanselmann
    """
1068 c6a622cf Michael Hanselmann
    if isinstance(names, basestring):
1069 c6a622cf Michael Hanselmann
      names = [names]
1070 c6a622cf Michael Hanselmann
1071 c6a622cf Michael Hanselmann
    # Avoid check if no locks are owned anyway
1072 c6a622cf Michael Hanselmann
    if names and self.is_owned():
1073 c6a622cf Michael Hanselmann
      candidates = []
1074 c6a622cf Michael Hanselmann
1075 c6a622cf Michael Hanselmann
      # Gather references to all locks (in case they're deleted in the meantime)
1076 c6a622cf Michael Hanselmann
      for lname in names:
1077 c6a622cf Michael Hanselmann
        try:
1078 c6a622cf Michael Hanselmann
          lock = self.__lockdict[lname]
1079 c6a622cf Michael Hanselmann
        except KeyError:
1080 c6a622cf Michael Hanselmann
          raise errors.LockError("Non-existing lock '%s' in set '%s' (it may"
1081 c6a622cf Michael Hanselmann
                                 " have been removed)" % (lname, self.name))
1082 c6a622cf Michael Hanselmann
        else:
1083 c6a622cf Michael Hanselmann
          candidates.append(lock)
1084 c6a622cf Michael Hanselmann
1085 c6a622cf Michael Hanselmann
      return compat.all(lock.is_owned(shared=shared) for lock in candidates)
1086 c6a622cf Michael Hanselmann
    else:
1087 c6a622cf Michael Hanselmann
      return False
1088 c6a622cf Michael Hanselmann
1089 8c811986 Michael Hanselmann
  def owning_all(self):
1090 8c811986 Michael Hanselmann
    """Checks whether current thread owns internal lock.
1091 8c811986 Michael Hanselmann

1092 8c811986 Michael Hanselmann
    Holding the internal lock is equivalent with holding all locks in the set
1093 8c811986 Michael Hanselmann
    (the opposite does not necessarily hold as it can not be easily
1094 8c811986 Michael Hanselmann
    determined). L{add} and L{remove} require the internal lock.
1095 8c811986 Michael Hanselmann

1096 8c811986 Michael Hanselmann
    @rtype: boolean
1097 8c811986 Michael Hanselmann

1098 8c811986 Michael Hanselmann
    """
1099 8c811986 Michael Hanselmann
    return self.__lock.is_owned()
1100 8c811986 Michael Hanselmann
1101 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
1102 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
1103 b2dabfd6 Guido Trotter
    if name is None:
1104 ee2b99e3 Michael Hanselmann
      if not self.is_owned():
1105 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
1106 aaae9bc0 Guido Trotter
    else:
1107 ee2b99e3 Michael Hanselmann
      if self.is_owned():
1108 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
1109 b2dabfd6 Guido Trotter
      else:
1110 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
1111 b2dabfd6 Guido Trotter
1112 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
1113 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
1114 aaae9bc0 Guido Trotter
1115 ee2b99e3 Michael Hanselmann
    assert not (name is None and self.__lock.is_owned()), \
1116 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
1117 e4335b5b Michael Hanselmann
1118 b2dabfd6 Guido Trotter
    if name is not None:
1119 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
1120 b2dabfd6 Guido Trotter
1121 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
1122 dc6296ff Michael Hanselmann
    if not (self.__lock.is_owned() or
1123 dc6296ff Michael Hanselmann
            self.__owners[threading.currentThread()]):
1124 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
1125 aaae9bc0 Guido Trotter
1126 ee2b99e3 Michael Hanselmann
  def list_owned(self):
1127 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
1128 ee2b99e3 Michael Hanselmann
    if self.is_owned():
1129 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
1130 aaae9bc0 Guido Trotter
    else:
1131 aaae9bc0 Guido Trotter
      return set()
1132 aaae9bc0 Guido Trotter
1133 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
1134 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
1135 ee2b99e3 Michael Hanselmann
    for lname in self.list_owned():
1136 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
1137 ee2b99e3 Michael Hanselmann
      if lock.is_owned():
1138 56452af7 Michael Hanselmann
        lock.release()
1139 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
1140 5aab242c Michael Hanselmann
1141 aaae9bc0 Guido Trotter
  def __names(self):
1142 aaae9bc0 Guido Trotter
    """Return the current set of names.
1143 aaae9bc0 Guido Trotter

1144 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
1145 aaae9bc0 Guido Trotter
    result after releasing the lock.
1146 aaae9bc0 Guido Trotter

1147 aaae9bc0 Guido Trotter
    """
1148 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
1149 aaae9bc0 Guido Trotter
1150 aaae9bc0 Guido Trotter
  def _names(self):
1151 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
1152 aaae9bc0 Guido Trotter

1153 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
1154 cdb08f44 Michael Hanselmann

1155 aaae9bc0 Guido Trotter
    """
1156 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
1157 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
1158 d4803c24 Guido Trotter
    release_lock = False
1159 ee2b99e3 Michael Hanselmann
    if not self.__lock.is_owned():
1160 d4803c24 Guido Trotter
      release_lock = True
1161 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
1162 aaae9bc0 Guido Trotter
    try:
1163 aaae9bc0 Guido Trotter
      result = self.__names()
1164 aaae9bc0 Guido Trotter
    finally:
1165 d4803c24 Guido Trotter
      if release_lock:
1166 d4803c24 Guido Trotter
        self.__lock.release()
1167 0cf257c5 Guido Trotter
    return set(result)
1168 aaae9bc0 Guido Trotter
1169 7100c2fa Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, priority=None,
1170 a95c53ea Michael Hanselmann
              opportunistic=False, test_notify=None):
1171 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
1172 aaae9bc0 Guido Trotter

1173 a95c53ea Michael Hanselmann
    @note: When acquiring locks opportunistically, any number of locks might
1174 a95c53ea Michael Hanselmann
      actually be acquired, even zero.
1175 a95c53ea Michael Hanselmann

1176 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1177 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1178 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1179 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1180 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
1181 c41eea6e Iustin Pop
        exclusive lock will be acquired
1182 5aab242c Michael Hanselmann
    @type timeout: float or None
1183 a95c53ea Michael Hanselmann
    @param timeout: Maximum time to acquire all locks; for opportunistic
1184 a95c53ea Michael Hanselmann
      acquisitions, a timeout can only be given when C{names} is C{None}, in
1185 a95c53ea Michael Hanselmann
      which case it is exclusively used for acquiring the L{LockSet}-internal
1186 a95c53ea Michael Hanselmann
      lock; opportunistic acquisitions don't use a timeout for acquiring
1187 a95c53ea Michael Hanselmann
      individual locks
1188 887c7aa6 Michael Hanselmann
    @type priority: integer
1189 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1190 a95c53ea Michael Hanselmann
    @type opportunistic: boolean
1191 a95c53ea Michael Hanselmann
    @param opportunistic: Acquire locks opportunistically; use the return value
1192 a95c53ea Michael Hanselmann
      to determine which locks were actually acquired
1193 5aab242c Michael Hanselmann
    @type test_notify: callable or None
1194 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1195 aaae9bc0 Guido Trotter

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

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

1202 aaae9bc0 Guido Trotter
    """
1203 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
1204 aaae9bc0 Guido Trotter
1205 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
1206 ee2b99e3 Michael Hanselmann
    assert not self.is_owned(), ("Cannot acquire locks in the same set twice"
1207 ee2b99e3 Michael Hanselmann
                                 " (lockset %s)" % self.name)
1208 aaae9bc0 Guido Trotter
1209 7100c2fa Michael Hanselmann
    if priority is None:
1210 7100c2fa Michael Hanselmann
      priority = _DEFAULT_PRIORITY
1211 7100c2fa Michael Hanselmann
1212 806e20fd Guido Trotter
    try:
1213 76e2f08a Michael Hanselmann
      if names is not None:
1214 a95c53ea Michael Hanselmann
        assert timeout is None or not opportunistic, \
1215 a95c53ea Michael Hanselmann
          ("Opportunistic acquisitions can only use a timeout if no"
1216 a95c53ea Michael Hanselmann
           " names are given; see docstring for details")
1217 a95c53ea Michael Hanselmann
1218 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
1219 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
1220 5aab242c Michael Hanselmann
          names = [names]
1221 5aab242c Michael Hanselmann
1222 a95c53ea Michael Hanselmann
        (mode, _, timeout_fn) = \
1223 a95c53ea Michael Hanselmann
          _GetLsAcquireModeAndTimeouts(False, timeout, opportunistic)
1224 a95c53ea Michael Hanselmann
1225 a95c53ea Michael Hanselmann
        return self.__acquire_inner(names, mode, shared, priority,
1226 a95c53ea Michael Hanselmann
                                    timeout_fn, test_notify)
1227 76e2f08a Michael Hanselmann
1228 76e2f08a Michael Hanselmann
      else:
1229 a95c53ea Michael Hanselmann
        (mode, ls_timeout_fn, timeout_fn) = \
1230 a95c53ea Michael Hanselmann
          _GetLsAcquireModeAndTimeouts(True, timeout, opportunistic)
1231 a95c53ea Michael Hanselmann
1232 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
1233 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
1234 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
1235 76e2f08a Michael Hanselmann
        #
1236 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
1237 887c7aa6 Michael Hanselmann
        # everybody else can use the instances at the same time. If we are
1238 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
1239 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
1240 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
1241 887c7aa6 Michael Hanselmann
        if not self.__lock.acquire(shared=shared, priority=priority,
1242 a95c53ea Michael Hanselmann
                                   timeout=ls_timeout_fn()):
1243 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1244 a95c53ea Michael Hanselmann
1245 76e2f08a Michael Hanselmann
        try:
1246 76e2f08a Michael Hanselmann
          # note we own the set-lock
1247 76e2f08a Michael Hanselmann
          self._add_owned()
1248 76e2f08a Michael Hanselmann
1249 a95c53ea Michael Hanselmann
          return self.__acquire_inner(self.__names(), mode, shared,
1250 a95c53ea Michael Hanselmann
                                      priority, timeout_fn, test_notify)
1251 76e2f08a Michael Hanselmann
        except:
1252 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1253 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1254 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
1255 5aab242c Michael Hanselmann
          self.__lock.release()
1256 76e2f08a Michael Hanselmann
          self._del_owned()
1257 76e2f08a Michael Hanselmann
          raise
1258 5aab242c Michael Hanselmann
1259 5aab242c Michael Hanselmann
    except _AcquireTimeout:
1260 5aab242c Michael Hanselmann
      return None
1261 aaae9bc0 Guido Trotter
1262 621b43ed Michael Hanselmann
  def __acquire_inner(self, names, mode, shared, priority,
1263 887c7aa6 Michael Hanselmann
                      timeout_fn, test_notify):
1264 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
1265 7e8841bd Michael Hanselmann

1266 a95c53ea Michael Hanselmann
    Acquisition modes:
1267 a95c53ea Michael Hanselmann

1268 a95c53ea Michael Hanselmann
      - C{_LS_ACQUIRE_ALL}: C{names} contains names of all locks in set, but
1269 a95c53ea Michael Hanselmann
        deleted locks can be ignored as the whole set is being acquired with
1270 a95c53ea Michael Hanselmann
        its internal lock held
1271 a95c53ea Michael Hanselmann
      - C{_LS_ACQUIRE_EXACT}: The names listed in C{names} must be acquired;
1272 a95c53ea Michael Hanselmann
        timeouts and deleted locks are fatal
1273 a95c53ea Michael Hanselmann
      - C{_LS_ACQUIRE_OPPORTUNISTIC}: C{names} lists names of locks (potentially
1274 a95c53ea Michael Hanselmann
        all within the set) which should be acquired opportunistically, that is
1275 a95c53ea Michael Hanselmann
        failures are ignored
1276 a95c53ea Michael Hanselmann

1277 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
1278 a95c53ea Michael Hanselmann
    @param mode: Lock acquisition mode (one of L{_LS_ACQUIRE_MODES})
1279 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
1280 a95c53ea Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout (C{None} for
1281 a95c53ea Michael Hanselmann
      opportunistic acquisitions)
1282 887c7aa6 Michael Hanselmann
    @param priority: Priority for acquiring locks
1283 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
1284 76e2f08a Michael Hanselmann

1285 76e2f08a Michael Hanselmann
    """
1286 a95c53ea Michael Hanselmann
    assert mode in _LS_ACQUIRE_MODES
1287 621b43ed Michael Hanselmann
1288 76e2f08a Michael Hanselmann
    acquire_list = []
1289 76e2f08a Michael Hanselmann
1290 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
1291 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
1292 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
1293 71e1863e Michael Hanselmann
    # deadlocks.
1294 a13d34a6 Michael Hanselmann
    for lname in sorted(frozenset(names)):
1295 76e2f08a Michael Hanselmann
      try:
1296 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
1297 76e2f08a Michael Hanselmann
      except KeyError:
1298 621b43ed Michael Hanselmann
        # We are acquiring the whole set, it doesn't matter if this particular
1299 621b43ed Michael Hanselmann
        # element is not there anymore. If, however, only certain names should
1300 621b43ed Michael Hanselmann
        # be acquired, not finding a lock is an error.
1301 621b43ed Michael Hanselmann
        if mode == _LS_ACQUIRE_EXACT:
1302 621b43ed Michael Hanselmann
          raise errors.LockError("Lock '%s' not found in set '%s' (it may have"
1303 621b43ed Michael Hanselmann
                                 " been removed)" % (lname, self.name))
1304 621b43ed Michael Hanselmann
      else:
1305 621b43ed Michael Hanselmann
        acquire_list.append((lname, lock))
1306 9b154270 Michael Hanselmann
1307 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
1308 76e2f08a Michael Hanselmann
    acquired = set()
1309 76e2f08a Michael Hanselmann
1310 76e2f08a Michael Hanselmann
    try:
1311 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
1312 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
1313 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
1314 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
1315 76e2f08a Michael Hanselmann
      # lock gets deleted.
1316 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
1317 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
1318 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
1319 76e2f08a Michael Hanselmann
        else:
1320 76e2f08a Michael Hanselmann
          test_notify_fn = None
1321 76e2f08a Michael Hanselmann
1322 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
1323 76e2f08a Michael Hanselmann
1324 76e2f08a Michael Hanselmann
        try:
1325 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
1326 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
1327 887c7aa6 Michael Hanselmann
                                     priority=priority,
1328 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
1329 76e2f08a Michael Hanselmann
        except errors.LockError:
1330 a95c53ea Michael Hanselmann
          if mode in (_LS_ACQUIRE_ALL, _LS_ACQUIRE_OPPORTUNISTIC):
1331 621b43ed Michael Hanselmann
            # We are acquiring the whole set, it doesn't matter if this
1332 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
1333 76e2f08a Michael Hanselmann
            continue
1334 76e2f08a Michael Hanselmann
1335 621b43ed Michael Hanselmann
          raise errors.LockError("Lock '%s' not found in set '%s' (it may have"
1336 621b43ed Michael Hanselmann
                                 " been removed)" % (lname, self.name))
1337 76e2f08a Michael Hanselmann
1338 76e2f08a Michael Hanselmann
        if not acq_success:
1339 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
1340 a95c53ea Michael Hanselmann
          if mode == _LS_ACQUIRE_OPPORTUNISTIC:
1341 a95c53ea Michael Hanselmann
            # Ignore timeouts on opportunistic acquisitions
1342 a95c53ea Michael Hanselmann
            continue
1343 a95c53ea Michael Hanselmann
1344 76e2f08a Michael Hanselmann
          if timeout is None:
1345 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
1346 76e2f08a Michael Hanselmann
            # blocking.
1347 7f93570a Iustin Pop
            raise errors.LockError("Failed to get lock %s (set %s)" %
1348 7f93570a Iustin Pop
                                   (lname, self.name))
1349 76e2f08a Michael Hanselmann
1350 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
1351 76e2f08a Michael Hanselmann
1352 76e2f08a Michael Hanselmann
        try:
1353 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
1354 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
1355 76e2f08a Michael Hanselmann
          acquired.add(lname)
1356 76e2f08a Michael Hanselmann
1357 76e2f08a Michael Hanselmann
        except:
1358 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
1359 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
1360 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
1361 ee2b99e3 Michael Hanselmann
          if lock.is_owned():
1362 76e2f08a Michael Hanselmann
            lock.release()
1363 76e2f08a Michael Hanselmann
          raise
1364 76e2f08a Michael Hanselmann
1365 76e2f08a Michael Hanselmann
    except:
1366 76e2f08a Michael Hanselmann
      # Release all owned locks
1367 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
1368 76e2f08a Michael Hanselmann
      raise
1369 76e2f08a Michael Hanselmann
1370 0cc00929 Guido Trotter
    return acquired
1371 aaae9bc0 Guido Trotter
1372 3dbe3ddf Michael Hanselmann
  def downgrade(self, names=None):
1373 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1374 3dbe3ddf Michael Hanselmann

1375 3dbe3ddf Michael Hanselmann
    The locks must have been acquired in exclusive mode.
1376 3dbe3ddf Michael Hanselmann

1377 3dbe3ddf Michael Hanselmann
    """
1378 ee2b99e3 Michael Hanselmann
    assert self.is_owned(), ("downgrade on lockset %s while not owning any"
1379 ee2b99e3 Michael Hanselmann
                             " lock" % self.name)
1380 3dbe3ddf Michael Hanselmann
1381 3dbe3ddf Michael Hanselmann
    # Support passing in a single resource to downgrade rather than many
1382 3dbe3ddf Michael Hanselmann
    if isinstance(names, basestring):
1383 3dbe3ddf Michael Hanselmann
      names = [names]
1384 3dbe3ddf Michael Hanselmann
1385 ee2b99e3 Michael Hanselmann
    owned = self.list_owned()
1386 3dbe3ddf Michael Hanselmann
1387 3dbe3ddf Michael Hanselmann
    if names is None:
1388 3dbe3ddf Michael Hanselmann
      names = owned
1389 3dbe3ddf Michael Hanselmann
    else:
1390 3dbe3ddf Michael Hanselmann
      names = set(names)
1391 3dbe3ddf Michael Hanselmann
      assert owned.issuperset(names), \
1392 3dbe3ddf Michael Hanselmann
        ("downgrade() on unheld resources %s (set %s)" %
1393 3dbe3ddf Michael Hanselmann
         (names.difference(owned), self.name))
1394 3dbe3ddf Michael Hanselmann
1395 3dbe3ddf Michael Hanselmann
    for lockname in names:
1396 3dbe3ddf Michael Hanselmann
      self.__lockdict[lockname].downgrade()
1397 3dbe3ddf Michael Hanselmann
1398 3dbe3ddf Michael Hanselmann
    # Do we own the lockset in exclusive mode?
1399 ee2b99e3 Michael Hanselmann
    if self.__lock.is_owned(shared=0):
1400 3dbe3ddf Michael Hanselmann
      # Have all locks been downgraded?
1401 ee2b99e3 Michael Hanselmann
      if not compat.any(lock.is_owned(shared=0)
1402 3dbe3ddf Michael Hanselmann
                        for lock in self.__lockdict.values()):
1403 3dbe3ddf Michael Hanselmann
        self.__lock.downgrade()
1404 ee2b99e3 Michael Hanselmann
        assert self.__lock.is_owned(shared=1)
1405 3dbe3ddf Michael Hanselmann
1406 3dbe3ddf Michael Hanselmann
    return True
1407 3dbe3ddf Michael Hanselmann
1408 aaae9bc0 Guido Trotter
  def release(self, names=None):
1409 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
1410 aaae9bc0 Guido Trotter

1411 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
1412 aaae9bc0 Guido Trotter
    before releasing them.
1413 aaae9bc0 Guido Trotter

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

1418 aaae9bc0 Guido Trotter
    """
1419 ee2b99e3 Michael Hanselmann
    assert self.is_owned(), ("release() on lock set %s while not owner" %
1420 ee2b99e3 Michael Hanselmann
                             self.name)
1421 aaae9bc0 Guido Trotter
1422 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
1423 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1424 aaae9bc0 Guido Trotter
      names = [names]
1425 aaae9bc0 Guido Trotter
1426 aaae9bc0 Guido Trotter
    if names is None:
1427 ee2b99e3 Michael Hanselmann
      names = self.list_owned()
1428 aaae9bc0 Guido Trotter
    else:
1429 aaae9bc0 Guido Trotter
      names = set(names)
1430 ee2b99e3 Michael Hanselmann
      assert self.list_owned().issuperset(names), (
1431 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1432 ee2b99e3 Michael Hanselmann
               (names.difference(self.list_owned()), self.name))
1433 aaae9bc0 Guido Trotter
1434 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1435 3b7ed473 Guido Trotter
    # After this 'add' can work again
1436 ee2b99e3 Michael Hanselmann
    if self.__lock.is_owned():
1437 3b7ed473 Guido Trotter
      self.__lock.release()
1438 b2dabfd6 Guido Trotter
      self._del_owned()
1439 3b7ed473 Guido Trotter
1440 aaae9bc0 Guido Trotter
    for lockname in names:
1441 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1442 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1443 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1444 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1445 aaae9bc0 Guido Trotter
1446 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1447 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1448 aaae9bc0 Guido Trotter

1449 ec44d893 Guido Trotter
    @type names: list of strings
1450 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1451 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1452 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1453 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1454 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1455 aaae9bc0 Guido Trotter

1456 aaae9bc0 Guido Trotter
    """
1457 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1458 ee2b99e3 Michael Hanselmann
    assert not self.is_owned() or self.__lock.is_owned(shared=0), \
1459 7f93570a Iustin Pop
      ("Cannot add locks if the set %s is only partially owned, or shared" %
1460 7f93570a Iustin Pop
       self.name)
1461 3b7ed473 Guido Trotter
1462 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1463 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1464 aaae9bc0 Guido Trotter
      names = [names]
1465 aaae9bc0 Guido Trotter
1466 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1467 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1468 3b7ed473 Guido Trotter
    release_lock = False
1469 ee2b99e3 Michael Hanselmann
    if not self.__lock.is_owned():
1470 3b7ed473 Guido Trotter
      release_lock = True
1471 3b7ed473 Guido Trotter
      self.__lock.acquire()
1472 3b7ed473 Guido Trotter
1473 aaae9bc0 Guido Trotter
    try:
1474 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1475 aaae9bc0 Guido Trotter
      if invalid_names:
1476 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1477 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1478 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1479 7f93570a Iustin Pop
        raise errors.LockError("duplicate add(%s) on lockset %s" %
1480 7f93570a Iustin Pop
                               (invalid_names, self.name))
1481 aaae9bc0 Guido Trotter
1482 aaae9bc0 Guido Trotter
      for lockname in names:
1483 19b9ba9a Michael Hanselmann
        lock = SharedLock(self._GetLockName(lockname), monitor=self.__monitor)
1484 aaae9bc0 Guido Trotter
1485 aaae9bc0 Guido Trotter
        if acquired:
1486 887c7aa6 Michael Hanselmann
          # No need for priority or timeout here as this lock has just been
1487 887c7aa6 Michael Hanselmann
          # created
1488 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1489 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1490 aaae9bc0 Guido Trotter
          try:
1491 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1492 aaae9bc0 Guido Trotter
          except:
1493 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1494 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1495 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1496 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1497 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1498 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1499 aaae9bc0 Guido Trotter
            lock.release()
1500 aaae9bc0 Guido Trotter
            raise
1501 aaae9bc0 Guido Trotter
1502 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1503 aaae9bc0 Guido Trotter
1504 aaae9bc0 Guido Trotter
    finally:
1505 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1506 3b7ed473 Guido Trotter
      if release_lock:
1507 3b7ed473 Guido Trotter
        self.__lock.release()
1508 aaae9bc0 Guido Trotter
1509 aaae9bc0 Guido Trotter
    return True
1510 aaae9bc0 Guido Trotter
1511 5e0a6daf Michael Hanselmann
  def remove(self, names):
1512 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1513 aaae9bc0 Guido Trotter

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

1517 ec44d893 Guido Trotter
    @type names: list of strings
1518 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1519 aaae9bc0 Guido Trotter

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

1524 aaae9bc0 Guido Trotter
    """
1525 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1526 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1527 aaae9bc0 Guido Trotter
      names = [names]
1528 aaae9bc0 Guido Trotter
1529 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1530 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1531 aaae9bc0 Guido Trotter
    # by the lock itself.
1532 ee2b99e3 Michael Hanselmann
    assert not self.is_owned() or self.list_owned().issuperset(names), (
1533 7f93570a Iustin Pop
      "remove() on acquired lockset %s while not owning all elements" %
1534 7f93570a Iustin Pop
      self.name)
1535 aaae9bc0 Guido Trotter
1536 3f404fc5 Guido Trotter
    removed = []
1537 aaae9bc0 Guido Trotter
1538 aaae9bc0 Guido Trotter
    for lname in names:
1539 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1540 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1541 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1542 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1543 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1544 aaae9bc0 Guido Trotter
      try:
1545 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1546 3f404fc5 Guido Trotter
        removed.append(lname)
1547 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1548 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1549 ee2b99e3 Michael Hanselmann
        assert not self.is_owned(), ("remove failed while holding lockset %s" %
1550 ee2b99e3 Michael Hanselmann
                                     self.name)
1551 aaae9bc0 Guido Trotter
      else:
1552 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1553 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1554 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1555 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1556 aaae9bc0 Guido Trotter
        #
1557 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1558 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1559 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1560 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1561 ee2b99e3 Michael Hanselmann
        if self.is_owned():
1562 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1563 aaae9bc0 Guido Trotter
1564 3f404fc5 Guido Trotter
    return removed
1565 aaae9bc0 Guido Trotter
1566 7ee7c0c7 Guido Trotter
1567 8716b1db Michael Hanselmann
# Locking levels, must be acquired in increasing order. Current rules are:
1568 8716b1db Michael Hanselmann
# - At level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1569 8716b1db Michael Hanselmann
#   acquired before performing any operation, either in shared or exclusive
1570 8716b1db Michael Hanselmann
#   mode. Acquiring the BGL in exclusive mode is discouraged and should be
1571 8716b1db Michael Hanselmann
#   avoided..
1572 8716b1db Michael Hanselmann
# - At levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks. If
1573 8716b1db Michael Hanselmann
#   you need more than one node, or more than one instance, acquire them at the
1574 8716b1db Michael Hanselmann
#   same time.
1575 8716b1db Michael Hanselmann
# - LEVEL_NODE_RES is for node resources and should be used by operations with
1576 8716b1db Michael Hanselmann
#   possibly high impact on the node's disks.
1577 8716b1db Michael Hanselmann
# - LEVEL_NODE_ALLOC blocks instance allocations for the whole cluster
1578 8716b1db Michael Hanselmann
#   ("NAL" is the only lock at this level). It should be acquired in shared
1579 8716b1db Michael Hanselmann
#   mode when an opcode blocks all or a significant amount of a cluster's
1580 8716b1db Michael Hanselmann
#   locks. Opcodes doing instance allocations should acquire in exclusive mode.
1581 8716b1db Michael Hanselmann
#   Once the set of acquired locks for an opcode has been reduced to the working
1582 8716b1db Michael Hanselmann
#   set, the NAL should be released as well to allow allocations to proceed.
1583 8716b1db Michael Hanselmann
(LEVEL_CLUSTER,
1584 8716b1db Michael Hanselmann
 LEVEL_INSTANCE,
1585 48aaca91 Michael Hanselmann
 LEVEL_NODE_ALLOC,
1586 8716b1db Michael Hanselmann
 LEVEL_NODEGROUP,
1587 8716b1db Michael Hanselmann
 LEVEL_NODE,
1588 8716b1db Michael Hanselmann
 LEVEL_NODE_RES,
1589 8716b1db Michael Hanselmann
 LEVEL_NETWORK) = range(0, 7)
1590 7ee7c0c7 Guido Trotter
1591 4e070776 Michael Hanselmann
LEVELS = [
1592 4e070776 Michael Hanselmann
  LEVEL_CLUSTER,
1593 4e070776 Michael Hanselmann
  LEVEL_INSTANCE,
1594 48aaca91 Michael Hanselmann
  LEVEL_NODE_ALLOC,
1595 4e070776 Michael Hanselmann
  LEVEL_NODEGROUP,
1596 4e070776 Michael Hanselmann
  LEVEL_NODE,
1597 4e070776 Michael Hanselmann
  LEVEL_NODE_RES,
1598 6c0a75db Dimitris Aragiorgis
  LEVEL_NETWORK,
1599 4e070776 Michael Hanselmann
  ]
1600 7ee7c0c7 Guido Trotter
1601 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1602 b8028dcf Michael Hanselmann
LEVELS_MOD = compat.UniqueFrozenset([
1603 4e070776 Michael Hanselmann
  LEVEL_NODE_RES,
1604 4e070776 Michael Hanselmann
  LEVEL_NODE,
1605 4e070776 Michael Hanselmann
  LEVEL_NODEGROUP,
1606 4e070776 Michael Hanselmann
  LEVEL_INSTANCE,
1607 6c0a75db Dimitris Aragiorgis
  LEVEL_NETWORK,
1608 4e070776 Michael Hanselmann
  ])
1609 7ee7c0c7 Guido Trotter
1610 5d7a899e Michael Hanselmann
#: Lock level names (make sure to use singular form)
1611 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1612 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1613 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1614 48aaca91 Michael Hanselmann
  LEVEL_NODE_ALLOC: "node-alloc",
1615 819ca990 Guido Trotter
  LEVEL_NODEGROUP: "nodegroup",
1616 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1617 5d7a899e Michael Hanselmann
  LEVEL_NODE_RES: "node-res",
1618 6c0a75db Dimitris Aragiorgis
  LEVEL_NETWORK: "network",
1619 ea205dbc Michael Hanselmann
  }
1620 ea205dbc Michael Hanselmann
1621 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1622 3ccb3a64 Michael Hanselmann
BGL = "BGL"
1623 7ee7c0c7 Guido Trotter
1624 8716b1db Michael Hanselmann
#: Node allocation lock
1625 8716b1db Michael Hanselmann
NAL = "NAL"
1626 8716b1db Michael Hanselmann
1627 7ee7c0c7 Guido Trotter
1628 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1629 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1630 7ee7c0c7 Guido Trotter

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

1636 7ee7c0c7 Guido Trotter
  """
1637 7ee7c0c7 Guido Trotter
  _instance = None
1638 7ee7c0c7 Guido Trotter
1639 6c0a75db Dimitris Aragiorgis
  def __init__(self, nodes, nodegroups, instances, networks):
1640 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1641 7ee7c0c7 Guido Trotter

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

1645 c41eea6e Iustin Pop
    @param nodes: list of node names
1646 819ca990 Guido Trotter
    @param nodegroups: list of nodegroup uuids
1647 c41eea6e Iustin Pop
    @param instances: list of instance names
1648 7ee7c0c7 Guido Trotter

1649 7ee7c0c7 Guido Trotter
    """
1650 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1651 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1652 c41eea6e Iustin Pop
1653 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1654 7ee7c0c7 Guido Trotter
1655 19b9ba9a Michael Hanselmann
    self._monitor = LockMonitor()
1656 19b9ba9a Michael Hanselmann
1657 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1658 7ee7c0c7 Guido Trotter
    # locking order.
1659 7ee7c0c7 Guido Trotter
    self.__keyring = {
1660 5d7a899e Michael Hanselmann
      LEVEL_CLUSTER: LockSet([BGL], "cluster", monitor=self._monitor),
1661 5d7a899e Michael Hanselmann
      LEVEL_NODE: LockSet(nodes, "node", monitor=self._monitor),
1662 5d7a899e Michael Hanselmann
      LEVEL_NODE_RES: LockSet(nodes, "node-res", monitor=self._monitor),
1663 5d7a899e Michael Hanselmann
      LEVEL_NODEGROUP: LockSet(nodegroups, "nodegroup", monitor=self._monitor),
1664 6c0a75db Dimitris Aragiorgis
      LEVEL_INSTANCE: LockSet(instances, "instance", monitor=self._monitor),
1665 6c0a75db Dimitris Aragiorgis
      LEVEL_NETWORK: LockSet(networks, "network", monitor=self._monitor),
1666 8716b1db Michael Hanselmann
      LEVEL_NODE_ALLOC: LockSet([NAL], "node-alloc", monitor=self._monitor),
1667 19b9ba9a Michael Hanselmann
      }
1668 19b9ba9a Michael Hanselmann
1669 5d7a899e Michael Hanselmann
    assert compat.all(ls.name == LEVEL_NAMES[level]
1670 8716b1db Michael Hanselmann
                      for (level, ls) in self.__keyring.items()), \
1671 8716b1db Michael Hanselmann
      "Keyring name mismatch"
1672 5d7a899e Michael Hanselmann
1673 4c03b2b5 Michael Hanselmann
  def AddToLockMonitor(self, provider):
1674 4c03b2b5 Michael Hanselmann
    """Registers a new lock with the monitor.
1675 4c03b2b5 Michael Hanselmann

1676 4c03b2b5 Michael Hanselmann
    See L{LockMonitor.RegisterLock}.
1677 4c03b2b5 Michael Hanselmann

1678 4c03b2b5 Michael Hanselmann
    """
1679 4c03b2b5 Michael Hanselmann
    return self._monitor.RegisterLock(provider)
1680 4c03b2b5 Michael Hanselmann
1681 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1682 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1683 19b9ba9a Michael Hanselmann

1684 19b9ba9a Michael Hanselmann
    See L{LockMonitor.QueryLocks}.
1685 19b9ba9a Michael Hanselmann

1686 19b9ba9a Michael Hanselmann
    """
1687 24d16f76 Michael Hanselmann
    return self._monitor.QueryLocks(fields)
1688 24d16f76 Michael Hanselmann
1689 7ee7c0c7 Guido Trotter
  def _names(self, level):
1690 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1691 7ee7c0c7 Guido Trotter

1692 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1693 c41eea6e Iustin Pop

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

1696 7ee7c0c7 Guido Trotter
    """
1697 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1698 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1699 7ee7c0c7 Guido Trotter
1700 ee2b99e3 Michael Hanselmann
  def is_owned(self, level):
1701 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1702 7ee7c0c7 Guido Trotter

1703 7ee7c0c7 Guido Trotter
    """
1704 ee2b99e3 Michael Hanselmann
    return self.__keyring[level].is_owned()
1705 7ee7c0c7 Guido Trotter
1706 ee2b99e3 Michael Hanselmann
  def list_owned(self, level):
1707 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1708 7ee7c0c7 Guido Trotter

1709 7ee7c0c7 Guido Trotter
    """
1710 ee2b99e3 Michael Hanselmann
    return self.__keyring[level].list_owned()
1711 07cba1bc Michael Hanselmann
1712 c6a622cf Michael Hanselmann
  def check_owned(self, level, names, shared=-1):
1713 c6a622cf Michael Hanselmann
    """Check if locks at a certain level are owned in a specific mode.
1714 c6a622cf Michael Hanselmann

1715 c6a622cf Michael Hanselmann
    @see: L{LockSet.check_owned}
1716 c6a622cf Michael Hanselmann

1717 c6a622cf Michael Hanselmann
    """
1718 c6a622cf Michael Hanselmann
    return self.__keyring[level].check_owned(names, shared=shared)
1719 c6a622cf Michael Hanselmann
1720 8c811986 Michael Hanselmann
  def owning_all(self, level):
1721 8c811986 Michael Hanselmann
    """Checks whether current thread owns all locks at a certain level.
1722 8c811986 Michael Hanselmann

1723 8c811986 Michael Hanselmann
    @see: L{LockSet.owning_all}
1724 8c811986 Michael Hanselmann

1725 8c811986 Michael Hanselmann
    """
1726 8c811986 Michael Hanselmann
    return self.__keyring[level].owning_all()
1727 8c811986 Michael Hanselmann
1728 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1729 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1730 7ee7c0c7 Guido Trotter

1731 7ee7c0c7 Guido Trotter
    """
1732 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1733 7ee7c0c7 Guido Trotter
    # the test cases.
1734 ee2b99e3 Michael Hanselmann
    return compat.any((self.is_owned(l) for l in LEVELS[level + 1:]))
1735 7ee7c0c7 Guido Trotter
1736 b459a848 Andrea Spadaccini
  def _BGL_owned(self): # pylint: disable=C0103
1737 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1738 7ee7c0c7 Guido Trotter

1739 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1740 7ee7c0c7 Guido Trotter

1741 7ee7c0c7 Guido Trotter
    """
1742 ee2b99e3 Michael Hanselmann
    return BGL in self.__keyring[LEVEL_CLUSTER].list_owned()
1743 7ee7c0c7 Guido Trotter
1744 c70d2d9b Iustin Pop
  @staticmethod
1745 b459a848 Andrea Spadaccini
  def _contains_BGL(level, names): # pylint: disable=C0103
1746 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1747 c41eea6e Iustin Pop

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

1751 7ee7c0c7 Guido Trotter
    """
1752 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1753 7ee7c0c7 Guido Trotter
1754 07db7ed2 Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0, priority=None,
1755 07db7ed2 Michael Hanselmann
              opportunistic=False):
1756 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1757 7ee7c0c7 Guido Trotter

1758 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1759 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1760 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1761 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1762 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1763 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1764 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1765 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1766 5e0a6daf Michael Hanselmann
    @type timeout: float
1767 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1768 b30d95b6 Michael Hanselmann
    @type priority: integer
1769 b30d95b6 Michael Hanselmann
    @param priority: Priority for acquiring lock
1770 07db7ed2 Michael Hanselmann
    @type opportunistic: boolean
1771 07db7ed2 Michael Hanselmann
    @param opportunistic: Acquire locks opportunistically; use the return value
1772 07db7ed2 Michael Hanselmann
      to determine which locks were actually acquired
1773 7ee7c0c7 Guido Trotter

1774 7ee7c0c7 Guido Trotter
    """
1775 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1776 7ee7c0c7 Guido Trotter
1777 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1778 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1779 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1780 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1781 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1782 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1783 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1784 5ae4945a Iustin Pop
      "You must own the Big Ganeti Lock before acquiring any other")
1785 7ee7c0c7 Guido Trotter
1786 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1787 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1788 5ae4945a Iustin Pop
                                          " while owning some at a greater one")
1789 7ee7c0c7 Guido Trotter
1790 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1791 b30d95b6 Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout,
1792 07db7ed2 Michael Hanselmann
                                         priority=priority,
1793 07db7ed2 Michael Hanselmann
                                         opportunistic=opportunistic)
1794 7ee7c0c7 Guido Trotter
1795 3dbe3ddf Michael Hanselmann
  def downgrade(self, level, names=None):
1796 3dbe3ddf Michael Hanselmann
    """Downgrade a set of resource locks from exclusive to shared mode.
1797 3dbe3ddf Michael Hanselmann

1798 3dbe3ddf Michael Hanselmann
    You must have acquired the locks in exclusive mode.
1799 3dbe3ddf Michael Hanselmann

1800 3dbe3ddf Michael Hanselmann
    @type level: member of locking.LEVELS
1801 3dbe3ddf Michael Hanselmann
    @param level: the level at which the locks shall be downgraded
1802 3dbe3ddf Michael Hanselmann
    @type names: list of strings, or None
1803 3dbe3ddf Michael Hanselmann
    @param names: the names of the locks which shall be downgraded
1804 3dbe3ddf Michael Hanselmann
        (defaults to all the locks acquired at the level)
1805 3dbe3ddf Michael Hanselmann

1806 3dbe3ddf Michael Hanselmann
    """
1807 3dbe3ddf Michael Hanselmann
    assert level in LEVELS, "Invalid locking level %s" % level
1808 3dbe3ddf Michael Hanselmann
1809 3dbe3ddf Michael Hanselmann
    return self.__keyring[level].downgrade(names=names)
1810 3dbe3ddf Michael Hanselmann
1811 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1812 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1813 7ee7c0c7 Guido Trotter

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

1817 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1818 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1819 ec44d893 Guido Trotter
    @type names: list of strings, or None
1820 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1821 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1822 7ee7c0c7 Guido Trotter

1823 7ee7c0c7 Guido Trotter
    """
1824 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1825 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1826 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1827 5ae4945a Iustin Pop
              "Cannot release the Big Ganeti Lock while holding something"
1828 5ae4945a Iustin Pop
              " at upper levels (%r)" %
1829 5ae4945a Iustin Pop
              (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self.list_owned(i))
1830 5ae4945a Iustin Pop
                                for i in self.__keyring.keys()]), ))
1831 7ee7c0c7 Guido Trotter
1832 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1833 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1834 7ee7c0c7 Guido Trotter
1835 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1836 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1837 7ee7c0c7 Guido Trotter

1838 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1839 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1840 ec44d893 Guido Trotter
    @type names: list of strings
1841 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1842 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1843 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1844 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1845 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1846 c41eea6e Iustin Pop

1847 7ee7c0c7 Guido Trotter
    """
1848 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1849 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1850 5ae4945a Iustin Pop
                               " operations")
1851 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1852 5ae4945a Iustin Pop
                                          " while owning some at a greater one")
1853 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1854 7ee7c0c7 Guido Trotter
1855 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1856 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1857 7ee7c0c7 Guido Trotter

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

1861 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1862 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1863 ec44d893 Guido Trotter
    @type names: list of strings
1864 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1865 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1866 7ee7c0c7 Guido Trotter

1867 7ee7c0c7 Guido Trotter
    """
1868 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1869 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1870 5ae4945a Iustin Pop
                               " operations")
1871 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1872 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1873 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1874 ee2b99e3 Michael Hanselmann
    assert self.is_owned(level) or not self._upper_owned(level), (
1875 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1876 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1877 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)
1878 19b9ba9a Michael Hanselmann
1879 19b9ba9a Michael Hanselmann
1880 44b4eddc Michael Hanselmann
def _MonitorSortKey((item, idx, num)):
1881 e4e35357 Michael Hanselmann
  """Sorting key function.
1882 e4e35357 Michael Hanselmann

1883 44b4eddc Michael Hanselmann
  Sort by name, registration order and then order of information. This provides
1884 44b4eddc Michael Hanselmann
  a stable sort order over different providers, even if they return the same
1885 44b4eddc Michael Hanselmann
  name.
1886 e4e35357 Michael Hanselmann

1887 e4e35357 Michael Hanselmann
  """
1888 e4e35357 Michael Hanselmann
  (name, _, _, _) = item
1889 e4e35357 Michael Hanselmann
1890 44b4eddc Michael Hanselmann
  return (utils.NiceSortKey(name), num, idx)
1891 e4e35357 Michael Hanselmann
1892 e4e35357 Michael Hanselmann
1893 19b9ba9a Michael Hanselmann
class LockMonitor(object):
1894 19b9ba9a Michael Hanselmann
  _LOCK_ATTR = "_lock"
1895 19b9ba9a Michael Hanselmann
1896 19b9ba9a Michael Hanselmann
  def __init__(self):
1897 19b9ba9a Michael Hanselmann
    """Initializes this class.
1898 19b9ba9a Michael Hanselmann

1899 19b9ba9a Michael Hanselmann
    """
1900 19b9ba9a Michael Hanselmann
    self._lock = SharedLock("LockMonitor")
1901 19b9ba9a Michael Hanselmann
1902 e4e35357 Michael Hanselmann
    # Counter for stable sorting
1903 e4e35357 Michael Hanselmann
    self._counter = itertools.count(0)
1904 e4e35357 Michael Hanselmann
1905 19b9ba9a Michael Hanselmann
    # Tracked locks. Weak references are used to avoid issues with circular
1906 19b9ba9a Michael Hanselmann
    # references and deletion.
1907 19b9ba9a Michael Hanselmann
    self._locks = weakref.WeakKeyDictionary()
1908 19b9ba9a Michael Hanselmann
1909 19b9ba9a Michael Hanselmann
  @ssynchronized(_LOCK_ATTR)
1910 44b4eddc Michael Hanselmann
  def RegisterLock(self, provider):
1911 19b9ba9a Michael Hanselmann
    """Registers a new lock.
1912 19b9ba9a Michael Hanselmann

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

1921 19b9ba9a Michael Hanselmann
    """
1922 44b4eddc Michael Hanselmann
    assert provider not in self._locks, "Duplicate registration"
1923 e4e35357 Michael Hanselmann
1924 e4e35357 Michael Hanselmann
    # There used to be a check for duplicate names here. As it turned out, when
1925 e4e35357 Michael Hanselmann
    # a lock is re-created with the same name in a very short timeframe, the
1926 e4e35357 Michael Hanselmann
    # previous instance might not yet be removed from the weakref dictionary.
1927 e4e35357 Michael Hanselmann
    # By keeping track of the order of incoming registrations, a stable sort
1928 e4e35357 Michael Hanselmann
    # ordering can still be guaranteed.
1929 e4e35357 Michael Hanselmann
1930 44b4eddc Michael Hanselmann
    self._locks[provider] = self._counter.next()
1931 19b9ba9a Michael Hanselmann
1932 24d16f76 Michael Hanselmann
  def _GetLockInfo(self, requested):
1933 44b4eddc Michael Hanselmann
    """Get information from all locks.
1934 19b9ba9a Michael Hanselmann

1935 19b9ba9a Michael Hanselmann
    """
1936 44b4eddc Michael Hanselmann
    # Must hold lock while getting consistent list of tracked items
1937 44b4eddc Michael Hanselmann
    self._lock.acquire(shared=1)
1938 44b4eddc Michael Hanselmann
    try:
1939 44b4eddc Michael Hanselmann
      items = self._locks.items()
1940 44b4eddc Michael Hanselmann
    finally:
1941 44b4eddc Michael Hanselmann
      self._lock.release()
1942 44b4eddc Michael Hanselmann
1943 44b4eddc Michael Hanselmann
    return [(info, idx, num)
1944 44b4eddc Michael Hanselmann
            for (provider, num) in items
1945 44b4eddc Michael Hanselmann
            for (idx, info) in enumerate(provider.GetLockInfo(requested))]
1946 19b9ba9a Michael Hanselmann
1947 24d16f76 Michael Hanselmann
  def _Query(self, fields):
1948 24d16f76 Michael Hanselmann
    """Queries information from all locks.
1949 19b9ba9a Michael Hanselmann

1950 24d16f76 Michael Hanselmann
    @type fields: list of strings
1951 24d16f76 Michael Hanselmann
    @param fields: List of fields to return
1952 24d16f76 Michael Hanselmann

1953 24d16f76 Michael Hanselmann
    """
1954 24d16f76 Michael Hanselmann
    qobj = query.Query(query.LOCK_FIELDS, fields)
1955 24d16f76 Michael Hanselmann
1956 e4e35357 Michael Hanselmann
    # Get all data with internal lock held and then sort by name and incoming
1957 e4e35357 Michael Hanselmann
    # order
1958 e4e35357 Michael Hanselmann
    lockinfo = sorted(self._GetLockInfo(qobj.RequestedData()),
1959 e4e35357 Michael Hanselmann
                      key=_MonitorSortKey)
1960 24d16f76 Michael Hanselmann
1961 e4e35357 Michael Hanselmann
    # Extract lock information and build query data
1962 eb62069e Iustin Pop
    return (qobj, query.LockQueryData(map(compat.fst, lockinfo)))
1963 19b9ba9a Michael Hanselmann
1964 24d16f76 Michael Hanselmann
  def QueryLocks(self, fields):
1965 19b9ba9a Michael Hanselmann
    """Queries information from all locks.
1966 19b9ba9a Michael Hanselmann

1967 19b9ba9a Michael Hanselmann
    @type fields: list of strings
1968 19b9ba9a Michael Hanselmann
    @param fields: List of fields to return
1969 19b9ba9a Michael Hanselmann

1970 19b9ba9a Michael Hanselmann
    """
1971 24d16f76 Michael Hanselmann
    (qobj, ctx) = self._Query(fields)
1972 19b9ba9a Michael Hanselmann
1973 24d16f76 Michael Hanselmann
    # Prepare query response
1974 24d16f76 Michael Hanselmann
    return query.GetQueryResponse(qobj, ctx)