Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 89b70f39

History | View | Annotate | Download (39.5 kB)

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

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

45 42a999d1 Guido Trotter
  """
46 42a999d1 Guido Trotter
  def wrap(fn):
47 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
48 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
49 42a999d1 Guido Trotter
      try:
50 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
51 42a999d1 Guido Trotter
      finally:
52 42a999d1 Guido Trotter
        lock.release()
53 42a999d1 Guido Trotter
    return sync_function
54 42a999d1 Guido Trotter
  return wrap
55 42a999d1 Guido Trotter
56 42a999d1 Guido Trotter
57 7e8841bd Michael Hanselmann
class RunningTimeout(object):
58 7e8841bd Michael Hanselmann
  """Class to calculate remaining timeout when doing several operations.
59 7e8841bd Michael Hanselmann

60 7e8841bd Michael Hanselmann
  """
61 7e8841bd Michael Hanselmann
  __slots__ = [
62 7e8841bd Michael Hanselmann
    "_allow_negative",
63 7e8841bd Michael Hanselmann
    "_start_time",
64 7e8841bd Michael Hanselmann
    "_time_fn",
65 7e8841bd Michael Hanselmann
    "_timeout",
66 7e8841bd Michael Hanselmann
    ]
67 7e8841bd Michael Hanselmann
68 7e8841bd Michael Hanselmann
  def __init__(self, timeout, allow_negative, _time_fn=time.time):
69 7e8841bd Michael Hanselmann
    """Initializes this class.
70 7e8841bd Michael Hanselmann

71 7e8841bd Michael Hanselmann
    @type timeout: float
72 7e8841bd Michael Hanselmann
    @param timeout: Timeout duration
73 7e8841bd Michael Hanselmann
    @type allow_negative: bool
74 7e8841bd Michael Hanselmann
    @param allow_negative: Whether to return values below zero
75 7e8841bd Michael Hanselmann
    @param _time_fn: Time function for unittests
76 7e8841bd Michael Hanselmann

77 7e8841bd Michael Hanselmann
    """
78 7e8841bd Michael Hanselmann
    object.__init__(self)
79 7e8841bd Michael Hanselmann
80 7e8841bd Michael Hanselmann
    if timeout is not None and timeout < 0.0:
81 7e8841bd Michael Hanselmann
      raise ValueError("Timeout must not be negative")
82 7e8841bd Michael Hanselmann
83 7e8841bd Michael Hanselmann
    self._timeout = timeout
84 7e8841bd Michael Hanselmann
    self._allow_negative = allow_negative
85 7e8841bd Michael Hanselmann
    self._time_fn = _time_fn
86 7e8841bd Michael Hanselmann
87 7e8841bd Michael Hanselmann
    self._start_time = None
88 7e8841bd Michael Hanselmann
89 7e8841bd Michael Hanselmann
  def Remaining(self):
90 7e8841bd Michael Hanselmann
    """Returns the remaining timeout.
91 7e8841bd Michael Hanselmann

92 7e8841bd Michael Hanselmann
    """
93 7e8841bd Michael Hanselmann
    if self._timeout is None:
94 7e8841bd Michael Hanselmann
      return None
95 7e8841bd Michael Hanselmann
96 7e8841bd Michael Hanselmann
    # Get start time on first calculation
97 7e8841bd Michael Hanselmann
    if self._start_time is None:
98 7e8841bd Michael Hanselmann
      self._start_time = self._time_fn()
99 7e8841bd Michael Hanselmann
100 7e8841bd Michael Hanselmann
    # Calculate remaining time
101 7e8841bd Michael Hanselmann
    remaining_timeout = self._start_time + self._timeout - self._time_fn()
102 7e8841bd Michael Hanselmann
103 7e8841bd Michael Hanselmann
    if not self._allow_negative:
104 7e8841bd Michael Hanselmann
      # Ensure timeout is always >= 0
105 7e8841bd Michael Hanselmann
      return max(0.0, remaining_timeout)
106 7e8841bd Michael Hanselmann
107 7e8841bd Michael Hanselmann
    return remaining_timeout
108 7e8841bd Michael Hanselmann
109 7e8841bd Michael Hanselmann
110 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
111 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
112 d76167a5 Michael Hanselmann

113 d76167a5 Michael Hanselmann
  """
114 d76167a5 Michael Hanselmann
  __slots__ = [
115 d76167a5 Michael Hanselmann
    "_fd",
116 d76167a5 Michael Hanselmann
    "_poller",
117 d76167a5 Michael Hanselmann
    ]
118 d76167a5 Michael Hanselmann
119 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
120 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
121 d76167a5 Michael Hanselmann

122 d76167a5 Michael Hanselmann
    @type poller: select.poll
123 d76167a5 Michael Hanselmann
    @param poller: Poller object
124 d76167a5 Michael Hanselmann
    @type fd: int
125 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
126 d76167a5 Michael Hanselmann

127 d76167a5 Michael Hanselmann
    """
128 d76167a5 Michael Hanselmann
    object.__init__(self)
129 d76167a5 Michael Hanselmann
    self._poller = poller
130 d76167a5 Michael Hanselmann
    self._fd = fd
131 d76167a5 Michael Hanselmann
132 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
133 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
134 d76167a5 Michael Hanselmann

135 d76167a5 Michael Hanselmann
    @type timeout: float or None
136 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
137 d76167a5 Michael Hanselmann

138 d76167a5 Michael Hanselmann
    """
139 f4e673fb Michael Hanselmann
    running_timeout = RunningTimeout(timeout, True)
140 f4e673fb Michael Hanselmann
141 f4e673fb Michael Hanselmann
    while True:
142 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
143 f4e673fb Michael Hanselmann
144 f4e673fb Michael Hanselmann
      if remaining_time is not None and remaining_time < 0.0:
145 f4e673fb Michael Hanselmann
        break
146 d76167a5 Michael Hanselmann
147 d76167a5 Michael Hanselmann
      try:
148 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
149 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
150 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
151 d76167a5 Michael Hanselmann
          raise
152 d76167a5 Michael Hanselmann
        result = None
153 d76167a5 Michael Hanselmann
154 d76167a5 Michael Hanselmann
      # Check whether we were notified
155 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
156 d76167a5 Michael Hanselmann
        break
157 d76167a5 Michael Hanselmann
158 d76167a5 Michael Hanselmann
159 2419060d Guido Trotter
class _BaseCondition(object):
160 2419060d Guido Trotter
  """Base class containing common code for conditions.
161 2419060d Guido Trotter

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

164 2419060d Guido Trotter
  """
165 2419060d Guido Trotter
  __slots__ = [
166 2419060d Guido Trotter
    "_lock",
167 2419060d Guido Trotter
    "acquire",
168 2419060d Guido Trotter
    "release",
169 2419060d Guido Trotter
    ]
170 2419060d Guido Trotter
171 2419060d Guido Trotter
  def __init__(self, lock):
172 2419060d Guido Trotter
    """Constructor for _BaseCondition.
173 2419060d Guido Trotter

174 69b99987 Michael Hanselmann
    @type lock: threading.Lock
175 2419060d Guido Trotter
    @param lock: condition base lock
176 2419060d Guido Trotter

177 2419060d Guido Trotter
    """
178 2419060d Guido Trotter
    object.__init__(self)
179 2419060d Guido Trotter
180 2419060d Guido Trotter
    # Recursive locks are not supported
181 2419060d Guido Trotter
    assert not hasattr(lock, "_acquire_restore")
182 2419060d Guido Trotter
    assert not hasattr(lock, "_release_save")
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 2419060d Guido Trotter
  def _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
198 2419060d Guido Trotter
    return True
199 2419060d Guido Trotter
200 2419060d Guido Trotter
  def _check_owned(self):
201 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
202 2419060d Guido Trotter

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

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

217 d76167a5 Michael Hanselmann
  """
218 34cb5617 Guido Trotter
219 34cb5617 Guido Trotter
  __slots__ = _BaseCondition.__slots__ + [
220 d76167a5 Michael Hanselmann
    "_poller",
221 d76167a5 Michael Hanselmann
    "_read_fd",
222 d76167a5 Michael Hanselmann
    "_write_fd",
223 d76167a5 Michael Hanselmann
    "_nwaiters",
224 34cb5617 Guido Trotter
    "_notified",
225 d76167a5 Michael Hanselmann
    ]
226 d76167a5 Michael Hanselmann
227 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
228 d76167a5 Michael Hanselmann
229 34cb5617 Guido Trotter
  def __init__(self, lock):
230 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
231 d76167a5 Michael Hanselmann

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

243 69b99987 Michael Hanselmann
    """
244 34cb5617 Guido Trotter
    if self._notified:
245 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
246 d76167a5 Michael Hanselmann
247 34cb5617 Guido Trotter
  def _Cleanup(self):
248 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
249 d76167a5 Michael Hanselmann

250 d76167a5 Michael Hanselmann
    """
251 34cb5617 Guido Trotter
    if self._read_fd is not None:
252 34cb5617 Guido Trotter
      os.close(self._read_fd)
253 34cb5617 Guido Trotter
      self._read_fd = None
254 d76167a5 Michael Hanselmann
255 34cb5617 Guido Trotter
    if self._write_fd is not None:
256 34cb5617 Guido Trotter
      os.close(self._write_fd)
257 34cb5617 Guido Trotter
      self._write_fd = None
258 34cb5617 Guido Trotter
    self._poller = None
259 d76167a5 Michael Hanselmann
260 34cb5617 Guido Trotter
  def wait(self, timeout=None):
261 34cb5617 Guido Trotter
    """Wait for a notification.
262 d76167a5 Michael Hanselmann

263 34cb5617 Guido Trotter
    @type timeout: float or None
264 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
265 d76167a5 Michael Hanselmann

266 d76167a5 Michael Hanselmann
    """
267 34cb5617 Guido Trotter
    self._check_owned()
268 34cb5617 Guido Trotter
    self._check_unnotified()
269 d76167a5 Michael Hanselmann
270 34cb5617 Guido Trotter
    self._nwaiters += 1
271 34cb5617 Guido Trotter
    try:
272 34cb5617 Guido Trotter
      if self._poller is None:
273 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
274 34cb5617 Guido Trotter
        self._poller = select.poll()
275 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
276 d76167a5 Michael Hanselmann
277 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
278 34cb5617 Guido Trotter
      self.release()
279 34cb5617 Guido Trotter
      try:
280 34cb5617 Guido Trotter
        # Wait for notification
281 34cb5617 Guido Trotter
        wait_fn(timeout)
282 34cb5617 Guido Trotter
      finally:
283 34cb5617 Guido Trotter
        # Re-acquire lock
284 34cb5617 Guido Trotter
        self.acquire()
285 34cb5617 Guido Trotter
    finally:
286 34cb5617 Guido Trotter
      self._nwaiters -= 1
287 34cb5617 Guido Trotter
      if self._nwaiters == 0:
288 34cb5617 Guido Trotter
        self._Cleanup()
289 d76167a5 Michael Hanselmann
290 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
291 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
292 d76167a5 Michael Hanselmann

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

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

311 48dabc6a Michael Hanselmann
  """
312 2419060d Guido Trotter
  __slots__ = _BaseCondition.__slots__ + [
313 48dabc6a Michael Hanselmann
    "_nwaiters",
314 34cb5617 Guido Trotter
    "_single_condition",
315 48dabc6a Michael Hanselmann
    ]
316 48dabc6a Michael Hanselmann
317 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
318 48dabc6a Michael Hanselmann
319 48dabc6a Michael Hanselmann
  def __init__(self, lock):
320 48dabc6a Michael Hanselmann
    """Initializes this class.
321 48dabc6a Michael Hanselmann

322 48dabc6a Michael Hanselmann
    """
323 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
324 48dabc6a Michael Hanselmann
    self._nwaiters = 0
325 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
326 48dabc6a Michael Hanselmann
327 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
328 48dabc6a Michael Hanselmann
    """Wait for a notification.
329 48dabc6a Michael Hanselmann

330 48dabc6a Michael Hanselmann
    @type timeout: float or None
331 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
332 48dabc6a Michael Hanselmann

333 48dabc6a Michael Hanselmann
    """
334 48dabc6a Michael Hanselmann
    self._check_owned()
335 48dabc6a Michael Hanselmann
336 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
337 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
338 34cb5617 Guido Trotter
    my_condition = self._single_condition
339 48dabc6a Michael Hanselmann
340 48dabc6a Michael Hanselmann
    assert self._nwaiters >= 0
341 48dabc6a Michael Hanselmann
    self._nwaiters += 1
342 48dabc6a Michael Hanselmann
    try:
343 34cb5617 Guido Trotter
      my_condition.wait(timeout)
344 48dabc6a Michael Hanselmann
    finally:
345 48dabc6a Michael Hanselmann
      assert self._nwaiters > 0
346 48dabc6a Michael Hanselmann
      self._nwaiters -= 1
347 48dabc6a Michael Hanselmann
348 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
349 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
350 48dabc6a Michael Hanselmann

351 48dabc6a Michael Hanselmann
    """
352 48dabc6a Michael Hanselmann
    self._check_owned()
353 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
354 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
355 48dabc6a Michael Hanselmann
356 48dabc6a Michael Hanselmann
  def has_waiting(self):
357 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
358 48dabc6a Michael Hanselmann

359 48dabc6a Michael Hanselmann
    """
360 48dabc6a Michael Hanselmann
    self._check_owned()
361 48dabc6a Michael Hanselmann
362 48dabc6a Michael Hanselmann
    return bool(self._nwaiters)
363 48dabc6a Michael Hanselmann
364 48dabc6a Michael Hanselmann
365 84e344d4 Michael Hanselmann
class _CountingCondition(object):
366 84e344d4 Michael Hanselmann
  """Wrapper for Python's built-in threading.Condition class.
367 84e344d4 Michael Hanselmann

368 84e344d4 Michael Hanselmann
  This wrapper keeps a count of active waiters. We can't access the internal
369 84e344d4 Michael Hanselmann
  "__waiters" attribute of threading.Condition because it's not thread-safe.
370 84e344d4 Michael Hanselmann

371 84e344d4 Michael Hanselmann
  """
372 84e344d4 Michael Hanselmann
  __slots__ = [
373 84e344d4 Michael Hanselmann
    "_cond",
374 84e344d4 Michael Hanselmann
    "_nwaiters",
375 84e344d4 Michael Hanselmann
    ]
376 84e344d4 Michael Hanselmann
377 84e344d4 Michael Hanselmann
  def __init__(self, lock):
378 84e344d4 Michael Hanselmann
    """Initializes this class.
379 84e344d4 Michael Hanselmann

380 84e344d4 Michael Hanselmann
    """
381 84e344d4 Michael Hanselmann
    object.__init__(self)
382 84e344d4 Michael Hanselmann
    self._cond = threading.Condition(lock=lock)
383 84e344d4 Michael Hanselmann
    self._nwaiters = 0
384 84e344d4 Michael Hanselmann
385 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
386 84e344d4 Michael Hanselmann
    """Notifies the condition.
387 84e344d4 Michael Hanselmann

388 84e344d4 Michael Hanselmann
    """
389 84e344d4 Michael Hanselmann
    return self._cond.notifyAll()
390 84e344d4 Michael Hanselmann
391 84e344d4 Michael Hanselmann
  def wait(self, timeout=None):
392 84e344d4 Michael Hanselmann
    """Waits for the condition to be notified.
393 84e344d4 Michael Hanselmann

394 84e344d4 Michael Hanselmann
    @type timeout: float or None
395 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
396 84e344d4 Michael Hanselmann

397 84e344d4 Michael Hanselmann
    """
398 84e344d4 Michael Hanselmann
    assert self._nwaiters >= 0
399 84e344d4 Michael Hanselmann
400 84e344d4 Michael Hanselmann
    self._nwaiters += 1
401 84e344d4 Michael Hanselmann
    try:
402 84e344d4 Michael Hanselmann
      return self._cond.wait(timeout=timeout)
403 84e344d4 Michael Hanselmann
    finally:
404 84e344d4 Michael Hanselmann
      self._nwaiters -= 1
405 84e344d4 Michael Hanselmann
406 84e344d4 Michael Hanselmann
  def has_waiting(self):
407 84e344d4 Michael Hanselmann
    """Returns whether there are active waiters.
408 84e344d4 Michael Hanselmann

409 84e344d4 Michael Hanselmann
    """
410 84e344d4 Michael Hanselmann
    return bool(self._nwaiters)
411 84e344d4 Michael Hanselmann
412 84e344d4 Michael Hanselmann
413 84e344d4 Michael Hanselmann
class SharedLock(object):
414 162c1c1f Guido Trotter
  """Implements a shared lock.
415 162c1c1f Guido Trotter

416 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
417 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
418 162c1c1f Guido Trotter
  can call acquire_exclusive().
419 162c1c1f Guido Trotter

420 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
421 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
422 162c1c1f Guido Trotter
  eventually do so.
423 162c1c1f Guido Trotter

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

440 84e344d4 Michael Hanselmann
    """
441 84e344d4 Michael Hanselmann
    object.__init__(self)
442 84e344d4 Michael Hanselmann
443 84e344d4 Michael Hanselmann
    # Internal lock
444 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
445 162c1c1f Guido Trotter
446 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
447 84e344d4 Michael Hanselmann
    self.__pending = []
448 84e344d4 Michael Hanselmann
449 84e344d4 Michael Hanselmann
    # Active and inactive conditions for shared locks
450 84e344d4 Michael Hanselmann
    self.__active_shr_c = self.__condition_class(self.__lock)
451 84e344d4 Michael Hanselmann
    self.__inactive_shr_c = self.__condition_class(self.__lock)
452 84e344d4 Michael Hanselmann
453 84e344d4 Michael Hanselmann
    # Current lock holders
454 162c1c1f Guido Trotter
    self.__shr = set()
455 162c1c1f Guido Trotter
    self.__exc = None
456 162c1c1f Guido Trotter
457 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
458 a95fd5d7 Guido Trotter
    self.__deleted = False
459 a95fd5d7 Guido Trotter
460 84e344d4 Michael Hanselmann
  def __check_deleted(self):
461 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
462 84e344d4 Michael Hanselmann

463 84e344d4 Michael Hanselmann
    """
464 84e344d4 Michael Hanselmann
    if self.__deleted:
465 84e344d4 Michael Hanselmann
      raise errors.LockError("Deleted lock")
466 84e344d4 Michael Hanselmann
467 162c1c1f Guido Trotter
  def __is_sharer(self):
468 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
469 84e344d4 Michael Hanselmann

470 84e344d4 Michael Hanselmann
    """
471 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
472 162c1c1f Guido Trotter
473 162c1c1f Guido Trotter
  def __is_exclusive(self):
474 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
475 84e344d4 Michael Hanselmann

476 84e344d4 Michael Hanselmann
    """
477 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
478 162c1c1f Guido Trotter
479 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
480 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
481 162c1c1f Guido Trotter

482 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
483 162c1c1f Guido Trotter
    the internal lock.
484 162c1c1f Guido Trotter

485 162c1c1f Guido Trotter
    """
486 162c1c1f Guido Trotter
    if shared < 0:
487 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
488 162c1c1f Guido Trotter
    elif shared:
489 162c1c1f Guido Trotter
      return self.__is_sharer()
490 162c1c1f Guido Trotter
    else:
491 162c1c1f Guido Trotter
      return self.__is_exclusive()
492 162c1c1f Guido Trotter
493 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
494 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
495 162c1c1f Guido Trotter

496 c41eea6e Iustin Pop
    @param shared:
497 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
498 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
499 c41eea6e Iustin Pop
        - > 0: check for shared ownership
500 162c1c1f Guido Trotter

501 162c1c1f Guido Trotter
    """
502 162c1c1f Guido Trotter
    self.__lock.acquire()
503 162c1c1f Guido Trotter
    try:
504 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
505 162c1c1f Guido Trotter
    finally:
506 162c1c1f Guido Trotter
      self.__lock.release()
507 162c1c1f Guido Trotter
508 84e344d4 Michael Hanselmann
  def _count_pending(self):
509 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
510 a95fd5d7 Guido Trotter

511 84e344d4 Michael Hanselmann
    @rtype: int
512 a95fd5d7 Guido Trotter

513 a95fd5d7 Guido Trotter
    """
514 84e344d4 Michael Hanselmann
    self.__lock.acquire()
515 84e344d4 Michael Hanselmann
    try:
516 84e344d4 Michael Hanselmann
      return len(self.__pending)
517 84e344d4 Michael Hanselmann
    finally:
518 84e344d4 Michael Hanselmann
      self.__lock.release()
519 a95fd5d7 Guido Trotter
520 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
521 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
522 84e344d4 Michael Hanselmann

523 84e344d4 Michael Hanselmann
    """
524 84e344d4 Michael Hanselmann
    if shared:
525 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
526 84e344d4 Michael Hanselmann
    else:
527 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
528 a95fd5d7 Guido Trotter
529 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
530 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
531 a95fd5d7 Guido Trotter

532 a95fd5d7 Guido Trotter
    """
533 84e344d4 Michael Hanselmann
    if shared:
534 84e344d4 Michael Hanselmann
      return self.__exc is None
535 84e344d4 Michael Hanselmann
    else:
536 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
537 a95fd5d7 Guido Trotter
538 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
539 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
540 a95fd5d7 Guido Trotter

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

543 84e344d4 Michael Hanselmann
    """
544 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
545 4d686df8 Guido Trotter
546 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
547 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
548 9216a9f7 Michael Hanselmann

549 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
550 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
551 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
552 9216a9f7 Michael Hanselmann

553 9216a9f7 Michael Hanselmann
    """
554 84e344d4 Michael Hanselmann
    self.__check_deleted()
555 9216a9f7 Michael Hanselmann
556 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
557 84e344d4 Michael Hanselmann
    assert not self.__is_owned(), "double acquire() on a non-recursive lock"
558 84e344d4 Michael Hanselmann
559 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
560 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
561 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
562 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
563 84e344d4 Michael Hanselmann
      return True
564 9216a9f7 Michael Hanselmann
565 84e344d4 Michael Hanselmann
    if shared:
566 84e344d4 Michael Hanselmann
      wait_condition = self.__active_shr_c
567 9216a9f7 Michael Hanselmann
568 84e344d4 Michael Hanselmann
      # Check if we're not yet in the queue
569 84e344d4 Michael Hanselmann
      if wait_condition not in self.__pending:
570 84e344d4 Michael Hanselmann
        self.__pending.append(wait_condition)
571 84e344d4 Michael Hanselmann
    else:
572 84e344d4 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock)
573 84e344d4 Michael Hanselmann
      # Always add to queue
574 84e344d4 Michael Hanselmann
      self.__pending.append(wait_condition)
575 84e344d4 Michael Hanselmann
576 84e344d4 Michael Hanselmann
    try:
577 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
578 84e344d4 Michael Hanselmann
      # expires.
579 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
580 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
581 84e344d4 Michael Hanselmann
        # Wait for notification
582 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
583 84e344d4 Michael Hanselmann
        self.__check_deleted()
584 84e344d4 Michael Hanselmann
585 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
586 84e344d4 Michael Hanselmann
        # internally for that case.
587 84e344d4 Michael Hanselmann
        if timeout is not None:
588 84e344d4 Michael Hanselmann
          break
589 84e344d4 Michael Hanselmann
590 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
591 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
592 84e344d4 Michael Hanselmann
        return True
593 9216a9f7 Michael Hanselmann
    finally:
594 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
595 84e344d4 Michael Hanselmann
      if not wait_condition.has_waiting() and not self.__deleted:
596 84e344d4 Michael Hanselmann
        self.__pending.remove(wait_condition)
597 9216a9f7 Michael Hanselmann
598 84e344d4 Michael Hanselmann
    return False
599 9216a9f7 Michael Hanselmann
600 008b92fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, test_notify=None):
601 162c1c1f Guido Trotter
    """Acquire a shared lock.
602 162c1c1f Guido Trotter

603 84e344d4 Michael Hanselmann
    @type shared: int
604 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
605 c41eea6e Iustin Pop
        exclusive lock will be acquired
606 84e344d4 Michael Hanselmann
    @type timeout: float
607 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
608 008b92fa Michael Hanselmann
    @type test_notify: callable or None
609 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
610 162c1c1f Guido Trotter

611 162c1c1f Guido Trotter
    """
612 162c1c1f Guido Trotter
    self.__lock.acquire()
613 162c1c1f Guido Trotter
    try:
614 008b92fa Michael Hanselmann
      # We already got the lock, notify now
615 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
616 008b92fa Michael Hanselmann
        test_notify()
617 008b92fa Michael Hanselmann
618 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
619 162c1c1f Guido Trotter
    finally:
620 162c1c1f Guido Trotter
      self.__lock.release()
621 162c1c1f Guido Trotter
622 162c1c1f Guido Trotter
  def release(self):
623 162c1c1f Guido Trotter
    """Release a Shared Lock.
624 162c1c1f Guido Trotter

625 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
626 162c1c1f Guido Trotter
    before calling this function.
627 162c1c1f Guido Trotter

628 162c1c1f Guido Trotter
    """
629 162c1c1f Guido Trotter
    self.__lock.acquire()
630 162c1c1f Guido Trotter
    try:
631 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
632 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
633 84e344d4 Michael Hanselmann
634 162c1c1f Guido Trotter
      # Autodetect release type
635 162c1c1f Guido Trotter
      if self.__is_exclusive():
636 162c1c1f Guido Trotter
        self.__exc = None
637 84e344d4 Michael Hanselmann
      else:
638 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
639 162c1c1f Guido Trotter
640 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
641 84e344d4 Michael Hanselmann
      if self.__pending:
642 84e344d4 Michael Hanselmann
        first_condition = self.__pending[0]
643 84e344d4 Michael Hanselmann
        first_condition.notifyAll()
644 4d686df8 Guido Trotter
645 84e344d4 Michael Hanselmann
        if first_condition == self.__active_shr_c:
646 84e344d4 Michael Hanselmann
          self.__active_shr_c = self.__inactive_shr_c
647 84e344d4 Michael Hanselmann
          self.__inactive_shr_c = first_condition
648 162c1c1f Guido Trotter
649 162c1c1f Guido Trotter
    finally:
650 162c1c1f Guido Trotter
      self.__lock.release()
651 162c1c1f Guido Trotter
652 84e344d4 Michael Hanselmann
  def delete(self, timeout=None):
653 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
654 a95fd5d7 Guido Trotter

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

659 84e344d4 Michael Hanselmann
    @type timeout: float
660 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
661 a95fd5d7 Guido Trotter

662 a95fd5d7 Guido Trotter
    """
663 a95fd5d7 Guido Trotter
    self.__lock.acquire()
664 a95fd5d7 Guido Trotter
    try:
665 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
666 84e344d4 Michael Hanselmann
667 84e344d4 Michael Hanselmann
      self.__check_deleted()
668 a95fd5d7 Guido Trotter
669 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
670 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
671 a95fd5d7 Guido Trotter
672 84e344d4 Michael Hanselmann
      if not acquired:
673 a66bd91b Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout)
674 a66bd91b Michael Hanselmann
675 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
676 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
677 84e344d4 Michael Hanselmann
678 84e344d4 Michael Hanselmann
      if acquired:
679 84e344d4 Michael Hanselmann
        self.__deleted = True
680 84e344d4 Michael Hanselmann
        self.__exc = None
681 a95fd5d7 Guido Trotter
682 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
683 84e344d4 Michael Hanselmann
        while self.__pending:
684 84e344d4 Michael Hanselmann
          self.__pending.pop().notifyAll()
685 a95fd5d7 Guido Trotter
686 84e344d4 Michael Hanselmann
      return acquired
687 a95fd5d7 Guido Trotter
    finally:
688 a95fd5d7 Guido Trotter
      self.__lock.release()
689 a95fd5d7 Guido Trotter
690 aaae9bc0 Guido Trotter
691 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
692 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
693 e310b019 Guido Trotter
ALL_SET = None
694 e310b019 Guido Trotter
695 e310b019 Guido Trotter
696 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
697 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
698 5aab242c Michael Hanselmann

699 5aab242c Michael Hanselmann
  """
700 5aab242c Michael Hanselmann
701 5aab242c Michael Hanselmann
702 aaae9bc0 Guido Trotter
class LockSet:
703 aaae9bc0 Guido Trotter
  """Implements a set of locks.
704 aaae9bc0 Guido Trotter

705 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
706 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
707 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
708 aaae9bc0 Guido Trotter
  preventing deadlock.
709 aaae9bc0 Guido Trotter

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

712 aaae9bc0 Guido Trotter
  """
713 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
714 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
715 aaae9bc0 Guido Trotter

716 c41eea6e Iustin Pop
    @param members: initial members of the set
717 aaae9bc0 Guido Trotter

718 aaae9bc0 Guido Trotter
    """
719 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
720 aaae9bc0 Guido Trotter
    self.__lock = SharedLock()
721 aaae9bc0 Guido Trotter
722 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
723 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
724 aaae9bc0 Guido Trotter
    self.__lockdict = {}
725 aaae9bc0 Guido Trotter
726 aaae9bc0 Guido Trotter
    if members is not None:
727 aaae9bc0 Guido Trotter
      for name in members:
728 aaae9bc0 Guido Trotter
        self.__lockdict[name] = SharedLock()
729 aaae9bc0 Guido Trotter
730 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
731 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
732 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
733 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
734 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
735 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
736 aaae9bc0 Guido Trotter
    # will be trouble.
737 aaae9bc0 Guido Trotter
    self.__owners = {}
738 aaae9bc0 Guido Trotter
739 aaae9bc0 Guido Trotter
  def _is_owned(self):
740 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
741 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
742 aaae9bc0 Guido Trotter
743 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
744 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
745 b2dabfd6 Guido Trotter
    if name is None:
746 b2dabfd6 Guido Trotter
      if not self._is_owned():
747 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
748 aaae9bc0 Guido Trotter
    else:
749 b2dabfd6 Guido Trotter
      if self._is_owned():
750 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
751 b2dabfd6 Guido Trotter
      else:
752 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
753 b2dabfd6 Guido Trotter
754 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
755 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
756 aaae9bc0 Guido Trotter
757 e4335b5b Michael Hanselmann
    assert not (name is None and self.__lock._is_owned()), \
758 e4335b5b Michael Hanselmann
           "Cannot hold internal lock when deleting owner status"
759 e4335b5b Michael Hanselmann
760 b2dabfd6 Guido Trotter
    if name is not None:
761 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
762 b2dabfd6 Guido Trotter
763 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
764 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
765 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
766 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
767 aaae9bc0 Guido Trotter
768 aaae9bc0 Guido Trotter
  def _list_owned(self):
769 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
770 aaae9bc0 Guido Trotter
    if self._is_owned():
771 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
772 aaae9bc0 Guido Trotter
    else:
773 aaae9bc0 Guido Trotter
      return set()
774 aaae9bc0 Guido Trotter
775 5aab242c Michael Hanselmann
  def _release_and_delete_owned(self):
776 5aab242c Michael Hanselmann
    """Release and delete all resources owned by the current thread"""
777 5aab242c Michael Hanselmann
    for lname in self._list_owned():
778 56452af7 Michael Hanselmann
      lock = self.__lockdict[lname]
779 56452af7 Michael Hanselmann
      if lock._is_owned():
780 56452af7 Michael Hanselmann
        lock.release()
781 5aab242c Michael Hanselmann
      self._del_owned(name=lname)
782 5aab242c Michael Hanselmann
783 aaae9bc0 Guido Trotter
  def __names(self):
784 aaae9bc0 Guido Trotter
    """Return the current set of names.
785 aaae9bc0 Guido Trotter

786 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
787 aaae9bc0 Guido Trotter
    result after releasing the lock.
788 aaae9bc0 Guido Trotter

789 aaae9bc0 Guido Trotter
    """
790 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
791 aaae9bc0 Guido Trotter
792 aaae9bc0 Guido Trotter
  def _names(self):
793 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
794 aaae9bc0 Guido Trotter

795 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
796 cdb08f44 Michael Hanselmann

797 aaae9bc0 Guido Trotter
    """
798 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
799 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
800 d4803c24 Guido Trotter
    release_lock = False
801 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
802 d4803c24 Guido Trotter
      release_lock = True
803 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
804 aaae9bc0 Guido Trotter
    try:
805 aaae9bc0 Guido Trotter
      result = self.__names()
806 aaae9bc0 Guido Trotter
    finally:
807 d4803c24 Guido Trotter
      if release_lock:
808 d4803c24 Guido Trotter
        self.__lock.release()
809 0cf257c5 Guido Trotter
    return set(result)
810 aaae9bc0 Guido Trotter
811 5aab242c Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, test_notify=None):
812 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
813 aaae9bc0 Guido Trotter

814 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
815 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
816 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
817 c41eea6e Iustin Pop
        exclusive lock will be acquired
818 5aab242c Michael Hanselmann
    @type timeout: float or None
819 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
820 5aab242c Michael Hanselmann
    @type test_notify: callable or None
821 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
822 aaae9bc0 Guido Trotter

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

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

829 aaae9bc0 Guido Trotter
    """
830 5aab242c Michael Hanselmann
    assert timeout is None or timeout >= 0.0
831 aaae9bc0 Guido Trotter
832 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
833 aaae9bc0 Guido Trotter
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
834 aaae9bc0 Guido Trotter
835 5aab242c Michael Hanselmann
    # We need to keep track of how long we spent waiting for a lock. The
836 5aab242c Michael Hanselmann
    # timeout passed to this function is over all lock acquires.
837 7e8841bd Michael Hanselmann
    running_timeout = RunningTimeout(timeout, False)
838 5aab242c Michael Hanselmann
839 806e20fd Guido Trotter
    try:
840 76e2f08a Michael Hanselmann
      if names is not None:
841 5aab242c Michael Hanselmann
        # Support passing in a single resource to acquire rather than many
842 5aab242c Michael Hanselmann
        if isinstance(names, basestring):
843 5aab242c Michael Hanselmann
          names = [names]
844 5aab242c Michael Hanselmann
845 76e2f08a Michael Hanselmann
        return self.__acquire_inner(names, False, shared,
846 7e8841bd Michael Hanselmann
                                    running_timeout.Remaining, test_notify)
847 76e2f08a Michael Hanselmann
848 76e2f08a Michael Hanselmann
      else:
849 76e2f08a Michael Hanselmann
        # If no names are given acquire the whole set by not letting new names
850 76e2f08a Michael Hanselmann
        # being added before we release, and getting the current list of names.
851 76e2f08a Michael Hanselmann
        # Some of them may then be deleted later, but we'll cope with this.
852 76e2f08a Michael Hanselmann
        #
853 76e2f08a Michael Hanselmann
        # We'd like to acquire this lock in a shared way, as it's nice if
854 76e2f08a Michael Hanselmann
        # everybody else can use the instances at the same time. If are
855 76e2f08a Michael Hanselmann
        # acquiring them exclusively though they won't be able to do this
856 76e2f08a Michael Hanselmann
        # anyway, though, so we'll get the list lock exclusively as well in
857 76e2f08a Michael Hanselmann
        # order to be able to do add() on the set while owning it.
858 76e2f08a Michael Hanselmann
        if not self.__lock.acquire(shared=shared,
859 7e8841bd Michael Hanselmann
                                   timeout=running_timeout.Remaining()):
860 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
861 76e2f08a Michael Hanselmann
        try:
862 76e2f08a Michael Hanselmann
          # note we own the set-lock
863 76e2f08a Michael Hanselmann
          self._add_owned()
864 76e2f08a Michael Hanselmann
865 76e2f08a Michael Hanselmann
          return self.__acquire_inner(self.__names(), True, shared,
866 7e8841bd Michael Hanselmann
                                      running_timeout.Remaining, test_notify)
867 76e2f08a Michael Hanselmann
        except:
868 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
869 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
870 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong, after this.
871 5aab242c Michael Hanselmann
          self.__lock.release()
872 76e2f08a Michael Hanselmann
          self._del_owned()
873 76e2f08a Michael Hanselmann
          raise
874 5aab242c Michael Hanselmann
875 5aab242c Michael Hanselmann
    except _AcquireTimeout:
876 5aab242c Michael Hanselmann
      return None
877 aaae9bc0 Guido Trotter
878 76e2f08a Michael Hanselmann
  def __acquire_inner(self, names, want_all, shared, timeout_fn, test_notify):
879 7e8841bd Michael Hanselmann
    """Inner logic for acquiring a number of locks.
880 7e8841bd Michael Hanselmann

881 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
882 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
883 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
884 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
885 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
886 76e2f08a Michael Hanselmann

887 76e2f08a Michael Hanselmann
    """
888 76e2f08a Michael Hanselmann
    acquire_list = []
889 76e2f08a Michael Hanselmann
890 76e2f08a Michael Hanselmann
    # First we look the locks up on __lockdict. We have no way of being sure
891 76e2f08a Michael Hanselmann
    # they will still be there after, but this makes it a lot faster should
892 71e1863e Michael Hanselmann
    # just one of them be the already wrong. Using a sorted sequence to prevent
893 71e1863e Michael Hanselmann
    # deadlocks.
894 71e1863e Michael Hanselmann
    for lname in sorted(utils.UniqueSequence(names)):
895 76e2f08a Michael Hanselmann
      try:
896 76e2f08a Michael Hanselmann
        lock = self.__lockdict[lname] # raises KeyError if lock is not there
897 76e2f08a Michael Hanselmann
      except KeyError:
898 76e2f08a Michael Hanselmann
        if want_all:
899 76e2f08a Michael Hanselmann
          # We are acquiring all the set, it doesn't matter if this particular
900 76e2f08a Michael Hanselmann
          # element is not there anymore.
901 76e2f08a Michael Hanselmann
          continue
902 76e2f08a Michael Hanselmann
903 76e2f08a Michael Hanselmann
        raise errors.LockError("Non-existing lock in set (%s)" % lname)
904 76e2f08a Michael Hanselmann
905 9b154270 Michael Hanselmann
      acquire_list.append((lname, lock))
906 9b154270 Michael Hanselmann
907 76e2f08a Michael Hanselmann
    # This will hold the locknames we effectively acquired.
908 76e2f08a Michael Hanselmann
    acquired = set()
909 76e2f08a Michael Hanselmann
910 76e2f08a Michael Hanselmann
    try:
911 76e2f08a Michael Hanselmann
      # Now acquire_list contains a sorted list of resources and locks we
912 76e2f08a Michael Hanselmann
      # want.  In order to get them we loop on this (private) list and
913 76e2f08a Michael Hanselmann
      # acquire() them.  We gave no real guarantee they will still exist till
914 76e2f08a Michael Hanselmann
      # this is done but .acquire() itself is safe and will alert us if the
915 76e2f08a Michael Hanselmann
      # lock gets deleted.
916 76e2f08a Michael Hanselmann
      for (lname, lock) in acquire_list:
917 76e2f08a Michael Hanselmann
        if __debug__ and callable(test_notify):
918 76e2f08a Michael Hanselmann
          test_notify_fn = lambda: test_notify(lname)
919 76e2f08a Michael Hanselmann
        else:
920 76e2f08a Michael Hanselmann
          test_notify_fn = None
921 76e2f08a Michael Hanselmann
922 76e2f08a Michael Hanselmann
        timeout = timeout_fn()
923 76e2f08a Michael Hanselmann
924 76e2f08a Michael Hanselmann
        try:
925 76e2f08a Michael Hanselmann
          # raises LockError if the lock was deleted
926 76e2f08a Michael Hanselmann
          acq_success = lock.acquire(shared=shared, timeout=timeout,
927 76e2f08a Michael Hanselmann
                                     test_notify=test_notify_fn)
928 76e2f08a Michael Hanselmann
        except errors.LockError:
929 76e2f08a Michael Hanselmann
          if want_all:
930 76e2f08a Michael Hanselmann
            # We are acquiring all the set, it doesn't matter if this
931 76e2f08a Michael Hanselmann
            # particular element is not there anymore.
932 76e2f08a Michael Hanselmann
            continue
933 76e2f08a Michael Hanselmann
934 76e2f08a Michael Hanselmann
          raise errors.LockError("Non-existing lock in set (%s)" % lname)
935 76e2f08a Michael Hanselmann
936 76e2f08a Michael Hanselmann
        if not acq_success:
937 76e2f08a Michael Hanselmann
          # Couldn't get lock or timeout occurred
938 76e2f08a Michael Hanselmann
          if timeout is None:
939 76e2f08a Michael Hanselmann
            # This shouldn't happen as SharedLock.acquire(timeout=None) is
940 76e2f08a Michael Hanselmann
            # blocking.
941 76e2f08a Michael Hanselmann
            raise errors.LockError("Failed to get lock %s" % lname)
942 76e2f08a Michael Hanselmann
943 76e2f08a Michael Hanselmann
          raise _AcquireTimeout()
944 76e2f08a Michael Hanselmann
945 76e2f08a Michael Hanselmann
        try:
946 76e2f08a Michael Hanselmann
          # now the lock cannot be deleted, we have it!
947 76e2f08a Michael Hanselmann
          self._add_owned(name=lname)
948 76e2f08a Michael Hanselmann
          acquired.add(lname)
949 76e2f08a Michael Hanselmann
950 76e2f08a Michael Hanselmann
        except:
951 76e2f08a Michael Hanselmann
          # We shouldn't have problems adding the lock to the owners list, but
952 76e2f08a Michael Hanselmann
          # if we did we'll try to release this lock and re-raise exception.
953 76e2f08a Michael Hanselmann
          # Of course something is going to be really wrong after this.
954 76e2f08a Michael Hanselmann
          if lock._is_owned():
955 76e2f08a Michael Hanselmann
            lock.release()
956 76e2f08a Michael Hanselmann
          raise
957 76e2f08a Michael Hanselmann
958 76e2f08a Michael Hanselmann
    except:
959 76e2f08a Michael Hanselmann
      # Release all owned locks
960 76e2f08a Michael Hanselmann
      self._release_and_delete_owned()
961 76e2f08a Michael Hanselmann
      raise
962 76e2f08a Michael Hanselmann
963 0cc00929 Guido Trotter
    return acquired
964 aaae9bc0 Guido Trotter
965 aaae9bc0 Guido Trotter
  def release(self, names=None):
966 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
967 aaae9bc0 Guido Trotter

968 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
969 aaae9bc0 Guido Trotter
    before releasing them.
970 aaae9bc0 Guido Trotter

971 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
972 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level).
973 aaae9bc0 Guido Trotter

974 aaae9bc0 Guido Trotter
    """
975 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
976 aaae9bc0 Guido Trotter
977 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
978 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
979 aaae9bc0 Guido Trotter
      names = [names]
980 aaae9bc0 Guido Trotter
981 aaae9bc0 Guido Trotter
    if names is None:
982 aaae9bc0 Guido Trotter
      names = self._list_owned()
983 aaae9bc0 Guido Trotter
    else:
984 aaae9bc0 Guido Trotter
      names = set(names)
985 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
986 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
987 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
988 aaae9bc0 Guido Trotter
989 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
990 3b7ed473 Guido Trotter
    # After this 'add' can work again
991 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
992 3b7ed473 Guido Trotter
      self.__lock.release()
993 b2dabfd6 Guido Trotter
      self._del_owned()
994 3b7ed473 Guido Trotter
995 aaae9bc0 Guido Trotter
    for lockname in names:
996 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
997 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
998 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
999 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1000 aaae9bc0 Guido Trotter
1001 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1002 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1003 aaae9bc0 Guido Trotter

1004 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1005 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1006 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1007 aaae9bc0 Guido Trotter

1008 aaae9bc0 Guido Trotter
    """
1009 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
1010 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
1011 d2aff862 Guido Trotter
      "Cannot add locks if the set is only partially owned, or shared"
1012 3b7ed473 Guido Trotter
1013 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
1014 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1015 aaae9bc0 Guido Trotter
      names = [names]
1016 aaae9bc0 Guido Trotter
1017 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
1018 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
1019 3b7ed473 Guido Trotter
    release_lock = False
1020 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
1021 3b7ed473 Guido Trotter
      release_lock = True
1022 3b7ed473 Guido Trotter
      self.__lock.acquire()
1023 3b7ed473 Guido Trotter
1024 aaae9bc0 Guido Trotter
    try:
1025 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
1026 aaae9bc0 Guido Trotter
      if invalid_names:
1027 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
1028 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
1029 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
1030 aaae9bc0 Guido Trotter
        raise errors.LockError("duplicate add() (%s)" % invalid_names)
1031 aaae9bc0 Guido Trotter
1032 aaae9bc0 Guido Trotter
      for lockname in names:
1033 aaae9bc0 Guido Trotter
        lock = SharedLock()
1034 aaae9bc0 Guido Trotter
1035 aaae9bc0 Guido Trotter
        if acquired:
1036 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
1037 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
1038 aaae9bc0 Guido Trotter
          try:
1039 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
1040 aaae9bc0 Guido Trotter
          except:
1041 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
1042 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
1043 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
1044 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
1045 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
1046 aaae9bc0 Guido Trotter
            # release is just a safety measure.
1047 aaae9bc0 Guido Trotter
            lock.release()
1048 aaae9bc0 Guido Trotter
            raise
1049 aaae9bc0 Guido Trotter
1050 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
1051 aaae9bc0 Guido Trotter
1052 aaae9bc0 Guido Trotter
    finally:
1053 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
1054 3b7ed473 Guido Trotter
      if release_lock:
1055 3b7ed473 Guido Trotter
        self.__lock.release()
1056 aaae9bc0 Guido Trotter
1057 aaae9bc0 Guido Trotter
    return True
1058 aaae9bc0 Guido Trotter
1059 5e0a6daf Michael Hanselmann
  def remove(self, names):
1060 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
1061 aaae9bc0 Guido Trotter

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

1065 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1066 aaae9bc0 Guido Trotter

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

1071 aaae9bc0 Guido Trotter
    """
1072 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
1073 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
1074 aaae9bc0 Guido Trotter
      names = [names]
1075 aaae9bc0 Guido Trotter
1076 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
1077 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
1078 aaae9bc0 Guido Trotter
    # by the lock itself.
1079 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
1080 aaae9bc0 Guido Trotter
      "remove() on acquired lockset while not owning all elements")
1081 aaae9bc0 Guido Trotter
1082 3f404fc5 Guido Trotter
    removed = []
1083 aaae9bc0 Guido Trotter
1084 aaae9bc0 Guido Trotter
    for lname in names:
1085 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
1086 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
1087 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
1088 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
1089 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
1090 aaae9bc0 Guido Trotter
      try:
1091 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
1092 3f404fc5 Guido Trotter
        removed.append(lname)
1093 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
1094 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
1095 aaae9bc0 Guido Trotter
        assert not self._is_owned(), "remove failed while holding lockset"
1096 aaae9bc0 Guido Trotter
      else:
1097 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
1098 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
1099 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
1100 aaae9bc0 Guido Trotter
        # since before our call to delete()).
1101 aaae9bc0 Guido Trotter
        #
1102 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
1103 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
1104 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
1105 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
1106 aaae9bc0 Guido Trotter
        if self._is_owned():
1107 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
1108 aaae9bc0 Guido Trotter
1109 3f404fc5 Guido Trotter
    return removed
1110 aaae9bc0 Guido Trotter
1111 7ee7c0c7 Guido Trotter
1112 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
1113 7ee7c0c7 Guido Trotter
# Current rules are:
1114 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
1115 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
1116 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
1117 7ee7c0c7 Guido Trotter
#   avoided.
1118 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
1119 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
1120 7ee7c0c7 Guido Trotter
#   the same time.
1121 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
1122 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
1123 04e1bfaf Guido Trotter
LEVEL_NODE = 2
1124 7ee7c0c7 Guido Trotter
1125 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
1126 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
1127 04e1bfaf Guido Trotter
          LEVEL_NODE]
1128 7ee7c0c7 Guido Trotter
1129 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
1130 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
1131 7ee7c0c7 Guido Trotter
1132 ea205dbc Michael Hanselmann
LEVEL_NAMES = {
1133 ea205dbc Michael Hanselmann
  LEVEL_CLUSTER: "cluster",
1134 ea205dbc Michael Hanselmann
  LEVEL_INSTANCE: "instance",
1135 ea205dbc Michael Hanselmann
  LEVEL_NODE: "node",
1136 ea205dbc Michael Hanselmann
  }
1137 ea205dbc Michael Hanselmann
1138 08a6c581 Guido Trotter
# Constant for the big ganeti lock
1139 7ee7c0c7 Guido Trotter
BGL = 'BGL'
1140 7ee7c0c7 Guido Trotter
1141 7ee7c0c7 Guido Trotter
1142 7ee7c0c7 Guido Trotter
class GanetiLockManager:
1143 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
1144 7ee7c0c7 Guido Trotter

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

1150 7ee7c0c7 Guido Trotter
  """
1151 7ee7c0c7 Guido Trotter
  _instance = None
1152 7ee7c0c7 Guido Trotter
1153 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1154 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1155 7ee7c0c7 Guido Trotter

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

1159 c41eea6e Iustin Pop
    @param nodes: list of node names
1160 c41eea6e Iustin Pop
    @param instances: list of instance names
1161 7ee7c0c7 Guido Trotter

1162 7ee7c0c7 Guido Trotter
    """
1163 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1164 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1165 c41eea6e Iustin Pop
1166 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1167 7ee7c0c7 Guido Trotter
1168 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1169 7ee7c0c7 Guido Trotter
    # locking order.
1170 7ee7c0c7 Guido Trotter
    self.__keyring = {
1171 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
1172 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
1173 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
1174 7ee7c0c7 Guido Trotter
    }
1175 7ee7c0c7 Guido Trotter
1176 7ee7c0c7 Guido Trotter
  def _names(self, level):
1177 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1178 7ee7c0c7 Guido Trotter

1179 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1180 c41eea6e Iustin Pop

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

1183 7ee7c0c7 Guido Trotter
    """
1184 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1185 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1186 7ee7c0c7 Guido Trotter
1187 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1188 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1189 7ee7c0c7 Guido Trotter

1190 7ee7c0c7 Guido Trotter
    """
1191 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1192 7ee7c0c7 Guido Trotter
1193 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1194 d4f4b3e7 Guido Trotter
1195 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1196 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1197 7ee7c0c7 Guido Trotter

1198 7ee7c0c7 Guido Trotter
    """
1199 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1200 7ee7c0c7 Guido Trotter
1201 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1202 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1203 7ee7c0c7 Guido Trotter

1204 7ee7c0c7 Guido Trotter
    """
1205 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1206 7ee7c0c7 Guido Trotter
    # the test cases.
1207 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1208 7ee7c0c7 Guido Trotter
1209 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1210 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1211 7ee7c0c7 Guido Trotter

1212 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1213 7ee7c0c7 Guido Trotter

1214 7ee7c0c7 Guido Trotter
    """
1215 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1216 7ee7c0c7 Guido Trotter
1217 c70d2d9b Iustin Pop
  @staticmethod
1218 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1219 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1220 c41eea6e Iustin Pop

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

1224 7ee7c0c7 Guido Trotter
    """
1225 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1226 7ee7c0c7 Guido Trotter
1227 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1228 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1229 7ee7c0c7 Guido Trotter

1230 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be acquired;
1231 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS.
1232 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1233 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1234 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1235 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1236 5e0a6daf Michael Hanselmann
    @type timeout: float
1237 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1238 7ee7c0c7 Guido Trotter

1239 7ee7c0c7 Guido Trotter
    """
1240 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1241 7ee7c0c7 Guido Trotter
1242 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1243 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1244 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1245 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1246 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1247 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1248 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1249 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1250 7ee7c0c7 Guido Trotter
1251 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1252 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1253 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1254 7ee7c0c7 Guido Trotter
1255 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1256 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1257 7ee7c0c7 Guido Trotter
1258 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1259 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1260 7ee7c0c7 Guido Trotter

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

1264 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be released;
1265 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS
1266 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1267 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1268 7ee7c0c7 Guido Trotter

1269 7ee7c0c7 Guido Trotter
    """
1270 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1271 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1272 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1273 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1274 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1275 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1276 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1277 7ee7c0c7 Guido Trotter
1278 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1279 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1280 7ee7c0c7 Guido Trotter
1281 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1282 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1283 7ee7c0c7 Guido Trotter

1284 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be added;
1285 5bbd3f7f Michael Hanselmann
        it must be a member of LEVELS_MOD.
1286 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1287 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1288 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1289 c41eea6e Iustin Pop

1290 7ee7c0c7 Guido Trotter
    """
1291 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1292 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1293 7ee7c0c7 Guido Trotter
           " operations")
1294 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1295 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1296 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1297 7ee7c0c7 Guido Trotter
1298 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1299 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1300 7ee7c0c7 Guido Trotter

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

1304 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be removed;
1305 c41eea6e Iustin Pop
        it must be a member of LEVELS_MOD
1306 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1307 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1308 7ee7c0c7 Guido Trotter

1309 7ee7c0c7 Guido Trotter
    """
1310 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1311 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1312 7ee7c0c7 Guido Trotter
           " operations")
1313 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1314 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1315 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1316 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1317 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1318 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1319 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)