Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ b2dabfd6

History | View | Annotate | Download (28 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 cdb08f44 Michael Hanselmann
      result = self.__is_owned(shared=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 cdb08f44 Michael Hanselmann
  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 162c1c1f Guido Trotter
  def acquire(self, blocking=1, shared=0):
137 162c1c1f Guido Trotter
    """Acquire a shared lock.
138 162c1c1f Guido Trotter

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

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

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

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

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

228 a95fd5d7 Guido Trotter
    Args:
229 a95fd5d7 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
230 a95fd5d7 Guido Trotter
                try-lock mode.  this locking mode is not supported yet unless
231 a95fd5d7 Guido Trotter
                you are already holding exclusively the lock.
232 a95fd5d7 Guido Trotter

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

261 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
262 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
263 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
264 aaae9bc0 Guido Trotter
  preventing deadlock.
265 aaae9bc0 Guido Trotter

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

268 aaae9bc0 Guido Trotter
  """
269 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
270 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
271 aaae9bc0 Guido Trotter

272 aaae9bc0 Guido Trotter
    Args:
273 aaae9bc0 Guido Trotter
      members: initial members of the set
274 aaae9bc0 Guido Trotter

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

333 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
334 aaae9bc0 Guido Trotter
    result after releasing the lock.
335 aaae9bc0 Guido Trotter

336 aaae9bc0 Guido Trotter
    """
337 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
338 aaae9bc0 Guido Trotter
339 aaae9bc0 Guido Trotter
  def _names(self):
340 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
341 aaae9bc0 Guido Trotter

342 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
343 cdb08f44 Michael Hanselmann

344 aaae9bc0 Guido Trotter
    """
345 aaae9bc0 Guido Trotter
    self.__lock.acquire(shared=1)
346 aaae9bc0 Guido Trotter
    try:
347 aaae9bc0 Guido Trotter
      result = self.__names()
348 aaae9bc0 Guido Trotter
    finally:
349 aaae9bc0 Guido Trotter
      self.__lock.release()
350 0cf257c5 Guido Trotter
    return set(result)
351 aaae9bc0 Guido Trotter
352 aaae9bc0 Guido Trotter
  def acquire(self, names, blocking=1, shared=0):
353 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
354 aaae9bc0 Guido Trotter

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

363 aaae9bc0 Guido Trotter
    Returns:
364 aaae9bc0 Guido Trotter
      True: when all the locks are successfully acquired
365 aaae9bc0 Guido Trotter

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

371 aaae9bc0 Guido Trotter
    """
372 aaae9bc0 Guido Trotter
    if not blocking:
373 aaae9bc0 Guido Trotter
      # We don't have non-blocking mode for now
374 aaae9bc0 Guido Trotter
      raise NotImplementedError
375 aaae9bc0 Guido Trotter
376 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
377 aaae9bc0 Guido Trotter
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
378 aaae9bc0 Guido Trotter
379 3b7ed473 Guido Trotter
    if names is None:
380 3b7ed473 Guido Trotter
      # If no names are given acquire the whole set by not letting new names
381 3b7ed473 Guido Trotter
      # being added before we release, and getting the current list of names.
382 3b7ed473 Guido Trotter
      # Some of them may then be deleted later, but we'll cope with this.
383 3b7ed473 Guido Trotter
      #
384 3b7ed473 Guido Trotter
      # We'd like to acquire this lock in a shared way, as it's nice if
385 3b7ed473 Guido Trotter
      # everybody else can use the instances at the same time. If are acquiring
386 3b7ed473 Guido Trotter
      # them exclusively though they won't be able to do this anyway, though,
387 3b7ed473 Guido Trotter
      # so we'll get the list lock exclusively as well in order to be able to
388 3b7ed473 Guido Trotter
      # do add() on the set while owning it.
389 3b7ed473 Guido Trotter
      self.__lock.acquire(shared=shared)
390 b2dabfd6 Guido Trotter
      try:
391 b2dabfd6 Guido Trotter
        # note we own the set-lock
392 b2dabfd6 Guido Trotter
        self._add_owned()
393 b2dabfd6 Guido Trotter
        names = self.__names()
394 b2dabfd6 Guido Trotter
      except:
395 b2dabfd6 Guido Trotter
        # We shouldn't have problems adding the lock to the owners list, but
396 b2dabfd6 Guido Trotter
        # if we did we'll try to release this lock and re-raise exception.
397 b2dabfd6 Guido Trotter
        # Of course something is going to be really wrong, after this.
398 b2dabfd6 Guido Trotter
        self.__lock.release()
399 b2dabfd6 Guido Trotter
        raise
400 3b7ed473 Guido Trotter
401 806e20fd Guido Trotter
    try:
402 806e20fd Guido Trotter
      # Support passing in a single resource to acquire rather than many
403 806e20fd Guido Trotter
      if isinstance(names, basestring):
404 806e20fd Guido Trotter
        names = [names]
405 806e20fd Guido Trotter
      else:
406 806e20fd Guido Trotter
        names.sort()
407 806e20fd Guido Trotter
408 806e20fd Guido Trotter
      acquire_list = []
409 806e20fd Guido Trotter
      # First we look the locks up on __lockdict. We have no way of being sure
410 806e20fd Guido Trotter
      # they will still be there after, but this makes it a lot faster should
411 806e20fd Guido Trotter
      # just one of them be the already wrong
412 806e20fd Guido Trotter
      for lname in names:
413 806e20fd Guido Trotter
        try:
414 806e20fd Guido Trotter
          lock = self.__lockdict[lname] # raises KeyError if the lock is not there
415 806e20fd Guido Trotter
          acquire_list.append((lname, lock))
416 806e20fd Guido Trotter
        except (KeyError):
417 3b7ed473 Guido Trotter
          if self.__lock._is_owned():
418 3b7ed473 Guido Trotter
            # We are acquiring all the set, it doesn't matter if this particular
419 3b7ed473 Guido Trotter
            # element is not there anymore.
420 3b7ed473 Guido Trotter
            continue
421 3b7ed473 Guido Trotter
          else:
422 3b7ed473 Guido Trotter
            raise errors.LockError('non-existing lock in set (%s)' % lname)
423 806e20fd Guido Trotter
424 806e20fd Guido Trotter
      # This will hold the locknames we effectively acquired.
425 806e20fd Guido Trotter
      acquired = set()
426 806e20fd Guido Trotter
      # Now acquire_list contains a sorted list of resources and locks we want.
427 806e20fd Guido Trotter
      # In order to get them we loop on this (private) list and acquire() them.
428 806e20fd Guido Trotter
      # We gave no real guarantee they will still exist till this is done but
429 806e20fd Guido Trotter
      # .acquire() itself is safe and will alert us if the lock gets deleted.
430 806e20fd Guido Trotter
      for (lname, lock) in acquire_list:
431 aaae9bc0 Guido Trotter
        try:
432 806e20fd Guido Trotter
          lock.acquire(shared=shared) # raises LockError if the lock is deleted
433 ea3f80bf Guido Trotter
          # now the lock cannot be deleted, we have it!
434 b2dabfd6 Guido Trotter
          self._add_owned(name=lname)
435 ea3f80bf Guido Trotter
          acquired.add(lname)
436 806e20fd Guido Trotter
        except (errors.LockError):
437 3b7ed473 Guido Trotter
          if self.__lock._is_owned():
438 3b7ed473 Guido Trotter
            # We are acquiring all the set, it doesn't matter if this particular
439 3b7ed473 Guido Trotter
            # element is not there anymore.
440 3b7ed473 Guido Trotter
            continue
441 3b7ed473 Guido Trotter
          else:
442 3b7ed473 Guido Trotter
            name_fail = lname
443 3b7ed473 Guido Trotter
            for lname in self._list_owned():
444 3b7ed473 Guido Trotter
              self.__lockdict[lname].release()
445 b2dabfd6 Guido Trotter
              self._del_owned(name=lname)
446 3b7ed473 Guido Trotter
            raise errors.LockError('non-existing lock in set (%s)' % name_fail)
447 ea3f80bf Guido Trotter
        except:
448 ea3f80bf Guido Trotter
          # We shouldn't have problems adding the lock to the owners list, but
449 ea3f80bf Guido Trotter
          # if we did we'll try to release this lock and re-raise exception.
450 ea3f80bf Guido Trotter
          # Of course something is going to be really wrong, after this.
451 ea3f80bf Guido Trotter
          if lock._is_owned():
452 ea3f80bf Guido Trotter
            lock.release()
453 ea3f80bf Guido Trotter
            raise
454 806e20fd Guido Trotter
455 806e20fd Guido Trotter
    except:
456 3b7ed473 Guido Trotter
      # If something went wrong and we had the set-lock let's release it...
457 3b7ed473 Guido Trotter
      if self.__lock._is_owned():
458 3b7ed473 Guido Trotter
        self.__lock.release()
459 806e20fd Guido Trotter
      raise
460 aaae9bc0 Guido Trotter
461 0cc00929 Guido Trotter
    return acquired
462 aaae9bc0 Guido Trotter
463 aaae9bc0 Guido Trotter
  def release(self, names=None):
464 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
465 aaae9bc0 Guido Trotter

466 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
467 aaae9bc0 Guido Trotter
    before releasing them.
468 aaae9bc0 Guido Trotter

469 aaae9bc0 Guido Trotter
    Args:
470 aaae9bc0 Guido Trotter
      names: the names of the locks which shall be released.
471 aaae9bc0 Guido Trotter
             (defaults to all the locks acquired at that level).
472 aaae9bc0 Guido Trotter

473 aaae9bc0 Guido Trotter
    """
474 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
475 aaae9bc0 Guido Trotter
476 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
477 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
478 aaae9bc0 Guido Trotter
      names = [names]
479 aaae9bc0 Guido Trotter
480 aaae9bc0 Guido Trotter
    if names is None:
481 aaae9bc0 Guido Trotter
      names = self._list_owned()
482 aaae9bc0 Guido Trotter
    else:
483 aaae9bc0 Guido Trotter
      names = set(names)
484 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
485 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
486 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
487 aaae9bc0 Guido Trotter
488 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
489 3b7ed473 Guido Trotter
    # After this 'add' can work again
490 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
491 3b7ed473 Guido Trotter
      self.__lock.release()
492 b2dabfd6 Guido Trotter
      self._del_owned()
493 3b7ed473 Guido Trotter
494 aaae9bc0 Guido Trotter
    for lockname in names:
495 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
496 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
497 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
498 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
499 aaae9bc0 Guido Trotter
500 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
501 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
502 aaae9bc0 Guido Trotter

503 aaae9bc0 Guido Trotter
    Args:
504 aaae9bc0 Guido Trotter
      names: names of the new elements to add
505 aaae9bc0 Guido Trotter
      acquired: pre-acquire the new resource?
506 aaae9bc0 Guido Trotter
      shared: is the pre-acquisition shared?
507 aaae9bc0 Guido Trotter

508 aaae9bc0 Guido Trotter
    """
509 3b7ed473 Guido Trotter
510 3b7ed473 Guido Trotter
    assert not self.__lock._is_owned(shared=1), (
511 3b7ed473 Guido Trotter
           "Cannot add new elements while sharing the set-lock")
512 3b7ed473 Guido Trotter
513 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
514 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
515 aaae9bc0 Guido Trotter
      names = [names]
516 aaae9bc0 Guido Trotter
517 3b7ed473 Guido Trotter
    # If we don't already own the set-level lock acquire it in an exclusive way
518 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
519 3b7ed473 Guido Trotter
    release_lock = False
520 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
521 3b7ed473 Guido Trotter
      release_lock = True
522 3b7ed473 Guido Trotter
      self.__lock.acquire()
523 3b7ed473 Guido Trotter
524 aaae9bc0 Guido Trotter
    try:
525 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
526 aaae9bc0 Guido Trotter
      if invalid_names:
527 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
528 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
529 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
530 aaae9bc0 Guido Trotter
        raise errors.LockError("duplicate add() (%s)" % invalid_names)
531 aaae9bc0 Guido Trotter
532 aaae9bc0 Guido Trotter
      for lockname in names:
533 aaae9bc0 Guido Trotter
        lock = SharedLock()
534 aaae9bc0 Guido Trotter
535 aaae9bc0 Guido Trotter
        if acquired:
536 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
537 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
538 aaae9bc0 Guido Trotter
          try:
539 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
540 aaae9bc0 Guido Trotter
          except:
541 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
542 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
543 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
544 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
545 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
546 aaae9bc0 Guido Trotter
            # release is just a safety measure.
547 aaae9bc0 Guido Trotter
            lock.release()
548 aaae9bc0 Guido Trotter
            raise
549 aaae9bc0 Guido Trotter
550 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
551 aaae9bc0 Guido Trotter
552 aaae9bc0 Guido Trotter
    finally:
553 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
554 3b7ed473 Guido Trotter
      if release_lock:
555 3b7ed473 Guido Trotter
        self.__lock.release()
556 aaae9bc0 Guido Trotter
557 aaae9bc0 Guido Trotter
    return True
558 aaae9bc0 Guido Trotter
559 aaae9bc0 Guido Trotter
  def remove(self, names, blocking=1):
560 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
561 aaae9bc0 Guido Trotter

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

565 aaae9bc0 Guido Trotter
    Args:
566 aaae9bc0 Guido Trotter
      names: names of the resource to remove.
567 aaae9bc0 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
568 aaae9bc0 Guido Trotter
                try-lock mode.  this locking mode is not supported yet unless
569 aaae9bc0 Guido Trotter
                you are already holding exclusively the locks.
570 aaae9bc0 Guido Trotter

571 aaae9bc0 Guido Trotter
    Returns:
572 3f404fc5 Guido Trotter
      A list of lock which we removed. The list is always equal to the names
573 3f404fc5 Guido Trotter
      list if we were holding all the locks exclusively.
574 aaae9bc0 Guido Trotter

575 aaae9bc0 Guido Trotter
    """
576 aaae9bc0 Guido Trotter
    if not blocking and not self._is_owned():
577 aaae9bc0 Guido Trotter
      # We don't have non-blocking mode for now
578 aaae9bc0 Guido Trotter
      raise NotImplementedError
579 aaae9bc0 Guido Trotter
580 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
581 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
582 aaae9bc0 Guido Trotter
      names = [names]
583 aaae9bc0 Guido Trotter
584 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
585 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
586 aaae9bc0 Guido Trotter
    # by the lock itself.
587 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
588 aaae9bc0 Guido Trotter
      "remove() on acquired lockset while not owning all elements")
589 aaae9bc0 Guido Trotter
590 3f404fc5 Guido Trotter
    removed = []
591 aaae9bc0 Guido Trotter
592 aaae9bc0 Guido Trotter
    for lname in names:
593 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
594 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
595 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
596 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
597 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
598 aaae9bc0 Guido Trotter
      try:
599 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
600 3f404fc5 Guido Trotter
        removed.append(lname)
601 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
602 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
603 aaae9bc0 Guido Trotter
        assert not self._is_owned(), "remove failed while holding lockset"
604 aaae9bc0 Guido Trotter
      else:
605 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
606 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
607 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
608 aaae9bc0 Guido Trotter
        # since before our call to delete()).
609 aaae9bc0 Guido Trotter
        #
610 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
611 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
612 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
613 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
614 aaae9bc0 Guido Trotter
        if self._is_owned():
615 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
616 aaae9bc0 Guido Trotter
617 3f404fc5 Guido Trotter
    return removed
618 aaae9bc0 Guido Trotter
619 7ee7c0c7 Guido Trotter
620 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
621 7ee7c0c7 Guido Trotter
# Current rules are:
622 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
623 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
624 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
625 7ee7c0c7 Guido Trotter
#   avoided.
626 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
627 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
628 7ee7c0c7 Guido Trotter
#   the same time.
629 7ee7c0c7 Guido Trotter
#  - level LEVEL_CONFIG contains the configuration lock, which you must acquire
630 7ee7c0c7 Guido Trotter
#  before reading or changing the config file.
631 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
632 7ee7c0c7 Guido Trotter
LEVEL_NODE = 1
633 7ee7c0c7 Guido Trotter
LEVEL_INSTANCE = 2
634 7ee7c0c7 Guido Trotter
LEVEL_CONFIG = 3
635 7ee7c0c7 Guido Trotter
636 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
637 7ee7c0c7 Guido Trotter
          LEVEL_NODE,
638 7ee7c0c7 Guido Trotter
          LEVEL_INSTANCE,
639 7ee7c0c7 Guido Trotter
          LEVEL_CONFIG]
640 7ee7c0c7 Guido Trotter
641 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
642 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
643 7ee7c0c7 Guido Trotter
644 7ee7c0c7 Guido Trotter
# Constant for the big ganeti lock and config lock
645 7ee7c0c7 Guido Trotter
BGL = 'BGL'
646 7ee7c0c7 Guido Trotter
CONFIG = 'config'
647 7ee7c0c7 Guido Trotter
648 7ee7c0c7 Guido Trotter
649 7ee7c0c7 Guido Trotter
class GanetiLockManager:
650 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
651 7ee7c0c7 Guido Trotter

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

657 7ee7c0c7 Guido Trotter
  """
658 7ee7c0c7 Guido Trotter
  _instance = None
659 7ee7c0c7 Guido Trotter
660 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
661 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
662 7ee7c0c7 Guido Trotter

663 7ee7c0c7 Guido Trotter
    There should be only a
664 7ee7c0c7 Guido Trotter
    GanetiLockManager object at any time, so this function raises an error if this
665 7ee7c0c7 Guido Trotter
    is not the case.
666 7ee7c0c7 Guido Trotter

667 7ee7c0c7 Guido Trotter
    Args:
668 7ee7c0c7 Guido Trotter
      nodes: list of node names
669 7ee7c0c7 Guido Trotter
      instances: list of instance names
670 7ee7c0c7 Guido Trotter

671 7ee7c0c7 Guido Trotter
    """
672 7ee7c0c7 Guido Trotter
    assert self.__class__._instance is None, "double GanetiLockManager instance"
673 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
674 7ee7c0c7 Guido Trotter
675 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
676 7ee7c0c7 Guido Trotter
    # locking order.
677 7ee7c0c7 Guido Trotter
    self.__keyring = {
678 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
679 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
680 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
681 7ee7c0c7 Guido Trotter
      LEVEL_CONFIG: LockSet([CONFIG]),
682 7ee7c0c7 Guido Trotter
    }
683 7ee7c0c7 Guido Trotter
684 7ee7c0c7 Guido Trotter
  def _names(self, level):
685 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
686 7ee7c0c7 Guido Trotter
    Used for debugging/testing purposes.
687 7ee7c0c7 Guido Trotter

688 7ee7c0c7 Guido Trotter
    Args:
689 7ee7c0c7 Guido Trotter
      level: the level whose list of locks to get
690 7ee7c0c7 Guido Trotter

691 7ee7c0c7 Guido Trotter
    """
692 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
693 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
694 7ee7c0c7 Guido Trotter
695 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
696 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
697 7ee7c0c7 Guido Trotter

698 7ee7c0c7 Guido Trotter
    """
699 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
700 7ee7c0c7 Guido Trotter
701 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
702 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
703 7ee7c0c7 Guido Trotter

704 7ee7c0c7 Guido Trotter
    """
705 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
706 7ee7c0c7 Guido Trotter
707 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
708 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
709 7ee7c0c7 Guido Trotter

710 7ee7c0c7 Guido Trotter
    """
711 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
712 7ee7c0c7 Guido Trotter
    # the test cases.
713 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
714 7ee7c0c7 Guido Trotter
715 7ee7c0c7 Guido Trotter
  def _BGL_owned(self):
716 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
717 7ee7c0c7 Guido Trotter

718 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
719 7ee7c0c7 Guido Trotter

720 7ee7c0c7 Guido Trotter
    """
721 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
722 7ee7c0c7 Guido Trotter
723 7ee7c0c7 Guido Trotter
  def _contains_BGL(self, level, names):
724 7ee7c0c7 Guido Trotter
    """Check if acting on the given level and set of names will change the
725 7ee7c0c7 Guido Trotter
    status of the Big Ganeti Lock.
726 7ee7c0c7 Guido Trotter

727 7ee7c0c7 Guido Trotter
    """
728 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
729 7ee7c0c7 Guido Trotter
730 7ee7c0c7 Guido Trotter
  def acquire(self, level, names, blocking=1, shared=0):
731 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
732 7ee7c0c7 Guido Trotter

733 7ee7c0c7 Guido Trotter
    Args:
734 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be acquired.
735 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS.
736 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be acquired.
737 7ee7c0c7 Guido Trotter
             (special lock names, or instance/node names)
738 7ee7c0c7 Guido Trotter
      shared: whether to acquire in shared mode. By default an exclusive lock
739 7ee7c0c7 Guido Trotter
              will be acquired.
740 7ee7c0c7 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in try-lock mode.
741 7ee7c0c7 Guido Trotter
                this locking mode is not supported yet.
742 7ee7c0c7 Guido Trotter

743 7ee7c0c7 Guido Trotter
    """
744 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
745 7ee7c0c7 Guido Trotter
746 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
747 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
748 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
749 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
750 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
751 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
752 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
753 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
754 7ee7c0c7 Guido Trotter
755 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
756 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level" 
757 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
758 7ee7c0c7 Guido Trotter
759 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
760 7ee7c0c7 Guido Trotter
    return self.__keyring[level].acquire(names, shared=shared,
761 7ee7c0c7 Guido Trotter
                                         blocking=blocking)
762 7ee7c0c7 Guido Trotter
763 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
764 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
765 7ee7c0c7 Guido Trotter

766 7ee7c0c7 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
767 7ee7c0c7 Guido Trotter
    before releasing them.
768 7ee7c0c7 Guido Trotter

769 7ee7c0c7 Guido Trotter
    Args:
770 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be released.
771 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS.
772 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be released.
773 7ee7c0c7 Guido Trotter
             (defaults to all the locks acquired at that level).
774 7ee7c0c7 Guido Trotter

775 7ee7c0c7 Guido Trotter
    """
776 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
777 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
778 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
779 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
780 7ee7c0c7 Guido Trotter
            " at upper levels")
781 7ee7c0c7 Guido Trotter
782 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
783 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
784 7ee7c0c7 Guido Trotter
785 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
786 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
787 7ee7c0c7 Guido Trotter

788 7ee7c0c7 Guido Trotter
    Args:
789 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be added.
790 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS_MOD.
791 7ee7c0c7 Guido Trotter
      names: names of the locks to acquire
792 7ee7c0c7 Guido Trotter
      acquired: whether to acquire the newly added locks
793 7ee7c0c7 Guido Trotter
      shared: whether the acquisition will be shared
794 7ee7c0c7 Guido Trotter
    """
795 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
796 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
797 7ee7c0c7 Guido Trotter
           " operations")
798 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
799 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
800 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
801 7ee7c0c7 Guido Trotter
802 7ee7c0c7 Guido Trotter
  def remove(self, level, names, blocking=1):
803 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
804 7ee7c0c7 Guido Trotter

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

808 7ee7c0c7 Guido Trotter
    Args:
809 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be removed.
810 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS_MOD.
811 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be removed.
812 7ee7c0c7 Guido Trotter
             (special lock names, or instance/node names)
813 7ee7c0c7 Guido Trotter
      blocking: whether to block while trying to operate in try-lock mode.
814 7ee7c0c7 Guido Trotter
                this locking mode is not supported yet.
815 7ee7c0c7 Guido Trotter

816 7ee7c0c7 Guido Trotter
    """
817 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
818 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
819 7ee7c0c7 Guido Trotter
           " operations")
820 7ee7c0c7 Guido Trotter
    # Check we either own the level or don't own anything from here up.
821 7ee7c0c7 Guido Trotter
    # LockSet.remove() will check the case in which we don't own all the needed
822 7ee7c0c7 Guido Trotter
    # resources, or we have a shared ownership.
823 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
824 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
825 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
826 cdb08f44 Michael Hanselmann
    return self.__keyring[level].remove(names, blocking=blocking)