Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 7c4c22f5

History | View | Annotate | Download (41.1 kB)

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

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

46 dbb11e8b Guido Trotter
  @type mylock: lockable object or string
47 dbb11e8b Guido Trotter
  @param mylock: lock to acquire or class member name of the lock to acquire
48 dbb11e8b Guido Trotter

49 42a999d1 Guido Trotter
  """
50 42a999d1 Guido Trotter
  def wrap(fn):
51 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
52 dbb11e8b Guido Trotter
      if isinstance(mylock, basestring):
53 dbb11e8b Guido Trotter
        assert args, "cannot ssynchronize on non-class method: self not found"
54 dbb11e8b Guido Trotter
        # args[0] is "self"
55 dbb11e8b Guido Trotter
        lock = getattr(args[0], mylock)
56 dbb11e8b Guido Trotter
      else:
57 dbb11e8b Guido Trotter
        lock = mylock
58 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
59 42a999d1 Guido Trotter
      try:
60 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
61 42a999d1 Guido Trotter
      finally:
62 42a999d1 Guido Trotter
        lock.release()
63 42a999d1 Guido Trotter
    return sync_function
64 42a999d1 Guido Trotter
  return wrap
65 42a999d1 Guido Trotter
66 42a999d1 Guido Trotter
67 7e8841bd Michael Hanselmann
class RunningTimeout(object):
68 7e8841bd Michael Hanselmann
  """Class to calculate remaining timeout when doing several operations.
69 7e8841bd Michael Hanselmann

70 7e8841bd Michael Hanselmann
  """
71 7e8841bd Michael Hanselmann
  __slots__ = [
72 7e8841bd Michael Hanselmann
    "_allow_negative",
73 7e8841bd Michael Hanselmann
    "_start_time",
74 7e8841bd Michael Hanselmann
    "_time_fn",
75 7e8841bd Michael Hanselmann
    "_timeout",
76 7e8841bd Michael Hanselmann
    ]
77 7e8841bd Michael Hanselmann
78 7e8841bd Michael Hanselmann
  def __init__(self, timeout, allow_negative, _time_fn=time.time):
79 7e8841bd Michael Hanselmann
    """Initializes this class.
80 7e8841bd Michael Hanselmann

81 7e8841bd Michael Hanselmann
    @type timeout: float
82 7e8841bd Michael Hanselmann
    @param timeout: Timeout duration
83 7e8841bd Michael Hanselmann
    @type allow_negative: bool
84 7e8841bd Michael Hanselmann
    @param allow_negative: Whether to return values below zero
85 7e8841bd Michael Hanselmann
    @param _time_fn: Time function for unittests
86 7e8841bd Michael Hanselmann

87 7e8841bd Michael Hanselmann
    """
88 7e8841bd Michael Hanselmann
    object.__init__(self)
89 7e8841bd Michael Hanselmann
90 7e8841bd Michael Hanselmann
    if timeout is not None and timeout < 0.0:
91 7e8841bd Michael Hanselmann
      raise ValueError("Timeout must not be negative")
92 7e8841bd Michael Hanselmann
93 7e8841bd Michael Hanselmann
    self._timeout = timeout
94 7e8841bd Michael Hanselmann
    self._allow_negative = allow_negative
95 7e8841bd Michael Hanselmann
    self._time_fn = _time_fn
96 7e8841bd Michael Hanselmann
97 7e8841bd Michael Hanselmann
    self._start_time = None
98 7e8841bd Michael Hanselmann
99 7e8841bd Michael Hanselmann
  def Remaining(self):
100 7e8841bd Michael Hanselmann
    """Returns the remaining timeout.
101 7e8841bd Michael Hanselmann

102 7e8841bd Michael Hanselmann
    """
103 7e8841bd Michael Hanselmann
    if self._timeout is None:
104 7e8841bd Michael Hanselmann
      return None
105 7e8841bd Michael Hanselmann
106 7e8841bd Michael Hanselmann
    # Get start time on first calculation
107 7e8841bd Michael Hanselmann
    if self._start_time is None:
108 7e8841bd Michael Hanselmann
      self._start_time = self._time_fn()
109 7e8841bd Michael Hanselmann
110 7e8841bd Michael Hanselmann
    # Calculate remaining time
111 7e8841bd Michael Hanselmann
    remaining_timeout = self._start_time + self._timeout - self._time_fn()
112 7e8841bd Michael Hanselmann
113 7e8841bd Michael Hanselmann
    if not self._allow_negative:
114 7e8841bd Michael Hanselmann
      # Ensure timeout is always >= 0
115 7e8841bd Michael Hanselmann
      return max(0.0, remaining_timeout)
116 7e8841bd Michael Hanselmann
117 7e8841bd Michael Hanselmann
    return remaining_timeout
118 7e8841bd Michael Hanselmann
119 7e8841bd Michael Hanselmann
120 34cb5617 Guido Trotter
class _SingleNotifyPipeConditionWaiter(object):
121 34cb5617 Guido Trotter
  """Helper class for SingleNotifyPipeCondition
122 d76167a5 Michael Hanselmann

123 d76167a5 Michael Hanselmann
  """
124 d76167a5 Michael Hanselmann
  __slots__ = [
125 d76167a5 Michael Hanselmann
    "_fd",
126 d76167a5 Michael Hanselmann
    "_poller",
127 d76167a5 Michael Hanselmann
    ]
128 d76167a5 Michael Hanselmann
129 34cb5617 Guido Trotter
  def __init__(self, poller, fd):
130 34cb5617 Guido Trotter
    """Constructor for _SingleNotifyPipeConditionWaiter
131 d76167a5 Michael Hanselmann

132 d76167a5 Michael Hanselmann
    @type poller: select.poll
133 d76167a5 Michael Hanselmann
    @param poller: Poller object
134 d76167a5 Michael Hanselmann
    @type fd: int
135 d76167a5 Michael Hanselmann
    @param fd: File descriptor to wait for
136 d76167a5 Michael Hanselmann

137 d76167a5 Michael Hanselmann
    """
138 d76167a5 Michael Hanselmann
    object.__init__(self)
139 d76167a5 Michael Hanselmann
    self._poller = poller
140 d76167a5 Michael Hanselmann
    self._fd = fd
141 d76167a5 Michael Hanselmann
142 d76167a5 Michael Hanselmann
  def __call__(self, timeout):
143 d76167a5 Michael Hanselmann
    """Wait for something to happen on the pipe.
144 d76167a5 Michael Hanselmann

145 d76167a5 Michael Hanselmann
    @type timeout: float or None
146 d76167a5 Michael Hanselmann
    @param timeout: Timeout for waiting (can be None)
147 d76167a5 Michael Hanselmann

148 d76167a5 Michael Hanselmann
    """
149 f4e673fb Michael Hanselmann
    running_timeout = RunningTimeout(timeout, True)
150 f4e673fb Michael Hanselmann
151 f4e673fb Michael Hanselmann
    while True:
152 f4e673fb Michael Hanselmann
      remaining_time = running_timeout.Remaining()
153 f4e673fb Michael Hanselmann
154 b44b0141 Michael Hanselmann
      if remaining_time is not None:
155 b44b0141 Michael Hanselmann
        if remaining_time < 0.0:
156 b44b0141 Michael Hanselmann
          break
157 d76167a5 Michael Hanselmann
158 413b7472 Michael Hanselmann
        # Our calculation uses seconds, poll() wants milliseconds
159 b44b0141 Michael Hanselmann
        remaining_time *= 1000
160 d76167a5 Michael Hanselmann
161 d76167a5 Michael Hanselmann
      try:
162 d76167a5 Michael Hanselmann
        result = self._poller.poll(remaining_time)
163 d76167a5 Michael Hanselmann
      except EnvironmentError, err:
164 d76167a5 Michael Hanselmann
        if err.errno != errno.EINTR:
165 d76167a5 Michael Hanselmann
          raise
166 d76167a5 Michael Hanselmann
        result = None
167 d76167a5 Michael Hanselmann
168 d76167a5 Michael Hanselmann
      # Check whether we were notified
169 d76167a5 Michael Hanselmann
      if result and result[0][0] == self._fd:
170 d76167a5 Michael Hanselmann
        break
171 d76167a5 Michael Hanselmann
172 d76167a5 Michael Hanselmann
173 2419060d Guido Trotter
class _BaseCondition(object):
174 2419060d Guido Trotter
  """Base class containing common code for conditions.
175 2419060d Guido Trotter

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

178 2419060d Guido Trotter
  """
179 2419060d Guido Trotter
  __slots__ = [
180 2419060d Guido Trotter
    "_lock",
181 2419060d Guido Trotter
    "acquire",
182 2419060d Guido Trotter
    "release",
183 7f890059 Guido Trotter
    "_is_owned",
184 7f890059 Guido Trotter
    "_acquire_restore",
185 7f890059 Guido Trotter
    "_release_save",
186 2419060d Guido Trotter
    ]
187 2419060d Guido Trotter
188 2419060d Guido Trotter
  def __init__(self, lock):
189 2419060d Guido Trotter
    """Constructor for _BaseCondition.
190 2419060d Guido Trotter

191 69b99987 Michael Hanselmann
    @type lock: threading.Lock
192 2419060d Guido Trotter
    @param lock: condition base lock
193 2419060d Guido Trotter

194 2419060d Guido Trotter
    """
195 2419060d Guido Trotter
    object.__init__(self)
196 2419060d Guido Trotter
197 7f890059 Guido Trotter
    try:
198 7f890059 Guido Trotter
      self._release_save = lock._release_save
199 7f890059 Guido Trotter
    except AttributeError:
200 7f890059 Guido Trotter
      self._release_save = self._base_release_save
201 7f890059 Guido Trotter
    try:
202 7f890059 Guido Trotter
      self._acquire_restore = lock._acquire_restore
203 7f890059 Guido Trotter
    except AttributeError:
204 7f890059 Guido Trotter
      self._acquire_restore = self._base_acquire_restore
205 7f890059 Guido Trotter
    try:
206 7f890059 Guido Trotter
      self._is_owned = lock._is_owned
207 7f890059 Guido Trotter
    except AttributeError:
208 7f890059 Guido Trotter
      self._is_owned = self._base_is_owned
209 2419060d Guido Trotter
210 2419060d Guido Trotter
    self._lock = lock
211 2419060d Guido Trotter
212 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
213 2419060d Guido Trotter
    self.acquire = lock.acquire
214 2419060d Guido Trotter
    self.release = lock.release
215 2419060d Guido Trotter
216 7f890059 Guido Trotter
  def _base_is_owned(self):
217 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
218 2419060d Guido Trotter

219 2419060d Guido Trotter
    """
220 2419060d Guido Trotter
    if self._lock.acquire(0):
221 2419060d Guido Trotter
      self._lock.release()
222 2419060d Guido Trotter
      return False
223 2419060d Guido Trotter
    return True
224 2419060d Guido Trotter
225 7f890059 Guido Trotter
  def _base_release_save(self):
226 7f890059 Guido Trotter
    self._lock.release()
227 7f890059 Guido Trotter
228 7f890059 Guido Trotter
  def _base_acquire_restore(self, _):
229 7f890059 Guido Trotter
    self._lock.acquire()
230 7f890059 Guido Trotter
231 2419060d Guido Trotter
  def _check_owned(self):
232 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
233 2419060d Guido Trotter

234 2419060d Guido Trotter
    """
235 2419060d Guido Trotter
    if not self._is_owned():
236 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
237 2419060d Guido Trotter
238 2419060d Guido Trotter
239 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
240 34cb5617 Guido Trotter
  """Condition which can only be notified once.
241 d76167a5 Michael Hanselmann

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

248 d76167a5 Michael Hanselmann
  """
249 34cb5617 Guido Trotter
250 154b9580 Balazs Lecz
  __slots__ = [
251 d76167a5 Michael Hanselmann
    "_poller",
252 d76167a5 Michael Hanselmann
    "_read_fd",
253 d76167a5 Michael Hanselmann
    "_write_fd",
254 d76167a5 Michael Hanselmann
    "_nwaiters",
255 34cb5617 Guido Trotter
    "_notified",
256 d76167a5 Michael Hanselmann
    ]
257 d76167a5 Michael Hanselmann
258 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
259 d76167a5 Michael Hanselmann
260 34cb5617 Guido Trotter
  def __init__(self, lock):
261 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
262 d76167a5 Michael Hanselmann

263 d76167a5 Michael Hanselmann
    """
264 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
265 d76167a5 Michael Hanselmann
    self._nwaiters = 0
266 34cb5617 Guido Trotter
    self._notified = False
267 34cb5617 Guido Trotter
    self._read_fd = None
268 34cb5617 Guido Trotter
    self._write_fd = None
269 34cb5617 Guido Trotter
    self._poller = None
270 d76167a5 Michael Hanselmann
271 34cb5617 Guido Trotter
  def _check_unnotified(self):
272 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
273 69b99987 Michael Hanselmann

274 69b99987 Michael Hanselmann
    """
275 34cb5617 Guido Trotter
    if self._notified:
276 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
277 d76167a5 Michael Hanselmann
278 34cb5617 Guido Trotter
  def _Cleanup(self):
279 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
280 d76167a5 Michael Hanselmann

281 d76167a5 Michael Hanselmann
    """
282 34cb5617 Guido Trotter
    if self._read_fd is not None:
283 34cb5617 Guido Trotter
      os.close(self._read_fd)
284 34cb5617 Guido Trotter
      self._read_fd = None
285 d76167a5 Michael Hanselmann
286 34cb5617 Guido Trotter
    if self._write_fd is not None:
287 34cb5617 Guido Trotter
      os.close(self._write_fd)
288 34cb5617 Guido Trotter
      self._write_fd = None
289 34cb5617 Guido Trotter
    self._poller = None
290 d76167a5 Michael Hanselmann
291 34cb5617 Guido Trotter
  def wait(self, timeout=None):
292 34cb5617 Guido Trotter
    """Wait for a notification.
293 d76167a5 Michael Hanselmann

294 34cb5617 Guido Trotter
    @type timeout: float or None
295 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
296 d76167a5 Michael Hanselmann

297 d76167a5 Michael Hanselmann
    """
298 34cb5617 Guido Trotter
    self._check_owned()
299 34cb5617 Guido Trotter
    self._check_unnotified()
300 d76167a5 Michael Hanselmann
301 34cb5617 Guido Trotter
    self._nwaiters += 1
302 34cb5617 Guido Trotter
    try:
303 34cb5617 Guido Trotter
      if self._poller is None:
304 34cb5617 Guido Trotter
        (self._read_fd, self._write_fd) = os.pipe()
305 34cb5617 Guido Trotter
        self._poller = select.poll()
306 34cb5617 Guido Trotter
        self._poller.register(self._read_fd, select.POLLHUP)
307 d76167a5 Michael Hanselmann
308 34cb5617 Guido Trotter
      wait_fn = self._waiter_class(self._poller, self._read_fd)
309 7f890059 Guido Trotter
      state = self._release_save()
310 34cb5617 Guido Trotter
      try:
311 34cb5617 Guido Trotter
        # Wait for notification
312 34cb5617 Guido Trotter
        wait_fn(timeout)
313 34cb5617 Guido Trotter
      finally:
314 34cb5617 Guido Trotter
        # Re-acquire lock
315 7f890059 Guido Trotter
        self._acquire_restore(state)
316 34cb5617 Guido Trotter
    finally:
317 34cb5617 Guido Trotter
      self._nwaiters -= 1
318 34cb5617 Guido Trotter
      if self._nwaiters == 0:
319 34cb5617 Guido Trotter
        self._Cleanup()
320 d76167a5 Michael Hanselmann
321 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
322 d76167a5 Michael Hanselmann
    """Close the writing side of the pipe to notify all waiters.
323 d76167a5 Michael Hanselmann

324 d76167a5 Michael Hanselmann
    """
325 34cb5617 Guido Trotter
    self._check_owned()
326 34cb5617 Guido Trotter
    self._check_unnotified()
327 34cb5617 Guido Trotter
    self._notified = True
328 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
329 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
330 d76167a5 Michael Hanselmann
      self._write_fd = None
331 d76167a5 Michael Hanselmann
332 d76167a5 Michael Hanselmann
333 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
334 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
335 48dabc6a Michael Hanselmann

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

342 48dabc6a Michael Hanselmann
  """
343 154b9580 Balazs Lecz
  __slots__ = [
344 48dabc6a Michael Hanselmann
    "_nwaiters",
345 34cb5617 Guido Trotter
    "_single_condition",
346 48dabc6a Michael Hanselmann
    ]
347 48dabc6a Michael Hanselmann
348 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
349 48dabc6a Michael Hanselmann
350 48dabc6a Michael Hanselmann
  def __init__(self, lock):
351 48dabc6a Michael Hanselmann
    """Initializes this class.
352 48dabc6a Michael Hanselmann

353 48dabc6a Michael Hanselmann
    """
354 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
355 48dabc6a Michael Hanselmann
    self._nwaiters = 0
356 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
357 48dabc6a Michael Hanselmann
358 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
359 48dabc6a Michael Hanselmann
    """Wait for a notification.
360 48dabc6a Michael Hanselmann

361 48dabc6a Michael Hanselmann
    @type timeout: float or None
362 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
363 48dabc6a Michael Hanselmann

364 48dabc6a Michael Hanselmann
    """
365 48dabc6a Michael Hanselmann
    self._check_owned()
366 48dabc6a Michael Hanselmann
367 48dabc6a Michael Hanselmann
    # Keep local reference to the pipe. It could be replaced by another thread
368 48dabc6a Michael Hanselmann
    # notifying while we're waiting.
369 34cb5617 Guido Trotter
    my_condition = self._single_condition
370 48dabc6a Michael Hanselmann
371 48dabc6a Michael Hanselmann
    assert self._nwaiters >= 0
372 48dabc6a Michael Hanselmann
    self._nwaiters += 1
373 48dabc6a Michael Hanselmann
    try:
374 34cb5617 Guido Trotter
      my_condition.wait(timeout)
375 48dabc6a Michael Hanselmann
    finally:
376 48dabc6a Michael Hanselmann
      assert self._nwaiters > 0
377 48dabc6a Michael Hanselmann
      self._nwaiters -= 1
378 48dabc6a Michael Hanselmann
379 7260cfbe Iustin Pop
  def notifyAll(self): # pylint: disable-msg=C0103
380 48dabc6a Michael Hanselmann
    """Notify all currently waiting threads.
381 48dabc6a Michael Hanselmann

382 48dabc6a Michael Hanselmann
    """
383 48dabc6a Michael Hanselmann
    self._check_owned()
384 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
385 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
386 48dabc6a Michael Hanselmann
387 48dabc6a Michael Hanselmann
  def has_waiting(self):
388 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
389 48dabc6a Michael Hanselmann

390 48dabc6a Michael Hanselmann
    """
391 48dabc6a Michael Hanselmann
    self._check_owned()
392 48dabc6a Michael Hanselmann
393 48dabc6a Michael Hanselmann
    return bool(self._nwaiters)
394 48dabc6a Michael Hanselmann
395 48dabc6a Michael Hanselmann
396 84e344d4 Michael Hanselmann
class SharedLock(object):
397 162c1c1f Guido Trotter
  """Implements a shared lock.
398 162c1c1f Guido Trotter

399 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
400 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
401 162c1c1f Guido Trotter
  can call acquire_exclusive().
402 162c1c1f Guido Trotter

403 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
404 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
405 162c1c1f Guido Trotter
  eventually do so.
406 162c1c1f Guido Trotter

407 7f93570a Iustin Pop
  @type name: string
408 7f93570a Iustin Pop
  @ivar name: the name of the lock
409 7f93570a Iustin Pop

410 162c1c1f Guido Trotter
  """
411 84e344d4 Michael Hanselmann
  __slots__ = [
412 84e344d4 Michael Hanselmann
    "__active_shr_c",
413 84e344d4 Michael Hanselmann
    "__inactive_shr_c",
414 84e344d4 Michael Hanselmann
    "__deleted",
415 84e344d4 Michael Hanselmann
    "__exc",
416 84e344d4 Michael Hanselmann
    "__lock",
417 84e344d4 Michael Hanselmann
    "__pending",
418 84e344d4 Michael Hanselmann
    "__shr",
419 7f93570a Iustin Pop
    "name",
420 84e344d4 Michael Hanselmann
    ]
421 84e344d4 Michael Hanselmann
422 34cb5617 Guido Trotter
  __condition_class = PipeCondition
423 84e344d4 Michael Hanselmann
424 7f93570a Iustin Pop
  def __init__(self, name):
425 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
426 84e344d4 Michael Hanselmann

427 7f93570a Iustin Pop
    @param name: the name of the lock
428 7f93570a Iustin Pop

429 84e344d4 Michael Hanselmann
    """
430 84e344d4 Michael Hanselmann
    object.__init__(self)
431 84e344d4 Michael Hanselmann
432 7f93570a Iustin Pop
    self.name = name
433 7f93570a Iustin Pop
434 84e344d4 Michael Hanselmann
    # Internal lock
435 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
436 162c1c1f Guido Trotter
437 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
438 84e344d4 Michael Hanselmann
    self.__pending = []
439 84e344d4 Michael Hanselmann
440 84e344d4 Michael Hanselmann
    # Active and inactive conditions for shared locks
441 84e344d4 Michael Hanselmann
    self.__active_shr_c = self.__condition_class(self.__lock)
442 84e344d4 Michael Hanselmann
    self.__inactive_shr_c = self.__condition_class(self.__lock)
443 84e344d4 Michael Hanselmann
444 84e344d4 Michael Hanselmann
    # Current lock holders
445 162c1c1f Guido Trotter
    self.__shr = set()
446 162c1c1f Guido Trotter
    self.__exc = None
447 162c1c1f Guido Trotter
448 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
449 a95fd5d7 Guido Trotter
    self.__deleted = False
450 a95fd5d7 Guido Trotter
451 84e344d4 Michael Hanselmann
  def __check_deleted(self):
452 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
453 84e344d4 Michael Hanselmann

454 84e344d4 Michael Hanselmann
    """
455 84e344d4 Michael Hanselmann
    if self.__deleted:
456 7f93570a Iustin Pop
      raise errors.LockError("Deleted lock %s" % self.name)
457 84e344d4 Michael Hanselmann
458 162c1c1f Guido Trotter
  def __is_sharer(self):
459 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
460 84e344d4 Michael Hanselmann

461 84e344d4 Michael Hanselmann
    """
462 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
463 162c1c1f Guido Trotter
464 162c1c1f Guido Trotter
  def __is_exclusive(self):
465 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
466 84e344d4 Michael Hanselmann

467 84e344d4 Michael Hanselmann
    """
468 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
469 162c1c1f Guido Trotter
470 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
471 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
472 162c1c1f Guido Trotter

473 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
474 162c1c1f Guido Trotter
    the internal lock.
475 162c1c1f Guido Trotter

476 162c1c1f Guido Trotter
    """
477 162c1c1f Guido Trotter
    if shared < 0:
478 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
479 162c1c1f Guido Trotter
    elif shared:
480 162c1c1f Guido Trotter
      return self.__is_sharer()
481 162c1c1f Guido Trotter
    else:
482 162c1c1f Guido Trotter
      return self.__is_exclusive()
483 162c1c1f Guido Trotter
484 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
485 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
486 162c1c1f Guido Trotter

487 c41eea6e Iustin Pop
    @param shared:
488 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
489 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
490 c41eea6e Iustin Pop
        - > 0: check for shared ownership
491 162c1c1f Guido Trotter

492 162c1c1f Guido Trotter
    """
493 162c1c1f Guido Trotter
    self.__lock.acquire()
494 162c1c1f Guido Trotter
    try:
495 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
496 162c1c1f Guido Trotter
    finally:
497 162c1c1f Guido Trotter
      self.__lock.release()
498 162c1c1f Guido Trotter
499 84e344d4 Michael Hanselmann
  def _count_pending(self):
500 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
501 a95fd5d7 Guido Trotter

502 84e344d4 Michael Hanselmann
    @rtype: int
503 a95fd5d7 Guido Trotter

504 a95fd5d7 Guido Trotter
    """
505 84e344d4 Michael Hanselmann
    self.__lock.acquire()
506 84e344d4 Michael Hanselmann
    try:
507 84e344d4 Michael Hanselmann
      return len(self.__pending)
508 84e344d4 Michael Hanselmann
    finally:
509 84e344d4 Michael Hanselmann
      self.__lock.release()
510 a95fd5d7 Guido Trotter
511 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
512 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
513 84e344d4 Michael Hanselmann

514 84e344d4 Michael Hanselmann
    """
515 84e344d4 Michael Hanselmann
    if shared:
516 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
517 84e344d4 Michael Hanselmann
    else:
518 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
519 a95fd5d7 Guido Trotter
520 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
521 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
522 a95fd5d7 Guido Trotter

523 a95fd5d7 Guido Trotter
    """
524 84e344d4 Michael Hanselmann
    if shared:
525 84e344d4 Michael Hanselmann
      return self.__exc is None
526 84e344d4 Michael Hanselmann
    else:
527 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
528 a95fd5d7 Guido Trotter
529 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
530 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
531 a95fd5d7 Guido Trotter

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

534 84e344d4 Michael Hanselmann
    """
535 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
536 4d686df8 Guido Trotter
537 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
538 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
539 9216a9f7 Michael Hanselmann

540 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
541 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
542 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
543 9216a9f7 Michael Hanselmann

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

595 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
596 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
597 c41eea6e Iustin Pop
        exclusive lock will be acquired
598 84e344d4 Michael Hanselmann
    @type timeout: float
599 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
600 008b92fa Michael Hanselmann
    @type test_notify: callable or None
601 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
602 162c1c1f Guido Trotter

603 162c1c1f Guido Trotter
    """
604 162c1c1f Guido Trotter
    self.__lock.acquire()
605 162c1c1f Guido Trotter
    try:
606 008b92fa Michael Hanselmann
      # We already got the lock, notify now
607 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
608 008b92fa Michael Hanselmann
        test_notify()
609 008b92fa Michael Hanselmann
610 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
611 162c1c1f Guido Trotter
    finally:
612 162c1c1f Guido Trotter
      self.__lock.release()
613 162c1c1f Guido Trotter
614 162c1c1f Guido Trotter
  def release(self):
615 162c1c1f Guido Trotter
    """Release a Shared Lock.
616 162c1c1f Guido Trotter

617 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
618 162c1c1f Guido Trotter
    before calling this function.
619 162c1c1f Guido Trotter

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

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

651 84e344d4 Michael Hanselmann
    @type timeout: float
652 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
653 a95fd5d7 Guido Trotter

654 a95fd5d7 Guido Trotter
    """
655 a95fd5d7 Guido Trotter
    self.__lock.acquire()
656 a95fd5d7 Guido Trotter
    try:
657 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
658 84e344d4 Michael Hanselmann
659 84e344d4 Michael Hanselmann
      self.__check_deleted()
660 a95fd5d7 Guido Trotter
661 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
662 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
663 a95fd5d7 Guido Trotter
664 84e344d4 Michael Hanselmann
      if not acquired:
665 a66bd91b Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout)
666 a66bd91b Michael Hanselmann
667 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
668 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
669 84e344d4 Michael Hanselmann
670 84e344d4 Michael Hanselmann
      if acquired:
671 84e344d4 Michael Hanselmann
        self.__deleted = True
672 84e344d4 Michael Hanselmann
        self.__exc = None
673 a95fd5d7 Guido Trotter
674 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
675 84e344d4 Michael Hanselmann
        while self.__pending:
676 84e344d4 Michael Hanselmann
          self.__pending.pop().notifyAll()
677 a95fd5d7 Guido Trotter
678 84e344d4 Michael Hanselmann
      return acquired
679 a95fd5d7 Guido Trotter
    finally:
680 a95fd5d7 Guido Trotter
      self.__lock.release()
681 a95fd5d7 Guido Trotter
682 1a4e32d0 Guido Trotter
  def _release_save(self):
683 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
684 1a4e32d0 Guido Trotter
    self.release()
685 1a4e32d0 Guido Trotter
    return shared
686 1a4e32d0 Guido Trotter
687 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
688 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
689 1a4e32d0 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 7f93570a Iustin Pop
  @type name: string
713 7f93570a Iustin Pop
  @ivar name: the name of the lockset
714 7f93570a Iustin Pop

715 aaae9bc0 Guido Trotter
  """
716 7f93570a Iustin Pop
  def __init__(self, members, name):
717 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
718 aaae9bc0 Guido Trotter

719 ec44d893 Guido Trotter
    @type members: list of strings
720 c41eea6e Iustin Pop
    @param members: initial members of the set
721 aaae9bc0 Guido Trotter

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

792 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
793 aaae9bc0 Guido Trotter
    result after releasing the lock.
794 aaae9bc0 Guido Trotter

795 aaae9bc0 Guido Trotter
    """
796 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
797 aaae9bc0 Guido Trotter
798 aaae9bc0 Guido Trotter
  def _names(self):
799 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
800 aaae9bc0 Guido Trotter

801 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
802 cdb08f44 Michael Hanselmann

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

820 ec44d893 Guido Trotter
    @type names: list of strings (or string)
821 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
822 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
823 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
824 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
825 c41eea6e Iustin Pop
        exclusive lock will be acquired
826 5aab242c Michael Hanselmann
    @type timeout: float or None
827 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
828 5aab242c Michael Hanselmann
    @type test_notify: callable or None
829 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
830 aaae9bc0 Guido Trotter

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

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

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

890 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
891 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
892 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
893 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
894 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
895 76e2f08a Michael Hanselmann

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

980 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
981 aaae9bc0 Guido Trotter
    before releasing them.
982 aaae9bc0 Guido Trotter

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

987 aaae9bc0 Guido Trotter
    """
988 7f93570a Iustin Pop
    assert self._is_owned(), ("release() on lock set %s while not owner" %
989 7f93570a Iustin Pop
                              self.name)
990 aaae9bc0 Guido Trotter
991 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
992 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
993 aaae9bc0 Guido Trotter
      names = [names]
994 aaae9bc0 Guido Trotter
995 aaae9bc0 Guido Trotter
    if names is None:
996 aaae9bc0 Guido Trotter
      names = self._list_owned()
997 aaae9bc0 Guido Trotter
    else:
998 aaae9bc0 Guido Trotter
      names = set(names)
999 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
1000 7f93570a Iustin Pop
               "release() on unheld resources %s (set %s)" %
1001 7f93570a Iustin Pop
               (names.difference(self._list_owned()), self.name))
1002 aaae9bc0 Guido Trotter
1003 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
1004 3b7ed473 Guido Trotter
    # After this 'add' can work again
1005 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
1006 3b7ed473 Guido Trotter
      self.__lock.release()
1007 b2dabfd6 Guido Trotter
      self._del_owned()
1008 3b7ed473 Guido Trotter
1009 aaae9bc0 Guido Trotter
    for lockname in names:
1010 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
1011 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
1012 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
1013 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
1014 aaae9bc0 Guido Trotter
1015 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
1016 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
1017 aaae9bc0 Guido Trotter

1018 ec44d893 Guido Trotter
    @type names: list of strings
1019 c41eea6e Iustin Pop
    @param names: names of the new elements to add
1020 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1021 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
1022 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1023 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
1024 aaae9bc0 Guido Trotter

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

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

1084 ec44d893 Guido Trotter
    @type names: list of strings
1085 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1086 aaae9bc0 Guido Trotter

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

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

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

1172 7ee7c0c7 Guido Trotter
  """
1173 7ee7c0c7 Guido Trotter
  _instance = None
1174 7ee7c0c7 Guido Trotter
1175 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1176 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1177 7ee7c0c7 Guido Trotter

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

1181 c41eea6e Iustin Pop
    @param nodes: list of node names
1182 c41eea6e Iustin Pop
    @param instances: list of instance names
1183 7ee7c0c7 Guido Trotter

1184 7ee7c0c7 Guido Trotter
    """
1185 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1186 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1187 c41eea6e Iustin Pop
1188 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1189 7ee7c0c7 Guido Trotter
1190 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1191 7ee7c0c7 Guido Trotter
    # locking order.
1192 7ee7c0c7 Guido Trotter
    self.__keyring = {
1193 7f93570a Iustin Pop
      LEVEL_CLUSTER: LockSet([BGL], "bgl lockset"),
1194 7f93570a Iustin Pop
      LEVEL_NODE: LockSet(nodes, "nodes lockset"),
1195 7f93570a Iustin Pop
      LEVEL_INSTANCE: LockSet(instances, "instances lockset"),
1196 7ee7c0c7 Guido Trotter
    }
1197 7ee7c0c7 Guido Trotter
1198 7ee7c0c7 Guido Trotter
  def _names(self, level):
1199 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1200 7ee7c0c7 Guido Trotter

1201 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1202 c41eea6e Iustin Pop

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

1205 7ee7c0c7 Guido Trotter
    """
1206 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1207 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1208 7ee7c0c7 Guido Trotter
1209 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1210 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1211 7ee7c0c7 Guido Trotter

1212 7ee7c0c7 Guido Trotter
    """
1213 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1214 7ee7c0c7 Guido Trotter
1215 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1216 d4f4b3e7 Guido Trotter
1217 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1218 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1219 7ee7c0c7 Guido Trotter

1220 7ee7c0c7 Guido Trotter
    """
1221 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1222 7ee7c0c7 Guido Trotter
1223 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1224 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1225 7ee7c0c7 Guido Trotter

1226 7ee7c0c7 Guido Trotter
    """
1227 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1228 7ee7c0c7 Guido Trotter
    # the test cases.
1229 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1230 7ee7c0c7 Guido Trotter
1231 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1232 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1233 7ee7c0c7 Guido Trotter

1234 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1235 7ee7c0c7 Guido Trotter

1236 7ee7c0c7 Guido Trotter
    """
1237 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1238 7ee7c0c7 Guido Trotter
1239 c70d2d9b Iustin Pop
  @staticmethod
1240 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1241 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1242 c41eea6e Iustin Pop

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

1246 7ee7c0c7 Guido Trotter
    """
1247 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1248 7ee7c0c7 Guido Trotter
1249 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1250 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1251 7ee7c0c7 Guido Trotter

1252 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1253 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1254 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1255 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1256 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1257 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1258 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1259 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1260 5e0a6daf Michael Hanselmann
    @type timeout: float
1261 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1262 7ee7c0c7 Guido Trotter

1263 7ee7c0c7 Guido Trotter
    """
1264 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1265 7ee7c0c7 Guido Trotter
1266 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
1267 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
1268 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
1269 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
1270 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
1271 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
1272 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
1273 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
1274 7ee7c0c7 Guido Trotter
1275 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
1276 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
1277 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1278 7ee7c0c7 Guido Trotter
1279 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
1280 5e0a6daf Michael Hanselmann
    return self.__keyring[level].acquire(names, shared=shared, timeout=timeout)
1281 7ee7c0c7 Guido Trotter
1282 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
1283 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
1284 7ee7c0c7 Guido Trotter

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

1288 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1289 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1290 ec44d893 Guido Trotter
    @type names: list of strings, or None
1291 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1292 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1293 7ee7c0c7 Guido Trotter

1294 7ee7c0c7 Guido Trotter
    """
1295 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1296 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
1297 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
1298 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
1299 e4335b5b Michael Hanselmann
            " at upper levels (%r)" %
1300 1f864b60 Iustin Pop
            (utils.CommaJoin(["%s=%r" % (LEVEL_NAMES[i], self._list_owned(i))
1301 1f864b60 Iustin Pop
                              for i in self.__keyring.keys()]), ))
1302 7ee7c0c7 Guido Trotter
1303 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
1304 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
1305 7ee7c0c7 Guido Trotter
1306 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
1307 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
1308 7ee7c0c7 Guido Trotter

1309 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1310 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1311 ec44d893 Guido Trotter
    @type names: list of strings
1312 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1313 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1314 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1315 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1316 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1317 c41eea6e Iustin Pop

1318 7ee7c0c7 Guido Trotter
    """
1319 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1320 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1321 7ee7c0c7 Guido Trotter
           " operations")
1322 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
1323 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
1324 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
1325 7ee7c0c7 Guido Trotter
1326 5e0a6daf Michael Hanselmann
  def remove(self, level, names):
1327 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
1328 7ee7c0c7 Guido Trotter

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

1332 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1333 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1334 ec44d893 Guido Trotter
    @type names: list of strings
1335 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1336 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1337 7ee7c0c7 Guido Trotter

1338 7ee7c0c7 Guido Trotter
    """
1339 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
1340 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
1341 7ee7c0c7 Guido Trotter
           " operations")
1342 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
1343 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
1344 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
1345 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
1346 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
1347 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
1348 5e0a6daf Michael Hanselmann
    return self.__keyring[level].remove(names)