Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 7ee7c0c7

History | View | Annotate | Download (25.7 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 162c1c1f Guido Trotter
# pylint: disable-msg=W0613,W0201
24 162c1c1f Guido Trotter
25 162c1c1f Guido Trotter
import threading
26 a95fd5d7 Guido Trotter
# Wouldn't it be better to define LockingError in the locking module?
27 a95fd5d7 Guido Trotter
# Well, for now that's how the rest of the code does it...
28 a95fd5d7 Guido Trotter
from ganeti import errors
29 7ee7c0c7 Guido Trotter
from ganeti import utils
30 162c1c1f Guido Trotter
31 162c1c1f Guido Trotter
32 162c1c1f Guido Trotter
class SharedLock:
33 162c1c1f Guido Trotter
  """Implements a shared lock.
34 162c1c1f Guido Trotter

35 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
36 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
37 162c1c1f Guido Trotter
  can call acquire_exclusive().
38 162c1c1f Guido Trotter

39 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
40 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
41 162c1c1f Guido Trotter
  eventually do so.
42 162c1c1f Guido Trotter

43 162c1c1f Guido Trotter
  """
44 162c1c1f Guido Trotter
  def __init__(self):
45 d6646186 Guido Trotter
    """Construct a new SharedLock"""
46 162c1c1f Guido Trotter
    # we have two conditions, c_shr and c_exc, sharing the same lock.
47 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
48 162c1c1f Guido Trotter
    self.__turn_shr = threading.Condition(self.__lock)
49 162c1c1f Guido Trotter
    self.__turn_exc = threading.Condition(self.__lock)
50 162c1c1f Guido Trotter
51 162c1c1f Guido Trotter
    # current lock holders
52 162c1c1f Guido Trotter
    self.__shr = set()
53 162c1c1f Guido Trotter
    self.__exc = None
54 162c1c1f Guido Trotter
55 162c1c1f Guido Trotter
    # lock waiters
56 162c1c1f Guido Trotter
    self.__nwait_exc = 0
57 162c1c1f Guido Trotter
    self.__nwait_shr = 0
58 162c1c1f Guido Trotter
59 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
60 a95fd5d7 Guido Trotter
    self.__deleted = False
61 a95fd5d7 Guido Trotter
62 162c1c1f Guido Trotter
  def __is_sharer(self):
63 162c1c1f Guido Trotter
    """Is the current thread sharing the lock at this time?"""
64 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
65 162c1c1f Guido Trotter
66 162c1c1f Guido Trotter
  def __is_exclusive(self):
67 162c1c1f Guido Trotter
    """Is the current thread holding the lock exclusively at this time?"""
68 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
69 162c1c1f Guido Trotter
70 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
71 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
72 162c1c1f Guido Trotter

73 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
74 162c1c1f Guido Trotter
    the internal lock.
75 162c1c1f Guido Trotter

76 162c1c1f Guido Trotter
    """
77 162c1c1f Guido Trotter
    if shared < 0:
78 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
79 162c1c1f Guido Trotter
    elif shared:
80 162c1c1f Guido Trotter
      return self.__is_sharer()
81 162c1c1f Guido Trotter
    else:
82 162c1c1f Guido Trotter
      return self.__is_exclusive()
83 162c1c1f Guido Trotter
84 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
85 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
86 162c1c1f Guido Trotter

87 162c1c1f Guido Trotter
    Args:
88 162c1c1f Guido Trotter
      shared:
89 162c1c1f Guido Trotter
        < 0: check for any type of ownership (default)
90 162c1c1f Guido Trotter
        0: check for exclusive ownership
91 162c1c1f Guido Trotter
        > 0: check for shared ownership
92 162c1c1f Guido Trotter

93 162c1c1f Guido Trotter
    """
94 162c1c1f Guido Trotter
    self.__lock.acquire()
95 162c1c1f Guido Trotter
    try:
96 162c1c1f Guido Trotter
      result = self.__is_owned(shared)
97 162c1c1f Guido Trotter
    finally:
98 162c1c1f Guido Trotter
      self.__lock.release()
99 162c1c1f Guido Trotter
100 162c1c1f Guido Trotter
    return result
101 162c1c1f Guido Trotter
102 a95fd5d7 Guido Trotter
  def __wait(self,c):
103 a95fd5d7 Guido Trotter
    """Wait on the given condition, and raise an exception if the current lock
104 a95fd5d7 Guido Trotter
    is declared deleted in the meantime.
105 a95fd5d7 Guido Trotter

106 a95fd5d7 Guido Trotter
    Args:
107 a95fd5d7 Guido Trotter
      c: condition to wait on
108 a95fd5d7 Guido Trotter

109 a95fd5d7 Guido Trotter
    """
110 a95fd5d7 Guido Trotter
    c.wait()
111 a95fd5d7 Guido Trotter
    if self.__deleted:
112 a95fd5d7 Guido Trotter
      raise errors.LockError('deleted lock')
113 a95fd5d7 Guido Trotter
114 a95fd5d7 Guido Trotter
  def __exclusive_acquire(self):
115 a95fd5d7 Guido Trotter
    """Acquire the lock exclusively.
116 a95fd5d7 Guido Trotter

117 a95fd5d7 Guido Trotter
    This is a private function that presumes you are already holding the
118 a95fd5d7 Guido Trotter
    internal lock. It's defined separately to avoid code duplication between
119 a95fd5d7 Guido Trotter
    acquire() and delete()
120 a95fd5d7 Guido Trotter

121 a95fd5d7 Guido Trotter
    """
122 a95fd5d7 Guido Trotter
    self.__nwait_exc += 1
123 a95fd5d7 Guido Trotter
    try:
124 a95fd5d7 Guido Trotter
      # This is to save ourselves from a nasty race condition that could
125 a95fd5d7 Guido Trotter
      # theoretically make the sharers starve.
126 a95fd5d7 Guido Trotter
      if self.__nwait_shr > 0 or self.__nwait_exc > 1:
127 a95fd5d7 Guido Trotter
        self.__wait(self.__turn_exc)
128 a95fd5d7 Guido Trotter
129 a95fd5d7 Guido Trotter
      while len(self.__shr) > 0 or self.__exc is not None:
130 a95fd5d7 Guido Trotter
        self.__wait(self.__turn_exc)
131 a95fd5d7 Guido Trotter
132 a95fd5d7 Guido Trotter
      self.__exc = threading.currentThread()
133 a95fd5d7 Guido Trotter
    finally:
134 a95fd5d7 Guido Trotter
      self.__nwait_exc -= 1
135 a95fd5d7 Guido Trotter
136 a95fd5d7 Guido Trotter
137 162c1c1f Guido Trotter
  def acquire(self, blocking=1, shared=0):
138 162c1c1f Guido Trotter
    """Acquire a shared lock.
139 162c1c1f Guido Trotter

140 162c1c1f Guido Trotter
    Args:
141 162c1c1f Guido Trotter
      shared: whether to acquire in shared mode. By default an exclusive lock
142 162c1c1f Guido Trotter
              will be acquired.
143 162c1c1f Guido Trotter
      blocking: whether to block while trying to acquire or to operate in try-lock mode.
144 162c1c1f Guido Trotter
                this locking mode is not supported yet.
145 162c1c1f Guido Trotter

146 162c1c1f Guido Trotter
    """
147 162c1c1f Guido Trotter
    if not blocking:
148 162c1c1f Guido Trotter
      # We don't have non-blocking mode for now
149 162c1c1f Guido Trotter
      raise NotImplementedError
150 162c1c1f Guido Trotter
151 162c1c1f Guido Trotter
    self.__lock.acquire()
152 162c1c1f Guido Trotter
    try:
153 a95fd5d7 Guido Trotter
      if self.__deleted:
154 a95fd5d7 Guido Trotter
        raise errors.LockError('deleted lock')
155 a95fd5d7 Guido Trotter
156 162c1c1f Guido Trotter
      # We cannot acquire the lock if we already have it
157 162c1c1f Guido Trotter
      assert not self.__is_owned(), "double acquire() on a non-recursive lock"
158 162c1c1f Guido Trotter
159 162c1c1f Guido Trotter
      if shared:
160 162c1c1f Guido Trotter
        self.__nwait_shr += 1
161 162c1c1f Guido Trotter
        try:
162 162c1c1f Guido Trotter
          # If there is an exclusive holder waiting we have to wait.  We'll
163 162c1c1f Guido Trotter
          # only do this once, though, when we start waiting for the lock. Then
164 162c1c1f Guido Trotter
          # we'll just wait while there are no exclusive holders.
165 162c1c1f Guido Trotter
          if self.__nwait_exc > 0:
166 162c1c1f Guido Trotter
            # TODO: if !blocking...
167 a95fd5d7 Guido Trotter
            self.__wait(self.__turn_shr)
168 162c1c1f Guido Trotter
169 162c1c1f Guido Trotter
          while self.__exc is not None:
170 162c1c1f Guido Trotter
            # TODO: if !blocking...
171 a95fd5d7 Guido Trotter
            self.__wait(self.__turn_shr)
172 162c1c1f Guido Trotter
173 162c1c1f Guido Trotter
          self.__shr.add(threading.currentThread())
174 162c1c1f Guido Trotter
        finally:
175 162c1c1f Guido Trotter
          self.__nwait_shr -= 1
176 162c1c1f Guido Trotter
177 162c1c1f Guido Trotter
      else:
178 a95fd5d7 Guido Trotter
        # TODO: if !blocking...
179 a95fd5d7 Guido Trotter
        # (or modify __exclusive_acquire for non-blocking mode)
180 a95fd5d7 Guido Trotter
        self.__exclusive_acquire()
181 162c1c1f Guido Trotter
182 162c1c1f Guido Trotter
    finally:
183 162c1c1f Guido Trotter
      self.__lock.release()
184 162c1c1f Guido Trotter
185 162c1c1f Guido Trotter
    return True
186 162c1c1f Guido Trotter
187 162c1c1f Guido Trotter
  def release(self):
188 162c1c1f Guido Trotter
    """Release a Shared Lock.
189 162c1c1f Guido Trotter

190 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
191 162c1c1f Guido Trotter
    before calling this function.
192 162c1c1f Guido Trotter

193 162c1c1f Guido Trotter
    """
194 162c1c1f Guido Trotter
    self.__lock.acquire()
195 162c1c1f Guido Trotter
    try:
196 162c1c1f Guido Trotter
      # Autodetect release type
197 162c1c1f Guido Trotter
      if self.__is_exclusive():
198 162c1c1f Guido Trotter
        self.__exc = None
199 162c1c1f Guido Trotter
200 162c1c1f Guido Trotter
        # An exclusive holder has just had the lock, time to put it in shared
201 162c1c1f Guido Trotter
        # mode if there are shared holders waiting. Otherwise wake up the next
202 162c1c1f Guido Trotter
        # exclusive holder.
203 162c1c1f Guido Trotter
        if self.__nwait_shr > 0:
204 162c1c1f Guido Trotter
          self.__turn_shr.notifyAll()
205 162c1c1f Guido Trotter
        elif self.__nwait_exc > 0:
206 162c1c1f Guido Trotter
         self.__turn_exc.notify()
207 162c1c1f Guido Trotter
208 162c1c1f Guido Trotter
      elif self.__is_sharer():
209 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
210 162c1c1f Guido Trotter
211 162c1c1f Guido Trotter
        # If there are shared holders waiting there *must* be an exclusive holder
212 162c1c1f Guido Trotter
        # waiting as well; otherwise what were they waiting for?
213 162c1c1f Guido Trotter
        assert (self.__nwait_shr == 0 or self.__nwait_exc > 0,
214 162c1c1f Guido Trotter
                "Lock sharers waiting while no exclusive is queueing")
215 162c1c1f Guido Trotter
216 162c1c1f Guido Trotter
        # If there are no more shared holders and some exclusive holders are
217 162c1c1f Guido Trotter
        # waiting let's wake one up.
218 162c1c1f Guido Trotter
        if len(self.__shr) == 0 and self.__nwait_exc > 0:
219 162c1c1f Guido Trotter
          self.__turn_exc.notify()
220 162c1c1f Guido Trotter
221 162c1c1f Guido Trotter
      else:
222 162c1c1f Guido Trotter
        assert False, "Cannot release non-owned lock"
223 162c1c1f Guido Trotter
224 162c1c1f Guido Trotter
    finally:
225 162c1c1f Guido Trotter
      self.__lock.release()
226 162c1c1f Guido Trotter
227 a95fd5d7 Guido Trotter
  def delete(self, blocking=1):
228 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
229 a95fd5d7 Guido Trotter

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

234 a95fd5d7 Guido Trotter
    Args:
235 a95fd5d7 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
236 a95fd5d7 Guido Trotter
                try-lock mode.  this locking mode is not supported yet unless
237 a95fd5d7 Guido Trotter
                you are already holding exclusively the lock.
238 a95fd5d7 Guido Trotter

239 a95fd5d7 Guido Trotter
    """
240 a95fd5d7 Guido Trotter
    self.__lock.acquire()
241 a95fd5d7 Guido Trotter
    try:
242 a95fd5d7 Guido Trotter
      assert not self.__is_sharer(), "cannot delete() a lock while sharing it"
243 a95fd5d7 Guido Trotter
244 a95fd5d7 Guido Trotter
      if self.__deleted:
245 a95fd5d7 Guido Trotter
        raise errors.LockError('deleted lock')
246 a95fd5d7 Guido Trotter
247 a95fd5d7 Guido Trotter
      if not self.__is_exclusive():
248 a95fd5d7 Guido Trotter
        if not blocking:
249 a95fd5d7 Guido Trotter
          # We don't have non-blocking mode for now
250 a95fd5d7 Guido Trotter
          raise NotImplementedError
251 a95fd5d7 Guido Trotter
        self.__exclusive_acquire()
252 a95fd5d7 Guido Trotter
253 a95fd5d7 Guido Trotter
      self.__deleted = True
254 a95fd5d7 Guido Trotter
      self.__exc = None
255 a95fd5d7 Guido Trotter
      # Wake up everybody, they will fail acquiring the lock and
256 a95fd5d7 Guido Trotter
      # raise an exception instead.
257 a95fd5d7 Guido Trotter
      self.__turn_exc.notifyAll()
258 a95fd5d7 Guido Trotter
      self.__turn_shr.notifyAll()
259 a95fd5d7 Guido Trotter
260 a95fd5d7 Guido Trotter
    finally:
261 a95fd5d7 Guido Trotter
      self.__lock.release()
262 a95fd5d7 Guido Trotter
263 aaae9bc0 Guido Trotter
264 aaae9bc0 Guido Trotter
class LockSet:
265 aaae9bc0 Guido Trotter
  """Implements a set of locks.
266 aaae9bc0 Guido Trotter

267 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
268 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
269 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
270 aaae9bc0 Guido Trotter
  preventing deadlock.
271 aaae9bc0 Guido Trotter

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

274 aaae9bc0 Guido Trotter
  """
275 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
276 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
277 aaae9bc0 Guido Trotter

278 aaae9bc0 Guido Trotter
    Args:
279 aaae9bc0 Guido Trotter
      members: initial members of the set
280 aaae9bc0 Guido Trotter

281 aaae9bc0 Guido Trotter
    """
282 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
283 aaae9bc0 Guido Trotter
    self.__lock = SharedLock()
284 aaae9bc0 Guido Trotter
285 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
286 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
287 aaae9bc0 Guido Trotter
    self.__lockdict = {}
288 aaae9bc0 Guido Trotter
289 aaae9bc0 Guido Trotter
    if members is not None:
290 aaae9bc0 Guido Trotter
      for name in members:
291 aaae9bc0 Guido Trotter
        self.__lockdict[name] = SharedLock()
292 aaae9bc0 Guido Trotter
293 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
294 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
295 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
296 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
297 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
298 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
299 aaae9bc0 Guido Trotter
    # will be trouble.
300 aaae9bc0 Guido Trotter
    self.__owners = {}
301 aaae9bc0 Guido Trotter
302 aaae9bc0 Guido Trotter
  def _is_owned(self):
303 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
304 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
305 aaae9bc0 Guido Trotter
306 aaae9bc0 Guido Trotter
  def _add_owned(self, name):
307 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
308 aaae9bc0 Guido Trotter
    if self._is_owned():
309 aaae9bc0 Guido Trotter
      self.__owners[threading.currentThread()].add(name)
310 aaae9bc0 Guido Trotter
    else:
311 aaae9bc0 Guido Trotter
       self.__owners[threading.currentThread()] = set([name])
312 aaae9bc0 Guido Trotter
313 aaae9bc0 Guido Trotter
  def _del_owned(self, name):
314 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
315 aaae9bc0 Guido Trotter
    self.__owners[threading.currentThread()].remove(name)
316 aaae9bc0 Guido Trotter
317 aaae9bc0 Guido Trotter
    if not self.__owners[threading.currentThread()]:
318 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
319 aaae9bc0 Guido Trotter
320 aaae9bc0 Guido Trotter
  def _list_owned(self):
321 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
322 aaae9bc0 Guido Trotter
    if self._is_owned():
323 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
324 aaae9bc0 Guido Trotter
    else:
325 aaae9bc0 Guido Trotter
      return set()
326 aaae9bc0 Guido Trotter
327 aaae9bc0 Guido Trotter
  def __names(self):
328 aaae9bc0 Guido Trotter
    """Return the current set of names.
329 aaae9bc0 Guido Trotter

330 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
331 aaae9bc0 Guido Trotter
    result after releasing the lock.
332 aaae9bc0 Guido Trotter

333 aaae9bc0 Guido Trotter
    """
334 aaae9bc0 Guido Trotter
    return set(self.__lockdict.keys())
335 aaae9bc0 Guido Trotter
336 aaae9bc0 Guido Trotter
  def _names(self):
337 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
338 aaae9bc0 Guido Trotter

339 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
340 aaae9bc0 Guido Trotter
    """
341 aaae9bc0 Guido Trotter
    self.__lock.acquire(shared=1)
342 aaae9bc0 Guido Trotter
    try:
343 aaae9bc0 Guido Trotter
      result = self.__names()
344 aaae9bc0 Guido Trotter
    finally:
345 aaae9bc0 Guido Trotter
      self.__lock.release()
346 aaae9bc0 Guido Trotter
    return result
347 aaae9bc0 Guido Trotter
348 aaae9bc0 Guido Trotter
  def acquire(self, names, blocking=1, shared=0):
349 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
350 aaae9bc0 Guido Trotter

351 aaae9bc0 Guido Trotter
    Args:
352 aaae9bc0 Guido Trotter
      names: the names of the locks which shall be acquired.
353 aaae9bc0 Guido Trotter
             (special lock names, or instance/node names)
354 aaae9bc0 Guido Trotter
      shared: whether to acquire in shared mode. By default an exclusive lock
355 aaae9bc0 Guido Trotter
              will be acquired.
356 aaae9bc0 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in try-lock mode.
357 aaae9bc0 Guido Trotter
                this locking mode is not supported yet.
358 aaae9bc0 Guido Trotter

359 aaae9bc0 Guido Trotter
    Returns:
360 aaae9bc0 Guido Trotter
      True: when all the locks are successfully acquired
361 aaae9bc0 Guido Trotter

362 aaae9bc0 Guido Trotter
    Raises:
363 aaae9bc0 Guido Trotter
      errors.LockError: when any lock we try to acquire has been deleted
364 aaae9bc0 Guido Trotter
      before we succeed. In this case none of the locks requested will be
365 aaae9bc0 Guido Trotter
      acquired.
366 aaae9bc0 Guido Trotter

367 aaae9bc0 Guido Trotter
    """
368 aaae9bc0 Guido Trotter
    if not blocking:
369 aaae9bc0 Guido Trotter
      # We don't have non-blocking mode for now
370 aaae9bc0 Guido Trotter
      raise NotImplementedError
371 aaae9bc0 Guido Trotter
372 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
373 aaae9bc0 Guido Trotter
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
374 aaae9bc0 Guido Trotter
375 aaae9bc0 Guido Trotter
    # Support passing in a single resource to acquire rather than many
376 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
377 aaae9bc0 Guido Trotter
      names = [names]
378 aaae9bc0 Guido Trotter
    else:
379 aaae9bc0 Guido Trotter
      names.sort()
380 aaae9bc0 Guido Trotter
381 e6c200d6 Guido Trotter
    acquire_list = []
382 e6c200d6 Guido Trotter
    # First we look the locks up on __lockdict. We have no way of being sure
383 e6c200d6 Guido Trotter
    # they will still be there after, but this makes it a lot faster should
384 e6c200d6 Guido Trotter
    # just one of them be the already wrong
385 aaae9bc0 Guido Trotter
    try:
386 aaae9bc0 Guido Trotter
      for lname in names:
387 aaae9bc0 Guido Trotter
        lock = self.__lockdict[lname] # raises KeyError if the lock is not there
388 e6c200d6 Guido Trotter
        acquire_list.append((lname, lock))
389 e6c200d6 Guido Trotter
    except (KeyError):
390 e6c200d6 Guido Trotter
      raise errors.LockError('non-existing lock in set (%s)' % lname)
391 e6c200d6 Guido Trotter
392 e6c200d6 Guido Trotter
    # Now acquire_list contains a sorted list of resources and locks we want.
393 e6c200d6 Guido Trotter
    # In order to get them we loop on this (private) list and acquire() them.
394 e6c200d6 Guido Trotter
    # We gave no real guarantee they will still exist till this is done but
395 e6c200d6 Guido Trotter
    # .acquire() itself is safe and will alert us if the lock gets deleted.
396 e6c200d6 Guido Trotter
    try:
397 e6c200d6 Guido Trotter
      for (lname, lock) in acquire_list:
398 aaae9bc0 Guido Trotter
        lock.acquire(shared=shared) # raises LockError if the lock is deleted
399 aaae9bc0 Guido Trotter
        try:
400 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
401 aaae9bc0 Guido Trotter
          self._add_owned(lname)
402 aaae9bc0 Guido Trotter
        except:
403 aaae9bc0 Guido Trotter
          # We shouldn't have problems adding the lock to the owners list, but
404 aaae9bc0 Guido Trotter
          # if we did we'll try to release this lock and re-raise exception.
405 aaae9bc0 Guido Trotter
          # Of course something is going to be really wrong, after this.
406 aaae9bc0 Guido Trotter
          lock.release()
407 aaae9bc0 Guido Trotter
          raise
408 aaae9bc0 Guido Trotter
409 e6c200d6 Guido Trotter
    except (errors.LockError):
410 aaae9bc0 Guido Trotter
      name_fail = lname
411 aaae9bc0 Guido Trotter
      for lname in self._list_owned():
412 aaae9bc0 Guido Trotter
        self.__lockdict[lname].release()
413 aaae9bc0 Guido Trotter
        self._del_owned(lname)
414 aaae9bc0 Guido Trotter
      raise errors.LockError('non-existing lock in set (%s)' % name_fail)
415 aaae9bc0 Guido Trotter
416 aaae9bc0 Guido Trotter
    return True
417 aaae9bc0 Guido Trotter
418 aaae9bc0 Guido Trotter
  def release(self, names=None):
419 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
420 aaae9bc0 Guido Trotter

421 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
422 aaae9bc0 Guido Trotter
    before releasing them.
423 aaae9bc0 Guido Trotter

424 aaae9bc0 Guido Trotter
    Args:
425 aaae9bc0 Guido Trotter
      names: the names of the locks which shall be released.
426 aaae9bc0 Guido Trotter
             (defaults to all the locks acquired at that level).
427 aaae9bc0 Guido Trotter

428 aaae9bc0 Guido Trotter
    """
429 aaae9bc0 Guido Trotter
430 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
431 aaae9bc0 Guido Trotter
432 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
433 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
434 aaae9bc0 Guido Trotter
      names = [names]
435 aaae9bc0 Guido Trotter
436 aaae9bc0 Guido Trotter
    if names is None:
437 aaae9bc0 Guido Trotter
      names = self._list_owned()
438 aaae9bc0 Guido Trotter
    else:
439 aaae9bc0 Guido Trotter
      names = set(names)
440 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
441 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
442 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
443 aaae9bc0 Guido Trotter
444 aaae9bc0 Guido Trotter
    for lockname in names:
445 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
446 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
447 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
448 aaae9bc0 Guido Trotter
      self._del_owned(lockname)
449 aaae9bc0 Guido Trotter
450 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
451 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
452 aaae9bc0 Guido Trotter

453 aaae9bc0 Guido Trotter
    Args:
454 aaae9bc0 Guido Trotter
      names: names of the new elements to add
455 aaae9bc0 Guido Trotter
      acquired: pre-acquire the new resource?
456 aaae9bc0 Guido Trotter
      shared: is the pre-acquisition shared?
457 aaae9bc0 Guido Trotter

458 aaae9bc0 Guido Trotter
    """
459 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
460 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
461 aaae9bc0 Guido Trotter
      names = [names]
462 aaae9bc0 Guido Trotter
463 aaae9bc0 Guido Trotter
    # Acquire the internal lock in an exclusive way, so there cannot be a
464 aaae9bc0 Guido Trotter
    # conflicting add()
465 aaae9bc0 Guido Trotter
    self.__lock.acquire()
466 aaae9bc0 Guido Trotter
    try:
467 aaae9bc0 Guido Trotter
      invalid_names = self.__names().intersection(names)
468 aaae9bc0 Guido Trotter
      if invalid_names:
469 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
470 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
471 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
472 aaae9bc0 Guido Trotter
        raise errors.LockError("duplicate add() (%s)" % invalid_names)
473 aaae9bc0 Guido Trotter
474 aaae9bc0 Guido Trotter
      for lockname in names:
475 aaae9bc0 Guido Trotter
        lock = SharedLock()
476 aaae9bc0 Guido Trotter
477 aaae9bc0 Guido Trotter
        if acquired:
478 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
479 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
480 aaae9bc0 Guido Trotter
          try:
481 aaae9bc0 Guido Trotter
            self._add_owned(lockname)
482 aaae9bc0 Guido Trotter
          except:
483 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
484 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
485 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
486 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
487 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
488 aaae9bc0 Guido Trotter
            # release is just a safety measure.
489 aaae9bc0 Guido Trotter
            lock.release()
490 aaae9bc0 Guido Trotter
            raise
491 aaae9bc0 Guido Trotter
492 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
493 aaae9bc0 Guido Trotter
494 aaae9bc0 Guido Trotter
    finally:
495 aaae9bc0 Guido Trotter
      self.__lock.release()
496 aaae9bc0 Guido Trotter
497 aaae9bc0 Guido Trotter
    return True
498 aaae9bc0 Guido Trotter
499 aaae9bc0 Guido Trotter
  def remove(self, names, blocking=1):
500 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
501 aaae9bc0 Guido Trotter

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

505 aaae9bc0 Guido Trotter
    Args:
506 aaae9bc0 Guido Trotter
      names: names of the resource to remove.
507 aaae9bc0 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
508 aaae9bc0 Guido Trotter
                try-lock mode.  this locking mode is not supported yet unless
509 aaae9bc0 Guido Trotter
                you are already holding exclusively the locks.
510 aaae9bc0 Guido Trotter

511 aaae9bc0 Guido Trotter
    Returns:
512 aaae9bc0 Guido Trotter
      A list of lock which we failed to delete. The list is always empty if we
513 aaae9bc0 Guido Trotter
      were holding all the locks exclusively.
514 aaae9bc0 Guido Trotter

515 aaae9bc0 Guido Trotter
    """
516 aaae9bc0 Guido Trotter
    if not blocking and not self._is_owned():
517 aaae9bc0 Guido Trotter
      # We don't have non-blocking mode for now
518 aaae9bc0 Guido Trotter
      raise NotImplementedError
519 aaae9bc0 Guido Trotter
520 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
521 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
522 aaae9bc0 Guido Trotter
      names = [names]
523 aaae9bc0 Guido Trotter
524 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
525 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
526 aaae9bc0 Guido Trotter
    # by the lock itself.
527 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
528 aaae9bc0 Guido Trotter
      "remove() on acquired lockset while not owning all elements")
529 aaae9bc0 Guido Trotter
530 aaae9bc0 Guido Trotter
    delete_failed=[]
531 aaae9bc0 Guido Trotter
532 aaae9bc0 Guido Trotter
    for lname in names:
533 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
534 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
535 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
536 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
537 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
538 aaae9bc0 Guido Trotter
      try:
539 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
540 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
541 aaae9bc0 Guido Trotter
        delete_failed.append(lname)
542 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
543 aaae9bc0 Guido Trotter
        assert not self._is_owned(), "remove failed while holding lockset"
544 aaae9bc0 Guido Trotter
      else:
545 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
546 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
547 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
548 aaae9bc0 Guido Trotter
        # since before our call to delete()).
549 aaae9bc0 Guido Trotter
        #
550 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
551 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
552 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
553 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
554 aaae9bc0 Guido Trotter
        if self._is_owned():
555 aaae9bc0 Guido Trotter
          self._del_owned(lname)
556 aaae9bc0 Guido Trotter
557 aaae9bc0 Guido Trotter
    return delete_failed
558 aaae9bc0 Guido Trotter
559 7ee7c0c7 Guido Trotter
560 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
561 7ee7c0c7 Guido Trotter
# Current rules are:
562 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
563 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
564 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
565 7ee7c0c7 Guido Trotter
#   avoided.
566 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
567 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
568 7ee7c0c7 Guido Trotter
#   the same time.
569 7ee7c0c7 Guido Trotter
#  - level LEVEL_CONFIG contains the configuration lock, which you must acquire
570 7ee7c0c7 Guido Trotter
#  before reading or changing the config file.
571 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
572 7ee7c0c7 Guido Trotter
LEVEL_NODE = 1
573 7ee7c0c7 Guido Trotter
LEVEL_INSTANCE = 2
574 7ee7c0c7 Guido Trotter
LEVEL_CONFIG = 3
575 7ee7c0c7 Guido Trotter
576 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
577 7ee7c0c7 Guido Trotter
          LEVEL_NODE,
578 7ee7c0c7 Guido Trotter
          LEVEL_INSTANCE,
579 7ee7c0c7 Guido Trotter
          LEVEL_CONFIG]
580 7ee7c0c7 Guido Trotter
581 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
582 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
583 7ee7c0c7 Guido Trotter
584 7ee7c0c7 Guido Trotter
# Constant for the big ganeti lock and config lock
585 7ee7c0c7 Guido Trotter
BGL = 'BGL'
586 7ee7c0c7 Guido Trotter
CONFIG = 'config'
587 7ee7c0c7 Guido Trotter
588 7ee7c0c7 Guido Trotter
589 7ee7c0c7 Guido Trotter
class GanetiLockManager:
590 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
591 7ee7c0c7 Guido Trotter

592 7ee7c0c7 Guido Trotter
  The purpouse of this small library is to manage locking for ganeti clusters
593 7ee7c0c7 Guido Trotter
  in a central place, while at the same time doing dynamic checks against
594 7ee7c0c7 Guido Trotter
  possible deadlocks. It will also make it easier to transition to a different
595 7ee7c0c7 Guido Trotter
  lock type should we migrate away from python threads.
596 7ee7c0c7 Guido Trotter

597 7ee7c0c7 Guido Trotter
  """
598 7ee7c0c7 Guido Trotter
  _instance = None
599 7ee7c0c7 Guido Trotter
600 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
601 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
602 7ee7c0c7 Guido Trotter

603 7ee7c0c7 Guido Trotter
    There should be only a
604 7ee7c0c7 Guido Trotter
    GanetiLockManager object at any time, so this function raises an error if this
605 7ee7c0c7 Guido Trotter
    is not the case.
606 7ee7c0c7 Guido Trotter

607 7ee7c0c7 Guido Trotter
    Args:
608 7ee7c0c7 Guido Trotter
      nodes: list of node names
609 7ee7c0c7 Guido Trotter
      instances: list of instance names
610 7ee7c0c7 Guido Trotter

611 7ee7c0c7 Guido Trotter
    """
612 7ee7c0c7 Guido Trotter
    assert self.__class__._instance is None, "double GanetiLockManager instance"
613 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
614 7ee7c0c7 Guido Trotter
615 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
616 7ee7c0c7 Guido Trotter
    # locking order.
617 7ee7c0c7 Guido Trotter
    self.__keyring = {
618 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
619 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
620 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
621 7ee7c0c7 Guido Trotter
      LEVEL_CONFIG: LockSet([CONFIG]),
622 7ee7c0c7 Guido Trotter
    }
623 7ee7c0c7 Guido Trotter
624 7ee7c0c7 Guido Trotter
  def _names(self, level):
625 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
626 7ee7c0c7 Guido Trotter
    Used for debugging/testing purposes.
627 7ee7c0c7 Guido Trotter

628 7ee7c0c7 Guido Trotter
    Args:
629 7ee7c0c7 Guido Trotter
      level: the level whose list of locks to get
630 7ee7c0c7 Guido Trotter

631 7ee7c0c7 Guido Trotter
    """
632 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
633 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
634 7ee7c0c7 Guido Trotter
635 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
636 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
637 7ee7c0c7 Guido Trotter

638 7ee7c0c7 Guido Trotter
    """
639 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
640 7ee7c0c7 Guido Trotter
641 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
642 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
643 7ee7c0c7 Guido Trotter

644 7ee7c0c7 Guido Trotter
    """
645 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
646 7ee7c0c7 Guido Trotter
647 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
648 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
649 7ee7c0c7 Guido Trotter

650 7ee7c0c7 Guido Trotter
    """
651 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
652 7ee7c0c7 Guido Trotter
    # the test cases.
653 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
654 7ee7c0c7 Guido Trotter
655 7ee7c0c7 Guido Trotter
  def _BGL_owned(self):
656 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
657 7ee7c0c7 Guido Trotter

658 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
659 7ee7c0c7 Guido Trotter

660 7ee7c0c7 Guido Trotter
    """
661 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
662 7ee7c0c7 Guido Trotter
663 7ee7c0c7 Guido Trotter
  def _contains_BGL(self, level, names):
664 7ee7c0c7 Guido Trotter
    """Check if acting on the given level and set of names will change the
665 7ee7c0c7 Guido Trotter
    status of the Big Ganeti Lock.
666 7ee7c0c7 Guido Trotter

667 7ee7c0c7 Guido Trotter
    """
668 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
669 7ee7c0c7 Guido Trotter
670 7ee7c0c7 Guido Trotter
  def acquire(self, level, names, blocking=1, shared=0):
671 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
672 7ee7c0c7 Guido Trotter

673 7ee7c0c7 Guido Trotter
    Args:
674 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be acquired.
675 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS.
676 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be acquired.
677 7ee7c0c7 Guido Trotter
             (special lock names, or instance/node names)
678 7ee7c0c7 Guido Trotter
      shared: whether to acquire in shared mode. By default an exclusive lock
679 7ee7c0c7 Guido Trotter
              will be acquired.
680 7ee7c0c7 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in try-lock mode.
681 7ee7c0c7 Guido Trotter
                this locking mode is not supported yet.
682 7ee7c0c7 Guido Trotter

683 7ee7c0c7 Guido Trotter
    """
684 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
685 7ee7c0c7 Guido Trotter
686 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
687 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
688 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
689 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
690 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
691 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
692 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
693 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
694 7ee7c0c7 Guido Trotter
695 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
696 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level" 
697 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
698 7ee7c0c7 Guido Trotter
699 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
700 7ee7c0c7 Guido Trotter
    return self.__keyring[level].acquire(names, shared=shared,
701 7ee7c0c7 Guido Trotter
                                         blocking=blocking)
702 7ee7c0c7 Guido Trotter
703 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
704 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
705 7ee7c0c7 Guido Trotter

706 7ee7c0c7 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
707 7ee7c0c7 Guido Trotter
    before releasing them.
708 7ee7c0c7 Guido Trotter

709 7ee7c0c7 Guido Trotter
    Args:
710 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be released.
711 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS.
712 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be released.
713 7ee7c0c7 Guido Trotter
             (defaults to all the locks acquired at that level).
714 7ee7c0c7 Guido Trotter

715 7ee7c0c7 Guido Trotter
    """
716 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
717 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
718 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
719 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
720 7ee7c0c7 Guido Trotter
            " at upper levels")
721 7ee7c0c7 Guido Trotter
722 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
723 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
724 7ee7c0c7 Guido Trotter
725 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
726 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
727 7ee7c0c7 Guido Trotter

728 7ee7c0c7 Guido Trotter
    Args:
729 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be added.
730 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS_MOD.
731 7ee7c0c7 Guido Trotter
      names: names of the locks to acquire
732 7ee7c0c7 Guido Trotter
      acquired: whether to acquire the newly added locks
733 7ee7c0c7 Guido Trotter
      shared: whether the acquisition will be shared
734 7ee7c0c7 Guido Trotter
    """
735 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
736 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
737 7ee7c0c7 Guido Trotter
           " operations")
738 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
739 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
740 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
741 7ee7c0c7 Guido Trotter
742 7ee7c0c7 Guido Trotter
  def remove(self, level, names, blocking=1):
743 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
744 7ee7c0c7 Guido Trotter

745 7ee7c0c7 Guido Trotter
    You must either already own the locks you are trying to remove exclusively
746 7ee7c0c7 Guido Trotter
    or not own any lock at an upper level.
747 7ee7c0c7 Guido Trotter

748 7ee7c0c7 Guido Trotter
    Args:
749 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be removed.
750 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS_MOD.
751 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be removed.
752 7ee7c0c7 Guido Trotter
             (special lock names, or instance/node names)
753 7ee7c0c7 Guido Trotter
      blocking: whether to block while trying to operate in try-lock mode.
754 7ee7c0c7 Guido Trotter
                this locking mode is not supported yet.
755 7ee7c0c7 Guido Trotter

756 7ee7c0c7 Guido Trotter
    """
757 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
758 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
759 7ee7c0c7 Guido Trotter
           " operations")
760 7ee7c0c7 Guido Trotter
    # Check we either own the level or don't own anything from here up.
761 7ee7c0c7 Guido Trotter
    # LockSet.remove() will check the case in which we don't own all the needed
762 7ee7c0c7 Guido Trotter
    # resources, or we have a shared ownership.
763 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
764 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
765 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
766 7ee7c0c7 Guido Trotter
    return self.__keyring[level].remove(names, blocking)