Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ adb6d685

History | View | Annotate | Download (39.9 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 cea881e5 Michael Hanselmann
from ganeti import compat
37 162c1c1f Guido Trotter
38 162c1c1f Guido Trotter
39 42a999d1 Guido Trotter
def ssynchronized(lock, 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 42a999d1 Guido Trotter
  """
47 42a999d1 Guido Trotter
  def wrap(fn):
48 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
49 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
50 42a999d1 Guido Trotter
      try:
51 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
52 42a999d1 Guido Trotter
      finally:
53 42a999d1 Guido Trotter
        lock.release()
54 42a999d1 Guido Trotter
    return sync_function
55 42a999d1 Guido Trotter
  return wrap
56 42a999d1 Guido Trotter
57 42a999d1 Guido Trotter
58 7e8841bd Michael Hanselmann
class RunningTimeout(object):
59 7e8841bd Michael Hanselmann
  """Class to calculate remaining timeout when doing several operations.
60 7e8841bd Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

169 2419060d Guido Trotter
  """
170 2419060d Guido Trotter
  __slots__ = [
171 2419060d Guido Trotter
    "_lock",
172 2419060d Guido Trotter
    "acquire",
173 2419060d Guido Trotter
    "release",
174 7f890059 Guido Trotter
    "_is_owned",
175 7f890059 Guido Trotter
    "_acquire_restore",
176 7f890059 Guido Trotter
    "_release_save",
177 2419060d Guido Trotter
    ]
178 2419060d Guido Trotter
179 2419060d Guido Trotter
  def __init__(self, lock):
180 2419060d Guido Trotter
    """Constructor for _BaseCondition.
181 2419060d Guido Trotter

182 69b99987 Michael Hanselmann
    @type lock: threading.Lock
183 2419060d Guido Trotter
    @param lock: condition base lock
184 2419060d Guido Trotter

185 2419060d Guido Trotter
    """
186 2419060d Guido Trotter
    object.__init__(self)
187 2419060d Guido Trotter
188 7f890059 Guido Trotter
    try:
189 7f890059 Guido Trotter
      self._release_save = lock._release_save
190 7f890059 Guido Trotter
    except AttributeError:
191 7f890059 Guido Trotter
      self._release_save = self._base_release_save
192 7f890059 Guido Trotter
    try:
193 7f890059 Guido Trotter
      self._acquire_restore = lock._acquire_restore
194 7f890059 Guido Trotter
    except AttributeError:
195 7f890059 Guido Trotter
      self._acquire_restore = self._base_acquire_restore
196 7f890059 Guido Trotter
    try:
197 7f890059 Guido Trotter
      self._is_owned = lock._is_owned
198 7f890059 Guido Trotter
    except AttributeError:
199 7f890059 Guido Trotter
      self._is_owned = self._base_is_owned
200 2419060d Guido Trotter
201 2419060d Guido Trotter
    self._lock = lock
202 2419060d Guido Trotter
203 2419060d Guido Trotter
    # Export the lock's acquire() and release() methods
204 2419060d Guido Trotter
    self.acquire = lock.acquire
205 2419060d Guido Trotter
    self.release = lock.release
206 2419060d Guido Trotter
207 7f890059 Guido Trotter
  def _base_is_owned(self):
208 2419060d Guido Trotter
    """Check whether lock is owned by current thread.
209 2419060d Guido Trotter

210 2419060d Guido Trotter
    """
211 2419060d Guido Trotter
    if self._lock.acquire(0):
212 2419060d Guido Trotter
      self._lock.release()
213 2419060d Guido Trotter
      return False
214 2419060d Guido Trotter
    return True
215 2419060d Guido Trotter
216 7f890059 Guido Trotter
  def _base_release_save(self):
217 7f890059 Guido Trotter
    self._lock.release()
218 7f890059 Guido Trotter
219 7f890059 Guido Trotter
  def _base_acquire_restore(self, _):
220 7f890059 Guido Trotter
    self._lock.acquire()
221 7f890059 Guido Trotter
222 2419060d Guido Trotter
  def _check_owned(self):
223 2419060d Guido Trotter
    """Raise an exception if the current thread doesn't own the lock.
224 2419060d Guido Trotter

225 2419060d Guido Trotter
    """
226 2419060d Guido Trotter
    if not self._is_owned():
227 2419060d Guido Trotter
      raise RuntimeError("cannot work with un-aquired lock")
228 2419060d Guido Trotter
229 2419060d Guido Trotter
230 34cb5617 Guido Trotter
class SingleNotifyPipeCondition(_BaseCondition):
231 34cb5617 Guido Trotter
  """Condition which can only be notified once.
232 d76167a5 Michael Hanselmann

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

239 d76167a5 Michael Hanselmann
  """
240 34cb5617 Guido Trotter
241 154b9580 Balazs Lecz
  __slots__ = [
242 d76167a5 Michael Hanselmann
    "_poller",
243 d76167a5 Michael Hanselmann
    "_read_fd",
244 d76167a5 Michael Hanselmann
    "_write_fd",
245 d76167a5 Michael Hanselmann
    "_nwaiters",
246 34cb5617 Guido Trotter
    "_notified",
247 d76167a5 Michael Hanselmann
    ]
248 d76167a5 Michael Hanselmann
249 34cb5617 Guido Trotter
  _waiter_class = _SingleNotifyPipeConditionWaiter
250 d76167a5 Michael Hanselmann
251 34cb5617 Guido Trotter
  def __init__(self, lock):
252 34cb5617 Guido Trotter
    """Constructor for SingleNotifyPipeCondition
253 d76167a5 Michael Hanselmann

254 d76167a5 Michael Hanselmann
    """
255 34cb5617 Guido Trotter
    _BaseCondition.__init__(self, lock)
256 d76167a5 Michael Hanselmann
    self._nwaiters = 0
257 34cb5617 Guido Trotter
    self._notified = False
258 34cb5617 Guido Trotter
    self._read_fd = None
259 34cb5617 Guido Trotter
    self._write_fd = None
260 34cb5617 Guido Trotter
    self._poller = None
261 d76167a5 Michael Hanselmann
262 34cb5617 Guido Trotter
  def _check_unnotified(self):
263 69b99987 Michael Hanselmann
    """Throws an exception if already notified.
264 69b99987 Michael Hanselmann

265 69b99987 Michael Hanselmann
    """
266 34cb5617 Guido Trotter
    if self._notified:
267 34cb5617 Guido Trotter
      raise RuntimeError("cannot use already notified condition")
268 d76167a5 Michael Hanselmann
269 34cb5617 Guido Trotter
  def _Cleanup(self):
270 34cb5617 Guido Trotter
    """Cleanup open file descriptors, if any.
271 d76167a5 Michael Hanselmann

272 d76167a5 Michael Hanselmann
    """
273 34cb5617 Guido Trotter
    if self._read_fd is not None:
274 34cb5617 Guido Trotter
      os.close(self._read_fd)
275 34cb5617 Guido Trotter
      self._read_fd = None
276 d76167a5 Michael Hanselmann
277 34cb5617 Guido Trotter
    if self._write_fd is not None:
278 34cb5617 Guido Trotter
      os.close(self._write_fd)
279 34cb5617 Guido Trotter
      self._write_fd = None
280 34cb5617 Guido Trotter
    self._poller = None
281 d76167a5 Michael Hanselmann
282 34cb5617 Guido Trotter
  def wait(self, timeout=None):
283 34cb5617 Guido Trotter
    """Wait for a notification.
284 d76167a5 Michael Hanselmann

285 34cb5617 Guido Trotter
    @type timeout: float or None
286 34cb5617 Guido Trotter
    @param timeout: Waiting timeout (can be None)
287 d76167a5 Michael Hanselmann

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

315 d76167a5 Michael Hanselmann
    """
316 34cb5617 Guido Trotter
    self._check_owned()
317 34cb5617 Guido Trotter
    self._check_unnotified()
318 34cb5617 Guido Trotter
    self._notified = True
319 d76167a5 Michael Hanselmann
    if self._write_fd is not None:
320 d76167a5 Michael Hanselmann
      os.close(self._write_fd)
321 d76167a5 Michael Hanselmann
      self._write_fd = None
322 d76167a5 Michael Hanselmann
323 d76167a5 Michael Hanselmann
324 34cb5617 Guido Trotter
class PipeCondition(_BaseCondition):
325 48dabc6a Michael Hanselmann
  """Group-only non-polling condition with counters.
326 48dabc6a Michael Hanselmann

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

333 48dabc6a Michael Hanselmann
  """
334 154b9580 Balazs Lecz
  __slots__ = [
335 48dabc6a Michael Hanselmann
    "_nwaiters",
336 34cb5617 Guido Trotter
    "_single_condition",
337 48dabc6a Michael Hanselmann
    ]
338 48dabc6a Michael Hanselmann
339 34cb5617 Guido Trotter
  _single_condition_class = SingleNotifyPipeCondition
340 48dabc6a Michael Hanselmann
341 48dabc6a Michael Hanselmann
  def __init__(self, lock):
342 48dabc6a Michael Hanselmann
    """Initializes this class.
343 48dabc6a Michael Hanselmann

344 48dabc6a Michael Hanselmann
    """
345 2419060d Guido Trotter
    _BaseCondition.__init__(self, lock)
346 48dabc6a Michael Hanselmann
    self._nwaiters = 0
347 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
348 48dabc6a Michael Hanselmann
349 48dabc6a Michael Hanselmann
  def wait(self, timeout=None):
350 48dabc6a Michael Hanselmann
    """Wait for a notification.
351 48dabc6a Michael Hanselmann

352 48dabc6a Michael Hanselmann
    @type timeout: float or None
353 48dabc6a Michael Hanselmann
    @param timeout: Waiting timeout (can be None)
354 48dabc6a Michael Hanselmann

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

373 48dabc6a Michael Hanselmann
    """
374 48dabc6a Michael Hanselmann
    self._check_owned()
375 34cb5617 Guido Trotter
    self._single_condition.notifyAll()
376 34cb5617 Guido Trotter
    self._single_condition = self._single_condition_class(self._lock)
377 48dabc6a Michael Hanselmann
378 48dabc6a Michael Hanselmann
  def has_waiting(self):
379 48dabc6a Michael Hanselmann
    """Returns whether there are active waiters.
380 48dabc6a Michael Hanselmann

381 48dabc6a Michael Hanselmann
    """
382 48dabc6a Michael Hanselmann
    self._check_owned()
383 48dabc6a Michael Hanselmann
384 48dabc6a Michael Hanselmann
    return bool(self._nwaiters)
385 48dabc6a Michael Hanselmann
386 48dabc6a Michael Hanselmann
387 84e344d4 Michael Hanselmann
class SharedLock(object):
388 162c1c1f Guido Trotter
  """Implements a shared lock.
389 162c1c1f Guido Trotter

390 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
391 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
392 162c1c1f Guido Trotter
  can call acquire_exclusive().
393 162c1c1f Guido Trotter

394 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
395 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
396 162c1c1f Guido Trotter
  eventually do so.
397 162c1c1f Guido Trotter

398 162c1c1f Guido Trotter
  """
399 84e344d4 Michael Hanselmann
  __slots__ = [
400 84e344d4 Michael Hanselmann
    "__active_shr_c",
401 84e344d4 Michael Hanselmann
    "__inactive_shr_c",
402 84e344d4 Michael Hanselmann
    "__deleted",
403 84e344d4 Michael Hanselmann
    "__exc",
404 84e344d4 Michael Hanselmann
    "__lock",
405 84e344d4 Michael Hanselmann
    "__pending",
406 84e344d4 Michael Hanselmann
    "__shr",
407 84e344d4 Michael Hanselmann
    ]
408 84e344d4 Michael Hanselmann
409 34cb5617 Guido Trotter
  __condition_class = PipeCondition
410 84e344d4 Michael Hanselmann
411 162c1c1f Guido Trotter
  def __init__(self):
412 84e344d4 Michael Hanselmann
    """Construct a new SharedLock.
413 84e344d4 Michael Hanselmann

414 84e344d4 Michael Hanselmann
    """
415 84e344d4 Michael Hanselmann
    object.__init__(self)
416 84e344d4 Michael Hanselmann
417 84e344d4 Michael Hanselmann
    # Internal lock
418 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
419 162c1c1f Guido Trotter
420 84e344d4 Michael Hanselmann
    # Queue containing waiting acquires
421 84e344d4 Michael Hanselmann
    self.__pending = []
422 84e344d4 Michael Hanselmann
423 84e344d4 Michael Hanselmann
    # Active and inactive conditions for shared locks
424 84e344d4 Michael Hanselmann
    self.__active_shr_c = self.__condition_class(self.__lock)
425 84e344d4 Michael Hanselmann
    self.__inactive_shr_c = self.__condition_class(self.__lock)
426 84e344d4 Michael Hanselmann
427 84e344d4 Michael Hanselmann
    # Current lock holders
428 162c1c1f Guido Trotter
    self.__shr = set()
429 162c1c1f Guido Trotter
    self.__exc = None
430 162c1c1f Guido Trotter
431 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
432 a95fd5d7 Guido Trotter
    self.__deleted = False
433 a95fd5d7 Guido Trotter
434 84e344d4 Michael Hanselmann
  def __check_deleted(self):
435 84e344d4 Michael Hanselmann
    """Raises an exception if the lock has been deleted.
436 84e344d4 Michael Hanselmann

437 84e344d4 Michael Hanselmann
    """
438 84e344d4 Michael Hanselmann
    if self.__deleted:
439 84e344d4 Michael Hanselmann
      raise errors.LockError("Deleted lock")
440 84e344d4 Michael Hanselmann
441 162c1c1f Guido Trotter
  def __is_sharer(self):
442 84e344d4 Michael Hanselmann
    """Is the current thread sharing the lock at this time?
443 84e344d4 Michael Hanselmann

444 84e344d4 Michael Hanselmann
    """
445 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
446 162c1c1f Guido Trotter
447 162c1c1f Guido Trotter
  def __is_exclusive(self):
448 84e344d4 Michael Hanselmann
    """Is the current thread holding the lock exclusively at this time?
449 84e344d4 Michael Hanselmann

450 84e344d4 Michael Hanselmann
    """
451 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
452 162c1c1f Guido Trotter
453 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
454 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
455 162c1c1f Guido Trotter

456 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
457 162c1c1f Guido Trotter
    the internal lock.
458 162c1c1f Guido Trotter

459 162c1c1f Guido Trotter
    """
460 162c1c1f Guido Trotter
    if shared < 0:
461 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
462 162c1c1f Guido Trotter
    elif shared:
463 162c1c1f Guido Trotter
      return self.__is_sharer()
464 162c1c1f Guido Trotter
    else:
465 162c1c1f Guido Trotter
      return self.__is_exclusive()
466 162c1c1f Guido Trotter
467 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
468 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
469 162c1c1f Guido Trotter

470 c41eea6e Iustin Pop
    @param shared:
471 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
472 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
473 c41eea6e Iustin Pop
        - > 0: check for shared ownership
474 162c1c1f Guido Trotter

475 162c1c1f Guido Trotter
    """
476 162c1c1f Guido Trotter
    self.__lock.acquire()
477 162c1c1f Guido Trotter
    try:
478 84e344d4 Michael Hanselmann
      return self.__is_owned(shared=shared)
479 162c1c1f Guido Trotter
    finally:
480 162c1c1f Guido Trotter
      self.__lock.release()
481 162c1c1f Guido Trotter
482 84e344d4 Michael Hanselmann
  def _count_pending(self):
483 84e344d4 Michael Hanselmann
    """Returns the number of pending acquires.
484 a95fd5d7 Guido Trotter

485 84e344d4 Michael Hanselmann
    @rtype: int
486 a95fd5d7 Guido Trotter

487 a95fd5d7 Guido Trotter
    """
488 84e344d4 Michael Hanselmann
    self.__lock.acquire()
489 84e344d4 Michael Hanselmann
    try:
490 84e344d4 Michael Hanselmann
      return len(self.__pending)
491 84e344d4 Michael Hanselmann
    finally:
492 84e344d4 Michael Hanselmann
      self.__lock.release()
493 a95fd5d7 Guido Trotter
494 84e344d4 Michael Hanselmann
  def __do_acquire(self, shared):
495 84e344d4 Michael Hanselmann
    """Actually acquire the lock.
496 84e344d4 Michael Hanselmann

497 84e344d4 Michael Hanselmann
    """
498 84e344d4 Michael Hanselmann
    if shared:
499 84e344d4 Michael Hanselmann
      self.__shr.add(threading.currentThread())
500 84e344d4 Michael Hanselmann
    else:
501 84e344d4 Michael Hanselmann
      self.__exc = threading.currentThread()
502 a95fd5d7 Guido Trotter
503 84e344d4 Michael Hanselmann
  def __can_acquire(self, shared):
504 84e344d4 Michael Hanselmann
    """Determine whether lock can be acquired.
505 a95fd5d7 Guido Trotter

506 a95fd5d7 Guido Trotter
    """
507 84e344d4 Michael Hanselmann
    if shared:
508 84e344d4 Michael Hanselmann
      return self.__exc is None
509 84e344d4 Michael Hanselmann
    else:
510 84e344d4 Michael Hanselmann
      return len(self.__shr) == 0 and self.__exc is None
511 a95fd5d7 Guido Trotter
512 84e344d4 Michael Hanselmann
  def __is_on_top(self, cond):
513 84e344d4 Michael Hanselmann
    """Checks whether the passed condition is on top of the queue.
514 a95fd5d7 Guido Trotter

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

517 84e344d4 Michael Hanselmann
    """
518 84e344d4 Michael Hanselmann
    return self.__pending[0] == cond
519 4d686df8 Guido Trotter
520 a66bd91b Michael Hanselmann
  def __acquire_unlocked(self, shared, timeout):
521 84e344d4 Michael Hanselmann
    """Acquire a shared lock.
522 9216a9f7 Michael Hanselmann

523 84e344d4 Michael Hanselmann
    @param shared: whether to acquire in shared mode; by default an
524 84e344d4 Michael Hanselmann
        exclusive lock will be acquired
525 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
526 9216a9f7 Michael Hanselmann

527 9216a9f7 Michael Hanselmann
    """
528 84e344d4 Michael Hanselmann
    self.__check_deleted()
529 9216a9f7 Michael Hanselmann
530 84e344d4 Michael Hanselmann
    # We cannot acquire the lock if we already have it
531 84e344d4 Michael Hanselmann
    assert not self.__is_owned(), "double acquire() on a non-recursive lock"
532 84e344d4 Michael Hanselmann
533 84e344d4 Michael Hanselmann
    # Check whether someone else holds the lock or there are pending acquires.
534 84e344d4 Michael Hanselmann
    if not self.__pending and self.__can_acquire(shared):
535 84e344d4 Michael Hanselmann
      # Apparently not, can acquire lock directly.
536 84e344d4 Michael Hanselmann
      self.__do_acquire(shared)
537 84e344d4 Michael Hanselmann
      return True
538 9216a9f7 Michael Hanselmann
539 84e344d4 Michael Hanselmann
    if shared:
540 84e344d4 Michael Hanselmann
      wait_condition = self.__active_shr_c
541 9216a9f7 Michael Hanselmann
542 84e344d4 Michael Hanselmann
      # Check if we're not yet in the queue
543 84e344d4 Michael Hanselmann
      if wait_condition not in self.__pending:
544 84e344d4 Michael Hanselmann
        self.__pending.append(wait_condition)
545 84e344d4 Michael Hanselmann
    else:
546 84e344d4 Michael Hanselmann
      wait_condition = self.__condition_class(self.__lock)
547 84e344d4 Michael Hanselmann
      # Always add to queue
548 84e344d4 Michael Hanselmann
      self.__pending.append(wait_condition)
549 84e344d4 Michael Hanselmann
550 84e344d4 Michael Hanselmann
    try:
551 84e344d4 Michael Hanselmann
      # Wait until we become the topmost acquire in the queue or the timeout
552 84e344d4 Michael Hanselmann
      # expires.
553 84e344d4 Michael Hanselmann
      while not (self.__is_on_top(wait_condition) and
554 84e344d4 Michael Hanselmann
                 self.__can_acquire(shared)):
555 84e344d4 Michael Hanselmann
        # Wait for notification
556 84e344d4 Michael Hanselmann
        wait_condition.wait(timeout)
557 84e344d4 Michael Hanselmann
        self.__check_deleted()
558 84e344d4 Michael Hanselmann
559 84e344d4 Michael Hanselmann
        # A lot of code assumes blocking acquires always succeed. Loop
560 84e344d4 Michael Hanselmann
        # internally for that case.
561 84e344d4 Michael Hanselmann
        if timeout is not None:
562 84e344d4 Michael Hanselmann
          break
563 84e344d4 Michael Hanselmann
564 84e344d4 Michael Hanselmann
      if self.__is_on_top(wait_condition) and self.__can_acquire(shared):
565 84e344d4 Michael Hanselmann
        self.__do_acquire(shared)
566 84e344d4 Michael Hanselmann
        return True
567 9216a9f7 Michael Hanselmann
    finally:
568 84e344d4 Michael Hanselmann
      # Remove condition from queue if there are no more waiters
569 84e344d4 Michael Hanselmann
      if not wait_condition.has_waiting() and not self.__deleted:
570 84e344d4 Michael Hanselmann
        self.__pending.remove(wait_condition)
571 9216a9f7 Michael Hanselmann
572 84e344d4 Michael Hanselmann
    return False
573 9216a9f7 Michael Hanselmann
574 008b92fa Michael Hanselmann
  def acquire(self, shared=0, timeout=None, test_notify=None):
575 162c1c1f Guido Trotter
    """Acquire a shared lock.
576 162c1c1f Guido Trotter

577 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
578 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
579 c41eea6e Iustin Pop
        exclusive lock will be acquired
580 84e344d4 Michael Hanselmann
    @type timeout: float
581 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
582 008b92fa Michael Hanselmann
    @type test_notify: callable or None
583 008b92fa Michael Hanselmann
    @param test_notify: Special callback function for unittesting
584 162c1c1f Guido Trotter

585 162c1c1f Guido Trotter
    """
586 162c1c1f Guido Trotter
    self.__lock.acquire()
587 162c1c1f Guido Trotter
    try:
588 008b92fa Michael Hanselmann
      # We already got the lock, notify now
589 008b92fa Michael Hanselmann
      if __debug__ and callable(test_notify):
590 008b92fa Michael Hanselmann
        test_notify()
591 008b92fa Michael Hanselmann
592 84e344d4 Michael Hanselmann
      return self.__acquire_unlocked(shared, timeout)
593 162c1c1f Guido Trotter
    finally:
594 162c1c1f Guido Trotter
      self.__lock.release()
595 162c1c1f Guido Trotter
596 162c1c1f Guido Trotter
  def release(self):
597 162c1c1f Guido Trotter
    """Release a Shared Lock.
598 162c1c1f Guido Trotter

599 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
600 162c1c1f Guido Trotter
    before calling this function.
601 162c1c1f Guido Trotter

602 162c1c1f Guido Trotter
    """
603 162c1c1f Guido Trotter
    self.__lock.acquire()
604 162c1c1f Guido Trotter
    try:
605 84e344d4 Michael Hanselmann
      assert self.__is_exclusive() or self.__is_sharer(), \
606 84e344d4 Michael Hanselmann
        "Cannot release non-owned lock"
607 84e344d4 Michael Hanselmann
608 162c1c1f Guido Trotter
      # Autodetect release type
609 162c1c1f Guido Trotter
      if self.__is_exclusive():
610 162c1c1f Guido Trotter
        self.__exc = None
611 84e344d4 Michael Hanselmann
      else:
612 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
613 162c1c1f Guido Trotter
614 84e344d4 Michael Hanselmann
      # Notify topmost condition in queue
615 84e344d4 Michael Hanselmann
      if self.__pending:
616 84e344d4 Michael Hanselmann
        first_condition = self.__pending[0]
617 84e344d4 Michael Hanselmann
        first_condition.notifyAll()
618 4d686df8 Guido Trotter
619 84e344d4 Michael Hanselmann
        if first_condition == self.__active_shr_c:
620 84e344d4 Michael Hanselmann
          self.__active_shr_c = self.__inactive_shr_c
621 84e344d4 Michael Hanselmann
          self.__inactive_shr_c = first_condition
622 162c1c1f Guido Trotter
623 162c1c1f Guido Trotter
    finally:
624 162c1c1f Guido Trotter
      self.__lock.release()
625 162c1c1f Guido Trotter
626 84e344d4 Michael Hanselmann
  def delete(self, timeout=None):
627 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
628 a95fd5d7 Guido Trotter

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

633 84e344d4 Michael Hanselmann
    @type timeout: float
634 84e344d4 Michael Hanselmann
    @param timeout: maximum waiting time before giving up
635 a95fd5d7 Guido Trotter

636 a95fd5d7 Guido Trotter
    """
637 a95fd5d7 Guido Trotter
    self.__lock.acquire()
638 a95fd5d7 Guido Trotter
    try:
639 84e344d4 Michael Hanselmann
      assert not self.__is_sharer(), "Cannot delete() a lock while sharing it"
640 84e344d4 Michael Hanselmann
641 84e344d4 Michael Hanselmann
      self.__check_deleted()
642 a95fd5d7 Guido Trotter
643 84e344d4 Michael Hanselmann
      # The caller is allowed to hold the lock exclusively already.
644 84e344d4 Michael Hanselmann
      acquired = self.__is_exclusive()
645 a95fd5d7 Guido Trotter
646 84e344d4 Michael Hanselmann
      if not acquired:
647 a66bd91b Michael Hanselmann
        acquired = self.__acquire_unlocked(0, timeout)
648 a66bd91b Michael Hanselmann
649 a66bd91b Michael Hanselmann
        assert self.__is_exclusive() and not self.__is_sharer(), \
650 a66bd91b Michael Hanselmann
          "Lock wasn't acquired in exclusive mode"
651 84e344d4 Michael Hanselmann
652 84e344d4 Michael Hanselmann
      if acquired:
653 84e344d4 Michael Hanselmann
        self.__deleted = True
654 84e344d4 Michael Hanselmann
        self.__exc = None
655 a95fd5d7 Guido Trotter
656 84e344d4 Michael Hanselmann
        # Notify all acquires. They'll throw an error.
657 84e344d4 Michael Hanselmann
        while self.__pending:
658 84e344d4 Michael Hanselmann
          self.__pending.pop().notifyAll()
659 a95fd5d7 Guido Trotter
660 84e344d4 Michael Hanselmann
      return acquired
661 a95fd5d7 Guido Trotter
    finally:
662 a95fd5d7 Guido Trotter
      self.__lock.release()
663 a95fd5d7 Guido Trotter
664 1a4e32d0 Guido Trotter
  def _release_save(self):
665 1a4e32d0 Guido Trotter
    shared = self.__is_sharer()
666 1a4e32d0 Guido Trotter
    self.release()
667 1a4e32d0 Guido Trotter
    return shared
668 1a4e32d0 Guido Trotter
669 1a4e32d0 Guido Trotter
  def _acquire_restore(self, shared):
670 1a4e32d0 Guido Trotter
    self.acquire(shared=shared)
671 1a4e32d0 Guido Trotter
672 aaae9bc0 Guido Trotter
673 f12eadb3 Iustin Pop
# Whenever we want to acquire a full LockSet we pass None as the value
674 5bbd3f7f Michael Hanselmann
# to acquire.  Hide this behind this nicely named constant.
675 e310b019 Guido Trotter
ALL_SET = None
676 e310b019 Guido Trotter
677 e310b019 Guido Trotter
678 5aab242c Michael Hanselmann
class _AcquireTimeout(Exception):
679 5aab242c Michael Hanselmann
  """Internal exception to abort an acquire on a timeout.
680 5aab242c Michael Hanselmann

681 5aab242c Michael Hanselmann
  """
682 5aab242c Michael Hanselmann
683 5aab242c Michael Hanselmann
684 aaae9bc0 Guido Trotter
class LockSet:
685 aaae9bc0 Guido Trotter
  """Implements a set of locks.
686 aaae9bc0 Guido Trotter

687 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
688 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
689 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
690 aaae9bc0 Guido Trotter
  preventing deadlock.
691 aaae9bc0 Guido Trotter

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

694 aaae9bc0 Guido Trotter
  """
695 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
696 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
697 aaae9bc0 Guido Trotter

698 ec44d893 Guido Trotter
    @type members: list of strings
699 c41eea6e Iustin Pop
    @param members: initial members of the set
700 aaae9bc0 Guido Trotter

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

769 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
770 aaae9bc0 Guido Trotter
    result after releasing the lock.
771 aaae9bc0 Guido Trotter

772 aaae9bc0 Guido Trotter
    """
773 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
774 aaae9bc0 Guido Trotter
775 aaae9bc0 Guido Trotter
  def _names(self):
776 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
777 aaae9bc0 Guido Trotter

778 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
779 cdb08f44 Michael Hanselmann

780 aaae9bc0 Guido Trotter
    """
781 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
782 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
783 d4803c24 Guido Trotter
    release_lock = False
784 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
785 d4803c24 Guido Trotter
      release_lock = True
786 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
787 aaae9bc0 Guido Trotter
    try:
788 aaae9bc0 Guido Trotter
      result = self.__names()
789 aaae9bc0 Guido Trotter
    finally:
790 d4803c24 Guido Trotter
      if release_lock:
791 d4803c24 Guido Trotter
        self.__lock.release()
792 0cf257c5 Guido Trotter
    return set(result)
793 aaae9bc0 Guido Trotter
794 5aab242c Michael Hanselmann
  def acquire(self, names, timeout=None, shared=0, test_notify=None):
795 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
796 aaae9bc0 Guido Trotter

797 ec44d893 Guido Trotter
    @type names: list of strings (or string)
798 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
799 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
800 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
801 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
802 c41eea6e Iustin Pop
        exclusive lock will be acquired
803 5aab242c Michael Hanselmann
    @type timeout: float or None
804 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
805 5aab242c Michael Hanselmann
    @type test_notify: callable or None
806 5aab242c Michael Hanselmann
    @param test_notify: Special callback function for unittesting
807 aaae9bc0 Guido Trotter

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

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

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

866 7e8841bd Michael Hanselmann
    @param names: Names of the locks to be acquired
867 7e8841bd Michael Hanselmann
    @param want_all: Whether all locks in the set should be acquired
868 7e8841bd Michael Hanselmann
    @param shared: Whether to acquire in shared mode
869 7e8841bd Michael Hanselmann
    @param timeout_fn: Function returning remaining timeout
870 7e8841bd Michael Hanselmann
    @param test_notify: Special callback function for unittesting
871 76e2f08a Michael Hanselmann

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

953 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
954 aaae9bc0 Guido Trotter
    before releasing them.
955 aaae9bc0 Guido Trotter

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

960 aaae9bc0 Guido Trotter
    """
961 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
962 aaae9bc0 Guido Trotter
963 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
964 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
965 aaae9bc0 Guido Trotter
      names = [names]
966 aaae9bc0 Guido Trotter
967 aaae9bc0 Guido Trotter
    if names is None:
968 aaae9bc0 Guido Trotter
      names = self._list_owned()
969 aaae9bc0 Guido Trotter
    else:
970 aaae9bc0 Guido Trotter
      names = set(names)
971 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
972 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
973 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
974 aaae9bc0 Guido Trotter
975 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
976 3b7ed473 Guido Trotter
    # After this 'add' can work again
977 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
978 3b7ed473 Guido Trotter
      self.__lock.release()
979 b2dabfd6 Guido Trotter
      self._del_owned()
980 3b7ed473 Guido Trotter
981 aaae9bc0 Guido Trotter
    for lockname in names:
982 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
983 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
984 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
985 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
986 aaae9bc0 Guido Trotter
987 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
988 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
989 aaae9bc0 Guido Trotter

990 ec44d893 Guido Trotter
    @type names: list of strings
991 c41eea6e Iustin Pop
    @param names: names of the new elements to add
992 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
993 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
994 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
995 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
996 aaae9bc0 Guido Trotter

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

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

1054 ec44d893 Guido Trotter
    @type names: list of strings
1055 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
1056 aaae9bc0 Guido Trotter

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

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

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

1140 7ee7c0c7 Guido Trotter
  """
1141 7ee7c0c7 Guido Trotter
  _instance = None
1142 7ee7c0c7 Guido Trotter
1143 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
1144 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
1145 7ee7c0c7 Guido Trotter

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

1149 c41eea6e Iustin Pop
    @param nodes: list of node names
1150 c41eea6e Iustin Pop
    @param instances: list of instance names
1151 7ee7c0c7 Guido Trotter

1152 7ee7c0c7 Guido Trotter
    """
1153 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
1154 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
1155 c41eea6e Iustin Pop
1156 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
1157 7ee7c0c7 Guido Trotter
1158 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
1159 7ee7c0c7 Guido Trotter
    # locking order.
1160 7ee7c0c7 Guido Trotter
    self.__keyring = {
1161 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
1162 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
1163 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
1164 7ee7c0c7 Guido Trotter
    }
1165 7ee7c0c7 Guido Trotter
1166 7ee7c0c7 Guido Trotter
  def _names(self, level):
1167 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
1168 7ee7c0c7 Guido Trotter

1169 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
1170 c41eea6e Iustin Pop

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

1173 7ee7c0c7 Guido Trotter
    """
1174 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
1175 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
1176 7ee7c0c7 Guido Trotter
1177 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
1178 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
1179 7ee7c0c7 Guido Trotter

1180 7ee7c0c7 Guido Trotter
    """
1181 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
1182 7ee7c0c7 Guido Trotter
1183 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
1184 d4f4b3e7 Guido Trotter
1185 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
1186 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
1187 7ee7c0c7 Guido Trotter

1188 7ee7c0c7 Guido Trotter
    """
1189 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
1190 7ee7c0c7 Guido Trotter
1191 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
1192 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
1193 7ee7c0c7 Guido Trotter

1194 7ee7c0c7 Guido Trotter
    """
1195 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
1196 7ee7c0c7 Guido Trotter
    # the test cases.
1197 cea881e5 Michael Hanselmann
    return compat.any((self._is_owned(l) for l in LEVELS[level + 1:]))
1198 7ee7c0c7 Guido Trotter
1199 fe267188 Iustin Pop
  def _BGL_owned(self): # pylint: disable-msg=C0103
1200 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
1201 7ee7c0c7 Guido Trotter

1202 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
1203 7ee7c0c7 Guido Trotter

1204 7ee7c0c7 Guido Trotter
    """
1205 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
1206 7ee7c0c7 Guido Trotter
1207 c70d2d9b Iustin Pop
  @staticmethod
1208 c70d2d9b Iustin Pop
  def _contains_BGL(level, names): # pylint: disable-msg=C0103
1209 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
1210 c41eea6e Iustin Pop

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

1214 7ee7c0c7 Guido Trotter
    """
1215 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
1216 7ee7c0c7 Guido Trotter
1217 5e0a6daf Michael Hanselmann
  def acquire(self, level, names, timeout=None, shared=0):
1218 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
1219 7ee7c0c7 Guido Trotter

1220 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1221 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be acquired
1222 ec44d893 Guido Trotter
    @type names: list of strings (or string)
1223 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
1224 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1225 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1226 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
1227 c41eea6e Iustin Pop
        an exclusive lock will be acquired
1228 5e0a6daf Michael Hanselmann
    @type timeout: float
1229 5e0a6daf Michael Hanselmann
    @param timeout: Maximum time to acquire all locks
1230 7ee7c0c7 Guido Trotter

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

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

1256 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS
1257 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be released
1258 ec44d893 Guido Trotter
    @type names: list of strings, or None
1259 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
1260 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
1261 7ee7c0c7 Guido Trotter

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

1277 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1278 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be added
1279 ec44d893 Guido Trotter
    @type names: list of strings
1280 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
1281 ec44d893 Guido Trotter
    @type acquired: integer (0/1) used as a boolean
1282 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
1283 ec44d893 Guido Trotter
    @type shared: integer (0/1) used as a boolean
1284 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
1285 c41eea6e Iustin Pop

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

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

1300 ec44d893 Guido Trotter
    @type level: member of locking.LEVELS_MOD
1301 ec44d893 Guido Trotter
    @param level: the level at which the locks shall be removed
1302 ec44d893 Guido Trotter
    @type names: list of strings
1303 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
1304 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
1305 7ee7c0c7 Guido Trotter

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