Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ a1578d63

History | View | Annotate | Download (29.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 42a999d1 Guido Trotter
def ssynchronized(lock, shared=0):
33 42a999d1 Guido Trotter
  """Shared Synchronization decorator.
34 42a999d1 Guido Trotter

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

39 42a999d1 Guido Trotter
  """
40 42a999d1 Guido Trotter
  def wrap(fn):
41 42a999d1 Guido Trotter
    def sync_function(*args, **kwargs):
42 42a999d1 Guido Trotter
      lock.acquire(shared=shared)
43 42a999d1 Guido Trotter
      try:
44 42a999d1 Guido Trotter
        return fn(*args, **kwargs)
45 42a999d1 Guido Trotter
      finally:
46 42a999d1 Guido Trotter
        lock.release()
47 42a999d1 Guido Trotter
    return sync_function
48 42a999d1 Guido Trotter
  return wrap
49 42a999d1 Guido Trotter
50 42a999d1 Guido Trotter
51 162c1c1f Guido Trotter
class SharedLock:
52 162c1c1f Guido Trotter
  """Implements a shared lock.
53 162c1c1f Guido Trotter

54 162c1c1f Guido Trotter
  Multiple threads can acquire the lock in a shared way, calling
55 162c1c1f Guido Trotter
  acquire_shared().  In order to acquire the lock in an exclusive way threads
56 162c1c1f Guido Trotter
  can call acquire_exclusive().
57 162c1c1f Guido Trotter

58 162c1c1f Guido Trotter
  The lock prevents starvation but does not guarantee that threads will acquire
59 162c1c1f Guido Trotter
  the shared lock in the order they queued for it, just that they will
60 162c1c1f Guido Trotter
  eventually do so.
61 162c1c1f Guido Trotter

62 162c1c1f Guido Trotter
  """
63 162c1c1f Guido Trotter
  def __init__(self):
64 d6646186 Guido Trotter
    """Construct a new SharedLock"""
65 162c1c1f Guido Trotter
    # we have two conditions, c_shr and c_exc, sharing the same lock.
66 162c1c1f Guido Trotter
    self.__lock = threading.Lock()
67 162c1c1f Guido Trotter
    self.__turn_shr = threading.Condition(self.__lock)
68 162c1c1f Guido Trotter
    self.__turn_exc = threading.Condition(self.__lock)
69 162c1c1f Guido Trotter
70 162c1c1f Guido Trotter
    # current lock holders
71 162c1c1f Guido Trotter
    self.__shr = set()
72 162c1c1f Guido Trotter
    self.__exc = None
73 162c1c1f Guido Trotter
74 162c1c1f Guido Trotter
    # lock waiters
75 162c1c1f Guido Trotter
    self.__nwait_exc = 0
76 162c1c1f Guido Trotter
    self.__nwait_shr = 0
77 4d686df8 Guido Trotter
    self.__npass_shr = 0
78 162c1c1f Guido Trotter
79 a95fd5d7 Guido Trotter
    # is this lock in the deleted state?
80 a95fd5d7 Guido Trotter
    self.__deleted = False
81 a95fd5d7 Guido Trotter
82 162c1c1f Guido Trotter
  def __is_sharer(self):
83 162c1c1f Guido Trotter
    """Is the current thread sharing the lock at this time?"""
84 162c1c1f Guido Trotter
    return threading.currentThread() in self.__shr
85 162c1c1f Guido Trotter
86 162c1c1f Guido Trotter
  def __is_exclusive(self):
87 162c1c1f Guido Trotter
    """Is the current thread holding the lock exclusively at this time?"""
88 162c1c1f Guido Trotter
    return threading.currentThread() == self.__exc
89 162c1c1f Guido Trotter
90 162c1c1f Guido Trotter
  def __is_owned(self, shared=-1):
91 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
92 162c1c1f Guido Trotter

93 162c1c1f Guido Trotter
    This is a private version of the function, which presumes you're holding
94 162c1c1f Guido Trotter
    the internal lock.
95 162c1c1f Guido Trotter

96 162c1c1f Guido Trotter
    """
97 162c1c1f Guido Trotter
    if shared < 0:
98 162c1c1f Guido Trotter
      return self.__is_sharer() or self.__is_exclusive()
99 162c1c1f Guido Trotter
    elif shared:
100 162c1c1f Guido Trotter
      return self.__is_sharer()
101 162c1c1f Guido Trotter
    else:
102 162c1c1f Guido Trotter
      return self.__is_exclusive()
103 162c1c1f Guido Trotter
104 162c1c1f Guido Trotter
  def _is_owned(self, shared=-1):
105 162c1c1f Guido Trotter
    """Is the current thread somehow owning the lock at this time?
106 162c1c1f Guido Trotter

107 162c1c1f Guido Trotter
    Args:
108 162c1c1f Guido Trotter
      shared:
109 162c1c1f Guido Trotter
        < 0: check for any type of ownership (default)
110 162c1c1f Guido Trotter
        0: check for exclusive ownership
111 162c1c1f Guido Trotter
        > 0: check for shared ownership
112 162c1c1f Guido Trotter

113 162c1c1f Guido Trotter
    """
114 162c1c1f Guido Trotter
    self.__lock.acquire()
115 162c1c1f Guido Trotter
    try:
116 cdb08f44 Michael Hanselmann
      result = self.__is_owned(shared=shared)
117 162c1c1f Guido Trotter
    finally:
118 162c1c1f Guido Trotter
      self.__lock.release()
119 162c1c1f Guido Trotter
120 162c1c1f Guido Trotter
    return result
121 162c1c1f Guido Trotter
122 cdb08f44 Michael Hanselmann
  def __wait(self, c):
123 a95fd5d7 Guido Trotter
    """Wait on the given condition, and raise an exception if the current lock
124 a95fd5d7 Guido Trotter
    is declared deleted in the meantime.
125 a95fd5d7 Guido Trotter

126 a95fd5d7 Guido Trotter
    Args:
127 a95fd5d7 Guido Trotter
      c: condition to wait on
128 a95fd5d7 Guido Trotter

129 a95fd5d7 Guido Trotter
    """
130 a95fd5d7 Guido Trotter
    c.wait()
131 a95fd5d7 Guido Trotter
    if self.__deleted:
132 a95fd5d7 Guido Trotter
      raise errors.LockError('deleted lock')
133 a95fd5d7 Guido Trotter
134 a95fd5d7 Guido Trotter
  def __exclusive_acquire(self):
135 a95fd5d7 Guido Trotter
    """Acquire the lock exclusively.
136 a95fd5d7 Guido Trotter

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

141 a95fd5d7 Guido Trotter
    """
142 a95fd5d7 Guido Trotter
    self.__nwait_exc += 1
143 a95fd5d7 Guido Trotter
    try:
144 a95fd5d7 Guido Trotter
      # This is to save ourselves from a nasty race condition that could
145 a95fd5d7 Guido Trotter
      # theoretically make the sharers starve.
146 a95fd5d7 Guido Trotter
      if self.__nwait_shr > 0 or self.__nwait_exc > 1:
147 a95fd5d7 Guido Trotter
        self.__wait(self.__turn_exc)
148 a95fd5d7 Guido Trotter
149 a95fd5d7 Guido Trotter
      while len(self.__shr) > 0 or self.__exc is not None:
150 a95fd5d7 Guido Trotter
        self.__wait(self.__turn_exc)
151 a95fd5d7 Guido Trotter
152 a95fd5d7 Guido Trotter
      self.__exc = threading.currentThread()
153 a95fd5d7 Guido Trotter
    finally:
154 a95fd5d7 Guido Trotter
      self.__nwait_exc -= 1
155 a95fd5d7 Guido Trotter
156 4d686df8 Guido Trotter
    assert self.__npass_shr == 0, "SharedLock: internal fairness violation"
157 4d686df8 Guido Trotter
158 162c1c1f Guido Trotter
  def acquire(self, blocking=1, shared=0):
159 162c1c1f Guido Trotter
    """Acquire a shared lock.
160 162c1c1f Guido Trotter

161 162c1c1f Guido Trotter
    Args:
162 162c1c1f Guido Trotter
      shared: whether to acquire in shared mode. By default an exclusive lock
163 162c1c1f Guido Trotter
              will be acquired.
164 4e07ec8c Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
165 4e07ec8c Guido Trotter
                try-lock mode. this locking mode is not supported yet.
166 162c1c1f Guido Trotter

167 162c1c1f Guido Trotter
    """
168 162c1c1f Guido Trotter
    if not blocking:
169 162c1c1f Guido Trotter
      # We don't have non-blocking mode for now
170 162c1c1f Guido Trotter
      raise NotImplementedError
171 162c1c1f Guido Trotter
172 162c1c1f Guido Trotter
    self.__lock.acquire()
173 162c1c1f Guido Trotter
    try:
174 a95fd5d7 Guido Trotter
      if self.__deleted:
175 a95fd5d7 Guido Trotter
        raise errors.LockError('deleted lock')
176 a95fd5d7 Guido Trotter
177 162c1c1f Guido Trotter
      # We cannot acquire the lock if we already have it
178 162c1c1f Guido Trotter
      assert not self.__is_owned(), "double acquire() on a non-recursive lock"
179 4d686df8 Guido Trotter
      assert self.__npass_shr >= 0, "Internal fairness condition weirdness"
180 162c1c1f Guido Trotter
181 162c1c1f Guido Trotter
      if shared:
182 162c1c1f Guido Trotter
        self.__nwait_shr += 1
183 162c1c1f Guido Trotter
        try:
184 4d686df8 Guido Trotter
          wait = False
185 162c1c1f Guido Trotter
          # If there is an exclusive holder waiting we have to wait.  We'll
186 162c1c1f Guido Trotter
          # only do this once, though, when we start waiting for the lock. Then
187 162c1c1f Guido Trotter
          # we'll just wait while there are no exclusive holders.
188 162c1c1f Guido Trotter
          if self.__nwait_exc > 0:
189 162c1c1f Guido Trotter
            # TODO: if !blocking...
190 4d686df8 Guido Trotter
            wait = True
191 a95fd5d7 Guido Trotter
            self.__wait(self.__turn_shr)
192 162c1c1f Guido Trotter
193 162c1c1f Guido Trotter
          while self.__exc is not None:
194 4d686df8 Guido Trotter
            wait = True
195 162c1c1f Guido Trotter
            # TODO: if !blocking...
196 a95fd5d7 Guido Trotter
            self.__wait(self.__turn_shr)
197 162c1c1f Guido Trotter
198 162c1c1f Guido Trotter
          self.__shr.add(threading.currentThread())
199 4d686df8 Guido Trotter
200 4d686df8 Guido Trotter
          # If we were waiting note that we passed
201 4d686df8 Guido Trotter
          if wait:
202 4d686df8 Guido Trotter
            self.__npass_shr -= 1
203 4d686df8 Guido Trotter
204 162c1c1f Guido Trotter
        finally:
205 162c1c1f Guido Trotter
          self.__nwait_shr -= 1
206 162c1c1f Guido Trotter
207 4d686df8 Guido Trotter
        assert self.__npass_shr >= 0, "Internal fairness condition weirdness"
208 162c1c1f Guido Trotter
      else:
209 a95fd5d7 Guido Trotter
        # TODO: if !blocking...
210 a95fd5d7 Guido Trotter
        # (or modify __exclusive_acquire for non-blocking mode)
211 a95fd5d7 Guido Trotter
        self.__exclusive_acquire()
212 162c1c1f Guido Trotter
213 162c1c1f Guido Trotter
    finally:
214 162c1c1f Guido Trotter
      self.__lock.release()
215 162c1c1f Guido Trotter
216 162c1c1f Guido Trotter
    return True
217 162c1c1f Guido Trotter
218 162c1c1f Guido Trotter
  def release(self):
219 162c1c1f Guido Trotter
    """Release a Shared Lock.
220 162c1c1f Guido Trotter

221 162c1c1f Guido Trotter
    You must have acquired the lock, either in shared or in exclusive mode,
222 162c1c1f Guido Trotter
    before calling this function.
223 162c1c1f Guido Trotter

224 162c1c1f Guido Trotter
    """
225 162c1c1f Guido Trotter
    self.__lock.acquire()
226 162c1c1f Guido Trotter
    try:
227 4d686df8 Guido Trotter
      assert self.__npass_shr >= 0, "Internal fairness condition weirdness"
228 162c1c1f Guido Trotter
      # Autodetect release type
229 162c1c1f Guido Trotter
      if self.__is_exclusive():
230 162c1c1f Guido Trotter
        self.__exc = None
231 162c1c1f Guido Trotter
232 162c1c1f Guido Trotter
        # An exclusive holder has just had the lock, time to put it in shared
233 162c1c1f Guido Trotter
        # mode if there are shared holders waiting. Otherwise wake up the next
234 162c1c1f Guido Trotter
        # exclusive holder.
235 162c1c1f Guido Trotter
        if self.__nwait_shr > 0:
236 4d686df8 Guido Trotter
          # Make sure at least the ones which were blocked pass.
237 4d686df8 Guido Trotter
          self.__npass_shr = self.__nwait_shr
238 162c1c1f Guido Trotter
          self.__turn_shr.notifyAll()
239 162c1c1f Guido Trotter
        elif self.__nwait_exc > 0:
240 c5cc3403 Guido Trotter
          self.__turn_exc.notify()
241 162c1c1f Guido Trotter
242 162c1c1f Guido Trotter
      elif self.__is_sharer():
243 162c1c1f Guido Trotter
        self.__shr.remove(threading.currentThread())
244 162c1c1f Guido Trotter
245 4d686df8 Guido Trotter
        # If there are shared holders waiting (and not just scheduled to pass)
246 4d686df8 Guido Trotter
        # there *must* be an exclusive holder waiting as well; otherwise what
247 4d686df8 Guido Trotter
        # were they waiting for?
248 94285814 Guido Trotter
        assert (self.__nwait_exc > 0 or self.__npass_shr == self.__nwait_shr), \
249 4d686df8 Guido Trotter
               "Lock sharers waiting while no exclusive is queueing"
250 4d686df8 Guido Trotter
251 4d686df8 Guido Trotter
        # If there are no more shared holders either in or scheduled to pass,
252 4d686df8 Guido Trotter
        # and some exclusive holders are waiting let's wake one up.
253 4d686df8 Guido Trotter
        if (len(self.__shr) == 0 and
254 4d686df8 Guido Trotter
            self.__nwait_exc > 0 and
255 4d686df8 Guido Trotter
            not self.__npass_shr > 0):
256 162c1c1f Guido Trotter
          self.__turn_exc.notify()
257 162c1c1f Guido Trotter
258 162c1c1f Guido Trotter
      else:
259 162c1c1f Guido Trotter
        assert False, "Cannot release non-owned lock"
260 162c1c1f Guido Trotter
261 162c1c1f Guido Trotter
    finally:
262 162c1c1f Guido Trotter
      self.__lock.release()
263 162c1c1f Guido Trotter
264 a95fd5d7 Guido Trotter
  def delete(self, blocking=1):
265 a95fd5d7 Guido Trotter
    """Delete a Shared Lock.
266 a95fd5d7 Guido Trotter

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

271 a95fd5d7 Guido Trotter
    Args:
272 a95fd5d7 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
273 a95fd5d7 Guido Trotter
                try-lock mode.  this locking mode is not supported yet unless
274 a95fd5d7 Guido Trotter
                you are already holding exclusively the lock.
275 a95fd5d7 Guido Trotter

276 a95fd5d7 Guido Trotter
    """
277 a95fd5d7 Guido Trotter
    self.__lock.acquire()
278 a95fd5d7 Guido Trotter
    try:
279 a95fd5d7 Guido Trotter
      assert not self.__is_sharer(), "cannot delete() a lock while sharing it"
280 a95fd5d7 Guido Trotter
281 a95fd5d7 Guido Trotter
      if self.__deleted:
282 a95fd5d7 Guido Trotter
        raise errors.LockError('deleted lock')
283 a95fd5d7 Guido Trotter
284 a95fd5d7 Guido Trotter
      if not self.__is_exclusive():
285 a95fd5d7 Guido Trotter
        if not blocking:
286 a95fd5d7 Guido Trotter
          # We don't have non-blocking mode for now
287 a95fd5d7 Guido Trotter
          raise NotImplementedError
288 a95fd5d7 Guido Trotter
        self.__exclusive_acquire()
289 a95fd5d7 Guido Trotter
290 a95fd5d7 Guido Trotter
      self.__deleted = True
291 a95fd5d7 Guido Trotter
      self.__exc = None
292 a95fd5d7 Guido Trotter
      # Wake up everybody, they will fail acquiring the lock and
293 a95fd5d7 Guido Trotter
      # raise an exception instead.
294 a95fd5d7 Guido Trotter
      self.__turn_exc.notifyAll()
295 a95fd5d7 Guido Trotter
      self.__turn_shr.notifyAll()
296 a95fd5d7 Guido Trotter
297 a95fd5d7 Guido Trotter
    finally:
298 a95fd5d7 Guido Trotter
      self.__lock.release()
299 a95fd5d7 Guido Trotter
300 aaae9bc0 Guido Trotter
301 e310b019 Guido Trotter
# Whenever we want to acquire a full LockSet we pass None as the value to acquire.
302 e310b019 Guido Trotter
# Hide this behing this nicely named constant.
303 e310b019 Guido Trotter
ALL_SET = None
304 e310b019 Guido Trotter
305 e310b019 Guido Trotter
306 aaae9bc0 Guido Trotter
class LockSet:
307 aaae9bc0 Guido Trotter
  """Implements a set of locks.
308 aaae9bc0 Guido Trotter

309 aaae9bc0 Guido Trotter
  This abstraction implements a set of shared locks for the same resource type,
310 aaae9bc0 Guido Trotter
  distinguished by name. The user can lock a subset of the resources and the
311 aaae9bc0 Guido Trotter
  LockSet will take care of acquiring the locks always in the same order, thus
312 aaae9bc0 Guido Trotter
  preventing deadlock.
313 aaae9bc0 Guido Trotter

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

316 aaae9bc0 Guido Trotter
  """
317 aaae9bc0 Guido Trotter
  def __init__(self, members=None):
318 aaae9bc0 Guido Trotter
    """Constructs a new LockSet.
319 aaae9bc0 Guido Trotter

320 aaae9bc0 Guido Trotter
    Args:
321 aaae9bc0 Guido Trotter
      members: initial members of the set
322 aaae9bc0 Guido Trotter

323 aaae9bc0 Guido Trotter
    """
324 aaae9bc0 Guido Trotter
    # Used internally to guarantee coherency.
325 aaae9bc0 Guido Trotter
    self.__lock = SharedLock()
326 aaae9bc0 Guido Trotter
327 aaae9bc0 Guido Trotter
    # The lockdict indexes the relationship name -> lock
328 aaae9bc0 Guido Trotter
    # The order-of-locking is implied by the alphabetical order of names
329 aaae9bc0 Guido Trotter
    self.__lockdict = {}
330 aaae9bc0 Guido Trotter
331 aaae9bc0 Guido Trotter
    if members is not None:
332 aaae9bc0 Guido Trotter
      for name in members:
333 aaae9bc0 Guido Trotter
        self.__lockdict[name] = SharedLock()
334 aaae9bc0 Guido Trotter
335 aaae9bc0 Guido Trotter
    # The owner dict contains the set of locks each thread owns. For
336 aaae9bc0 Guido Trotter
    # performance each thread can access its own key without a global lock on
337 aaae9bc0 Guido Trotter
    # this structure. It is paramount though that *no* other type of access is
338 aaae9bc0 Guido Trotter
    # done to this structure (eg. no looping over its keys). *_owner helper
339 aaae9bc0 Guido Trotter
    # function are defined to guarantee access is correct, but in general never
340 aaae9bc0 Guido Trotter
    # do anything different than __owners[threading.currentThread()], or there
341 aaae9bc0 Guido Trotter
    # will be trouble.
342 aaae9bc0 Guido Trotter
    self.__owners = {}
343 aaae9bc0 Guido Trotter
344 aaae9bc0 Guido Trotter
  def _is_owned(self):
345 aaae9bc0 Guido Trotter
    """Is the current thread a current level owner?"""
346 aaae9bc0 Guido Trotter
    return threading.currentThread() in self.__owners
347 aaae9bc0 Guido Trotter
348 b2dabfd6 Guido Trotter
  def _add_owned(self, name=None):
349 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
350 b2dabfd6 Guido Trotter
    if name is None:
351 b2dabfd6 Guido Trotter
      if not self._is_owned():
352 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set()
353 aaae9bc0 Guido Trotter
    else:
354 b2dabfd6 Guido Trotter
      if self._is_owned():
355 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()].add(name)
356 b2dabfd6 Guido Trotter
      else:
357 b2dabfd6 Guido Trotter
        self.__owners[threading.currentThread()] = set([name])
358 b2dabfd6 Guido Trotter
359 aaae9bc0 Guido Trotter
360 b2dabfd6 Guido Trotter
  def _del_owned(self, name=None):
361 aaae9bc0 Guido Trotter
    """Note the current thread owns the given lock"""
362 aaae9bc0 Guido Trotter
363 b2dabfd6 Guido Trotter
    if name is not None:
364 b2dabfd6 Guido Trotter
      self.__owners[threading.currentThread()].remove(name)
365 b2dabfd6 Guido Trotter
366 b2dabfd6 Guido Trotter
    # Only remove the key if we don't hold the set-lock as well
367 b2dabfd6 Guido Trotter
    if (not self.__lock._is_owned() and
368 b2dabfd6 Guido Trotter
        not self.__owners[threading.currentThread()]):
369 aaae9bc0 Guido Trotter
      del self.__owners[threading.currentThread()]
370 aaae9bc0 Guido Trotter
371 aaae9bc0 Guido Trotter
  def _list_owned(self):
372 aaae9bc0 Guido Trotter
    """Get the set of resource names owned by the current thread"""
373 aaae9bc0 Guido Trotter
    if self._is_owned():
374 aaae9bc0 Guido Trotter
      return self.__owners[threading.currentThread()].copy()
375 aaae9bc0 Guido Trotter
    else:
376 aaae9bc0 Guido Trotter
      return set()
377 aaae9bc0 Guido Trotter
378 aaae9bc0 Guido Trotter
  def __names(self):
379 aaae9bc0 Guido Trotter
    """Return the current set of names.
380 aaae9bc0 Guido Trotter

381 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
382 aaae9bc0 Guido Trotter
    result after releasing the lock.
383 aaae9bc0 Guido Trotter

384 aaae9bc0 Guido Trotter
    """
385 0cf257c5 Guido Trotter
    return self.__lockdict.keys()
386 aaae9bc0 Guido Trotter
387 aaae9bc0 Guido Trotter
  def _names(self):
388 aaae9bc0 Guido Trotter
    """Return a copy of the current set of elements.
389 aaae9bc0 Guido Trotter

390 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
391 cdb08f44 Michael Hanselmann

392 aaae9bc0 Guido Trotter
    """
393 d4803c24 Guido Trotter
    # If we don't already own the set-level lock acquired
394 d4803c24 Guido Trotter
    # we'll get it and note we need to release it later.
395 d4803c24 Guido Trotter
    release_lock = False
396 d4803c24 Guido Trotter
    if not self.__lock._is_owned():
397 d4803c24 Guido Trotter
      release_lock = True
398 d4803c24 Guido Trotter
      self.__lock.acquire(shared=1)
399 aaae9bc0 Guido Trotter
    try:
400 aaae9bc0 Guido Trotter
      result = self.__names()
401 aaae9bc0 Guido Trotter
    finally:
402 d4803c24 Guido Trotter
      if release_lock:
403 d4803c24 Guido Trotter
        self.__lock.release()
404 0cf257c5 Guido Trotter
    return set(result)
405 aaae9bc0 Guido Trotter
406 aaae9bc0 Guido Trotter
  def acquire(self, names, blocking=1, shared=0):
407 aaae9bc0 Guido Trotter
    """Acquire a set of resource locks.
408 aaae9bc0 Guido Trotter

409 aaae9bc0 Guido Trotter
    Args:
410 aaae9bc0 Guido Trotter
      names: the names of the locks which shall be acquired.
411 aaae9bc0 Guido Trotter
             (special lock names, or instance/node names)
412 aaae9bc0 Guido Trotter
      shared: whether to acquire in shared mode. By default an exclusive lock
413 aaae9bc0 Guido Trotter
              will be acquired.
414 4e07ec8c Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
415 4e07ec8c Guido Trotter
                try-lock mode.  this locking mode is not supported yet.
416 aaae9bc0 Guido Trotter

417 aaae9bc0 Guido Trotter
    Returns:
418 aaae9bc0 Guido Trotter
      True: when all the locks are successfully acquired
419 aaae9bc0 Guido Trotter

420 aaae9bc0 Guido Trotter
    Raises:
421 aaae9bc0 Guido Trotter
      errors.LockError: when any lock we try to acquire has been deleted
422 aaae9bc0 Guido Trotter
      before we succeed. In this case none of the locks requested will be
423 aaae9bc0 Guido Trotter
      acquired.
424 aaae9bc0 Guido Trotter

425 aaae9bc0 Guido Trotter
    """
426 aaae9bc0 Guido Trotter
    if not blocking:
427 aaae9bc0 Guido Trotter
      # We don't have non-blocking mode for now
428 aaae9bc0 Guido Trotter
      raise NotImplementedError
429 aaae9bc0 Guido Trotter
430 aaae9bc0 Guido Trotter
    # Check we don't already own locks at this level
431 aaae9bc0 Guido Trotter
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
432 aaae9bc0 Guido Trotter
433 3b7ed473 Guido Trotter
    if names is None:
434 3b7ed473 Guido Trotter
      # If no names are given acquire the whole set by not letting new names
435 3b7ed473 Guido Trotter
      # being added before we release, and getting the current list of names.
436 3b7ed473 Guido Trotter
      # Some of them may then be deleted later, but we'll cope with this.
437 3b7ed473 Guido Trotter
      #
438 3b7ed473 Guido Trotter
      # We'd like to acquire this lock in a shared way, as it's nice if
439 3b7ed473 Guido Trotter
      # everybody else can use the instances at the same time. If are acquiring
440 3b7ed473 Guido Trotter
      # them exclusively though they won't be able to do this anyway, though,
441 3b7ed473 Guido Trotter
      # so we'll get the list lock exclusively as well in order to be able to
442 3b7ed473 Guido Trotter
      # do add() on the set while owning it.
443 3b7ed473 Guido Trotter
      self.__lock.acquire(shared=shared)
444 b2dabfd6 Guido Trotter
      try:
445 b2dabfd6 Guido Trotter
        # note we own the set-lock
446 b2dabfd6 Guido Trotter
        self._add_owned()
447 b2dabfd6 Guido Trotter
        names = self.__names()
448 b2dabfd6 Guido Trotter
      except:
449 b2dabfd6 Guido Trotter
        # We shouldn't have problems adding the lock to the owners list, but
450 b2dabfd6 Guido Trotter
        # if we did we'll try to release this lock and re-raise exception.
451 b2dabfd6 Guido Trotter
        # Of course something is going to be really wrong, after this.
452 b2dabfd6 Guido Trotter
        self.__lock.release()
453 b2dabfd6 Guido Trotter
        raise
454 3b7ed473 Guido Trotter
455 806e20fd Guido Trotter
    try:
456 806e20fd Guido Trotter
      # Support passing in a single resource to acquire rather than many
457 806e20fd Guido Trotter
      if isinstance(names, basestring):
458 806e20fd Guido Trotter
        names = [names]
459 806e20fd Guido Trotter
      else:
460 806e20fd Guido Trotter
        names.sort()
461 806e20fd Guido Trotter
462 806e20fd Guido Trotter
      acquire_list = []
463 806e20fd Guido Trotter
      # First we look the locks up on __lockdict. We have no way of being sure
464 806e20fd Guido Trotter
      # they will still be there after, but this makes it a lot faster should
465 806e20fd Guido Trotter
      # just one of them be the already wrong
466 34ca3914 Guido Trotter
      for lname in utils.UniqueSequence(names):
467 806e20fd Guido Trotter
        try:
468 4e07ec8c Guido Trotter
          lock = self.__lockdict[lname] # raises KeyError if lock is not there
469 806e20fd Guido Trotter
          acquire_list.append((lname, lock))
470 806e20fd Guido Trotter
        except (KeyError):
471 3b7ed473 Guido Trotter
          if self.__lock._is_owned():
472 3b7ed473 Guido Trotter
            # We are acquiring all the set, it doesn't matter if this particular
473 3b7ed473 Guido Trotter
            # element is not there anymore.
474 3b7ed473 Guido Trotter
            continue
475 3b7ed473 Guido Trotter
          else:
476 3b7ed473 Guido Trotter
            raise errors.LockError('non-existing lock in set (%s)' % lname)
477 806e20fd Guido Trotter
478 806e20fd Guido Trotter
      # This will hold the locknames we effectively acquired.
479 806e20fd Guido Trotter
      acquired = set()
480 806e20fd Guido Trotter
      # Now acquire_list contains a sorted list of resources and locks we want.
481 806e20fd Guido Trotter
      # In order to get them we loop on this (private) list and acquire() them.
482 806e20fd Guido Trotter
      # We gave no real guarantee they will still exist till this is done but
483 806e20fd Guido Trotter
      # .acquire() itself is safe and will alert us if the lock gets deleted.
484 806e20fd Guido Trotter
      for (lname, lock) in acquire_list:
485 aaae9bc0 Guido Trotter
        try:
486 806e20fd Guido Trotter
          lock.acquire(shared=shared) # raises LockError if the lock is deleted
487 ea3f80bf Guido Trotter
          # now the lock cannot be deleted, we have it!
488 b2dabfd6 Guido Trotter
          self._add_owned(name=lname)
489 ea3f80bf Guido Trotter
          acquired.add(lname)
490 806e20fd Guido Trotter
        except (errors.LockError):
491 3b7ed473 Guido Trotter
          if self.__lock._is_owned():
492 3b7ed473 Guido Trotter
            # We are acquiring all the set, it doesn't matter if this particular
493 3b7ed473 Guido Trotter
            # element is not there anymore.
494 3b7ed473 Guido Trotter
            continue
495 3b7ed473 Guido Trotter
          else:
496 3b7ed473 Guido Trotter
            name_fail = lname
497 3b7ed473 Guido Trotter
            for lname in self._list_owned():
498 3b7ed473 Guido Trotter
              self.__lockdict[lname].release()
499 b2dabfd6 Guido Trotter
              self._del_owned(name=lname)
500 3b7ed473 Guido Trotter
            raise errors.LockError('non-existing lock in set (%s)' % name_fail)
501 ea3f80bf Guido Trotter
        except:
502 ea3f80bf Guido Trotter
          # We shouldn't have problems adding the lock to the owners list, but
503 ea3f80bf Guido Trotter
          # if we did we'll try to release this lock and re-raise exception.
504 ea3f80bf Guido Trotter
          # Of course something is going to be really wrong, after this.
505 ea3f80bf Guido Trotter
          if lock._is_owned():
506 ea3f80bf Guido Trotter
            lock.release()
507 ea3f80bf Guido Trotter
            raise
508 806e20fd Guido Trotter
509 806e20fd Guido Trotter
    except:
510 3b7ed473 Guido Trotter
      # If something went wrong and we had the set-lock let's release it...
511 3b7ed473 Guido Trotter
      if self.__lock._is_owned():
512 3b7ed473 Guido Trotter
        self.__lock.release()
513 806e20fd Guido Trotter
      raise
514 aaae9bc0 Guido Trotter
515 0cc00929 Guido Trotter
    return acquired
516 aaae9bc0 Guido Trotter
517 aaae9bc0 Guido Trotter
  def release(self, names=None):
518 aaae9bc0 Guido Trotter
    """Release a set of resource locks, at the same level.
519 aaae9bc0 Guido Trotter

520 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
521 aaae9bc0 Guido Trotter
    before releasing them.
522 aaae9bc0 Guido Trotter

523 aaae9bc0 Guido Trotter
    Args:
524 aaae9bc0 Guido Trotter
      names: the names of the locks which shall be released.
525 aaae9bc0 Guido Trotter
             (defaults to all the locks acquired at that level).
526 aaae9bc0 Guido Trotter

527 aaae9bc0 Guido Trotter
    """
528 aaae9bc0 Guido Trotter
    assert self._is_owned(), "release() on lock set while not owner"
529 aaae9bc0 Guido Trotter
530 aaae9bc0 Guido Trotter
    # Support passing in a single resource to release rather than many
531 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
532 aaae9bc0 Guido Trotter
      names = [names]
533 aaae9bc0 Guido Trotter
534 aaae9bc0 Guido Trotter
    if names is None:
535 aaae9bc0 Guido Trotter
      names = self._list_owned()
536 aaae9bc0 Guido Trotter
    else:
537 aaae9bc0 Guido Trotter
      names = set(names)
538 aaae9bc0 Guido Trotter
      assert self._list_owned().issuperset(names), (
539 aaae9bc0 Guido Trotter
               "release() on unheld resources %s" %
540 aaae9bc0 Guido Trotter
               names.difference(self._list_owned()))
541 aaae9bc0 Guido Trotter
542 3b7ed473 Guido Trotter
    # First of all let's release the "all elements" lock, if set.
543 3b7ed473 Guido Trotter
    # After this 'add' can work again
544 3b7ed473 Guido Trotter
    if self.__lock._is_owned():
545 3b7ed473 Guido Trotter
      self.__lock.release()
546 b2dabfd6 Guido Trotter
      self._del_owned()
547 3b7ed473 Guido Trotter
548 aaae9bc0 Guido Trotter
    for lockname in names:
549 aaae9bc0 Guido Trotter
      # If we are sure the lock doesn't leave __lockdict without being
550 aaae9bc0 Guido Trotter
      # exclusively held we can do this...
551 aaae9bc0 Guido Trotter
      self.__lockdict[lockname].release()
552 b2dabfd6 Guido Trotter
      self._del_owned(name=lockname)
553 aaae9bc0 Guido Trotter
554 aaae9bc0 Guido Trotter
  def add(self, names, acquired=0, shared=0):
555 aaae9bc0 Guido Trotter
    """Add a new set of elements to the set
556 aaae9bc0 Guido Trotter

557 aaae9bc0 Guido Trotter
    Args:
558 aaae9bc0 Guido Trotter
      names: names of the new elements to add
559 aaae9bc0 Guido Trotter
      acquired: pre-acquire the new resource?
560 aaae9bc0 Guido Trotter
      shared: is the pre-acquisition shared?
561 aaae9bc0 Guido Trotter

562 aaae9bc0 Guido Trotter
    """
563 d2aff862 Guido Trotter
    # Check we don't already own locks at this level
564 d2aff862 Guido Trotter
    assert not self._is_owned() or self.__lock._is_owned(shared=0), \
565 d2aff862 Guido Trotter
      "Cannot add locks if the set is only partially owned, or shared"
566 3b7ed473 Guido Trotter
567 aaae9bc0 Guido Trotter
    # Support passing in a single resource to add rather than many
568 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
569 aaae9bc0 Guido Trotter
      names = [names]
570 aaae9bc0 Guido Trotter
571 ab62526c Guido Trotter
    # If we don't already own the set-level lock acquired in an exclusive way
572 3b7ed473 Guido Trotter
    # we'll get it and note we need to release it later.
573 3b7ed473 Guido Trotter
    release_lock = False
574 3b7ed473 Guido Trotter
    if not self.__lock._is_owned():
575 3b7ed473 Guido Trotter
      release_lock = True
576 3b7ed473 Guido Trotter
      self.__lock.acquire()
577 3b7ed473 Guido Trotter
578 aaae9bc0 Guido Trotter
    try:
579 0cf257c5 Guido Trotter
      invalid_names = set(self.__names()).intersection(names)
580 aaae9bc0 Guido Trotter
      if invalid_names:
581 aaae9bc0 Guido Trotter
        # This must be an explicit raise, not an assert, because assert is
582 aaae9bc0 Guido Trotter
        # turned off when using optimization, and this can happen because of
583 aaae9bc0 Guido Trotter
        # concurrency even if the user doesn't want it.
584 aaae9bc0 Guido Trotter
        raise errors.LockError("duplicate add() (%s)" % invalid_names)
585 aaae9bc0 Guido Trotter
586 aaae9bc0 Guido Trotter
      for lockname in names:
587 aaae9bc0 Guido Trotter
        lock = SharedLock()
588 aaae9bc0 Guido Trotter
589 aaae9bc0 Guido Trotter
        if acquired:
590 aaae9bc0 Guido Trotter
          lock.acquire(shared=shared)
591 aaae9bc0 Guido Trotter
          # now the lock cannot be deleted, we have it!
592 aaae9bc0 Guido Trotter
          try:
593 b2dabfd6 Guido Trotter
            self._add_owned(name=lockname)
594 aaae9bc0 Guido Trotter
          except:
595 aaae9bc0 Guido Trotter
            # We shouldn't have problems adding the lock to the owners list,
596 aaae9bc0 Guido Trotter
            # but if we did we'll try to release this lock and re-raise
597 aaae9bc0 Guido Trotter
            # exception.  Of course something is going to be really wrong,
598 aaae9bc0 Guido Trotter
            # after this.  On the other hand the lock hasn't been added to the
599 aaae9bc0 Guido Trotter
            # __lockdict yet so no other threads should be pending on it. This
600 aaae9bc0 Guido Trotter
            # release is just a safety measure.
601 aaae9bc0 Guido Trotter
            lock.release()
602 aaae9bc0 Guido Trotter
            raise
603 aaae9bc0 Guido Trotter
604 aaae9bc0 Guido Trotter
        self.__lockdict[lockname] = lock
605 aaae9bc0 Guido Trotter
606 aaae9bc0 Guido Trotter
    finally:
607 3b7ed473 Guido Trotter
      # Only release __lock if we were not holding it previously.
608 3b7ed473 Guido Trotter
      if release_lock:
609 3b7ed473 Guido Trotter
        self.__lock.release()
610 aaae9bc0 Guido Trotter
611 aaae9bc0 Guido Trotter
    return True
612 aaae9bc0 Guido Trotter
613 aaae9bc0 Guido Trotter
  def remove(self, names, blocking=1):
614 aaae9bc0 Guido Trotter
    """Remove elements from the lock set.
615 aaae9bc0 Guido Trotter

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

619 aaae9bc0 Guido Trotter
    Args:
620 aaae9bc0 Guido Trotter
      names: names of the resource to remove.
621 aaae9bc0 Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
622 aaae9bc0 Guido Trotter
                try-lock mode.  this locking mode is not supported yet unless
623 aaae9bc0 Guido Trotter
                you are already holding exclusively the locks.
624 aaae9bc0 Guido Trotter

625 aaae9bc0 Guido Trotter
    Returns:
626 3f404fc5 Guido Trotter
      A list of lock which we removed. The list is always equal to the names
627 3f404fc5 Guido Trotter
      list if we were holding all the locks exclusively.
628 aaae9bc0 Guido Trotter

629 aaae9bc0 Guido Trotter
    """
630 aaae9bc0 Guido Trotter
    if not blocking and not self._is_owned():
631 aaae9bc0 Guido Trotter
      # We don't have non-blocking mode for now
632 aaae9bc0 Guido Trotter
      raise NotImplementedError
633 aaae9bc0 Guido Trotter
634 aaae9bc0 Guido Trotter
    # Support passing in a single resource to remove rather than many
635 aaae9bc0 Guido Trotter
    if isinstance(names, basestring):
636 aaae9bc0 Guido Trotter
      names = [names]
637 aaae9bc0 Guido Trotter
638 aaae9bc0 Guido Trotter
    # If we own any subset of this lock it must be a superset of what we want
639 aaae9bc0 Guido Trotter
    # to delete. The ownership must also be exclusive, but that will be checked
640 aaae9bc0 Guido Trotter
    # by the lock itself.
641 aaae9bc0 Guido Trotter
    assert not self._is_owned() or self._list_owned().issuperset(names), (
642 aaae9bc0 Guido Trotter
      "remove() on acquired lockset while not owning all elements")
643 aaae9bc0 Guido Trotter
644 3f404fc5 Guido Trotter
    removed = []
645 aaae9bc0 Guido Trotter
646 aaae9bc0 Guido Trotter
    for lname in names:
647 aaae9bc0 Guido Trotter
      # Calling delete() acquires the lock exclusively if we don't already own
648 aaae9bc0 Guido Trotter
      # it, and causes all pending and subsequent lock acquires to fail. It's
649 aaae9bc0 Guido Trotter
      # fine to call it out of order because delete() also implies release(),
650 aaae9bc0 Guido Trotter
      # and the assertion above guarantees that if we either already hold
651 aaae9bc0 Guido Trotter
      # everything we want to delete, or we hold none.
652 aaae9bc0 Guido Trotter
      try:
653 aaae9bc0 Guido Trotter
        self.__lockdict[lname].delete()
654 3f404fc5 Guido Trotter
        removed.append(lname)
655 aaae9bc0 Guido Trotter
      except (KeyError, errors.LockError):
656 aaae9bc0 Guido Trotter
        # This cannot happen if we were already holding it, verify:
657 aaae9bc0 Guido Trotter
        assert not self._is_owned(), "remove failed while holding lockset"
658 aaae9bc0 Guido Trotter
      else:
659 aaae9bc0 Guido Trotter
        # If no LockError was raised we are the ones who deleted the lock.
660 aaae9bc0 Guido Trotter
        # This means we can safely remove it from lockdict, as any further or
661 aaae9bc0 Guido Trotter
        # pending delete() or acquire() will fail (and nobody can have the lock
662 aaae9bc0 Guido Trotter
        # since before our call to delete()).
663 aaae9bc0 Guido Trotter
        #
664 aaae9bc0 Guido Trotter
        # This is done in an else clause because if the exception was thrown
665 aaae9bc0 Guido Trotter
        # it's the job of the one who actually deleted it.
666 aaae9bc0 Guido Trotter
        del self.__lockdict[lname]
667 aaae9bc0 Guido Trotter
        # And let's remove it from our private list if we owned it.
668 aaae9bc0 Guido Trotter
        if self._is_owned():
669 b2dabfd6 Guido Trotter
          self._del_owned(name=lname)
670 aaae9bc0 Guido Trotter
671 3f404fc5 Guido Trotter
    return removed
672 aaae9bc0 Guido Trotter
673 7ee7c0c7 Guido Trotter
674 7ee7c0c7 Guido Trotter
# Locking levels, must be acquired in increasing order.
675 7ee7c0c7 Guido Trotter
# Current rules are:
676 7ee7c0c7 Guido Trotter
#   - at level LEVEL_CLUSTER resides the Big Ganeti Lock (BGL) which must be
677 7ee7c0c7 Guido Trotter
#   acquired before performing any operation, either in shared or in exclusive
678 7ee7c0c7 Guido Trotter
#   mode. acquiring the BGL in exclusive mode is discouraged and should be
679 7ee7c0c7 Guido Trotter
#   avoided.
680 7ee7c0c7 Guido Trotter
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
681 7ee7c0c7 Guido Trotter
#   If you need more than one node, or more than one instance, acquire them at
682 7ee7c0c7 Guido Trotter
#   the same time.
683 7ee7c0c7 Guido Trotter
LEVEL_CLUSTER = 0
684 04e1bfaf Guido Trotter
LEVEL_INSTANCE = 1
685 04e1bfaf Guido Trotter
LEVEL_NODE = 2
686 7ee7c0c7 Guido Trotter
687 7ee7c0c7 Guido Trotter
LEVELS = [LEVEL_CLUSTER,
688 04e1bfaf Guido Trotter
          LEVEL_INSTANCE,
689 04e1bfaf Guido Trotter
          LEVEL_NODE]
690 7ee7c0c7 Guido Trotter
691 7ee7c0c7 Guido Trotter
# Lock levels which are modifiable
692 7ee7c0c7 Guido Trotter
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
693 7ee7c0c7 Guido Trotter
694 08a6c581 Guido Trotter
# Constant for the big ganeti lock
695 7ee7c0c7 Guido Trotter
BGL = 'BGL'
696 7ee7c0c7 Guido Trotter
697 7ee7c0c7 Guido Trotter
698 7ee7c0c7 Guido Trotter
class GanetiLockManager:
699 7ee7c0c7 Guido Trotter
  """The Ganeti Locking Library
700 7ee7c0c7 Guido Trotter

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

706 7ee7c0c7 Guido Trotter
  """
707 7ee7c0c7 Guido Trotter
  _instance = None
708 7ee7c0c7 Guido Trotter
709 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
710 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
711 7ee7c0c7 Guido Trotter

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

715 7ee7c0c7 Guido Trotter
    Args:
716 7ee7c0c7 Guido Trotter
      nodes: list of node names
717 7ee7c0c7 Guido Trotter
      instances: list of instance names
718 7ee7c0c7 Guido Trotter

719 7ee7c0c7 Guido Trotter
    """
720 7ee7c0c7 Guido Trotter
    assert self.__class__._instance is None, "double GanetiLockManager instance"
721 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
722 7ee7c0c7 Guido Trotter
723 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
724 7ee7c0c7 Guido Trotter
    # locking order.
725 7ee7c0c7 Guido Trotter
    self.__keyring = {
726 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
727 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
728 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
729 7ee7c0c7 Guido Trotter
    }
730 7ee7c0c7 Guido Trotter
731 7ee7c0c7 Guido Trotter
  def _names(self, level):
732 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
733 7ee7c0c7 Guido Trotter
    Used for debugging/testing purposes.
734 7ee7c0c7 Guido Trotter

735 7ee7c0c7 Guido Trotter
    Args:
736 7ee7c0c7 Guido Trotter
      level: the level whose list of locks to get
737 7ee7c0c7 Guido Trotter

738 7ee7c0c7 Guido Trotter
    """
739 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
740 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
741 7ee7c0c7 Guido Trotter
742 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
743 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
744 7ee7c0c7 Guido Trotter

745 7ee7c0c7 Guido Trotter
    """
746 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
747 7ee7c0c7 Guido Trotter
748 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
749 d4f4b3e7 Guido Trotter
750 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
751 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
752 7ee7c0c7 Guido Trotter

753 7ee7c0c7 Guido Trotter
    """
754 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
755 7ee7c0c7 Guido Trotter
756 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
757 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
758 7ee7c0c7 Guido Trotter

759 7ee7c0c7 Guido Trotter
    """
760 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
761 7ee7c0c7 Guido Trotter
    # the test cases.
762 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
763 7ee7c0c7 Guido Trotter
764 7ee7c0c7 Guido Trotter
  def _BGL_owned(self):
765 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
766 7ee7c0c7 Guido Trotter

767 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
768 7ee7c0c7 Guido Trotter

769 7ee7c0c7 Guido Trotter
    """
770 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
771 7ee7c0c7 Guido Trotter
772 7ee7c0c7 Guido Trotter
  def _contains_BGL(self, level, names):
773 7ee7c0c7 Guido Trotter
    """Check if acting on the given level and set of names will change the
774 7ee7c0c7 Guido Trotter
    status of the Big Ganeti Lock.
775 7ee7c0c7 Guido Trotter

776 7ee7c0c7 Guido Trotter
    """
777 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
778 7ee7c0c7 Guido Trotter
779 7ee7c0c7 Guido Trotter
  def acquire(self, level, names, blocking=1, shared=0):
780 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
781 7ee7c0c7 Guido Trotter

782 7ee7c0c7 Guido Trotter
    Args:
783 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be acquired.
784 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS.
785 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be acquired.
786 7ee7c0c7 Guido Trotter
             (special lock names, or instance/node names)
787 7ee7c0c7 Guido Trotter
      shared: whether to acquire in shared mode. By default an exclusive lock
788 7ee7c0c7 Guido Trotter
              will be acquired.
789 4e07ec8c Guido Trotter
      blocking: whether to block while trying to acquire or to operate in
790 4e07ec8c Guido Trotter
                try-lock mode.  this locking mode is not supported yet.
791 7ee7c0c7 Guido Trotter

792 7ee7c0c7 Guido Trotter
    """
793 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
794 7ee7c0c7 Guido Trotter
795 7ee7c0c7 Guido Trotter
    # Check that we are either acquiring the Big Ganeti Lock or we already own
796 7ee7c0c7 Guido Trotter
    # it. Some "legacy" opcodes need to be sure they are run non-concurrently
797 7ee7c0c7 Guido Trotter
    # so even if we've migrated we need to at least share the BGL to be
798 7ee7c0c7 Guido Trotter
    # compatible with them. Of course if we own the BGL exclusively there's no
799 7ee7c0c7 Guido Trotter
    # point in acquiring any other lock, unless perhaps we are half way through
800 7ee7c0c7 Guido Trotter
    # the migration of the current opcode.
801 7ee7c0c7 Guido Trotter
    assert (self._contains_BGL(level, names) or self._BGL_owned()), (
802 7ee7c0c7 Guido Trotter
            "You must own the Big Ganeti Lock before acquiring any other")
803 7ee7c0c7 Guido Trotter
804 7ee7c0c7 Guido Trotter
    # Check we don't own locks at the same or upper levels.
805 21a6c826 Guido Trotter
    assert not self._upper_owned(level), ("Cannot acquire locks at a level"
806 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
807 7ee7c0c7 Guido Trotter
808 7ee7c0c7 Guido Trotter
    # Acquire the locks in the set.
809 7ee7c0c7 Guido Trotter
    return self.__keyring[level].acquire(names, shared=shared,
810 7ee7c0c7 Guido Trotter
                                         blocking=blocking)
811 7ee7c0c7 Guido Trotter
812 7ee7c0c7 Guido Trotter
  def release(self, level, names=None):
813 7ee7c0c7 Guido Trotter
    """Release a set of resource locks, at the same level.
814 7ee7c0c7 Guido Trotter

815 7ee7c0c7 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
816 7ee7c0c7 Guido Trotter
    before releasing them.
817 7ee7c0c7 Guido Trotter

818 7ee7c0c7 Guido Trotter
    Args:
819 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be released.
820 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS.
821 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be released.
822 7ee7c0c7 Guido Trotter
             (defaults to all the locks acquired at that level).
823 7ee7c0c7 Guido Trotter

824 7ee7c0c7 Guido Trotter
    """
825 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
826 7ee7c0c7 Guido Trotter
    assert (not self._contains_BGL(level, names) or
827 7ee7c0c7 Guido Trotter
            not self._upper_owned(LEVEL_CLUSTER)), (
828 7ee7c0c7 Guido Trotter
            "Cannot release the Big Ganeti Lock while holding something"
829 7ee7c0c7 Guido Trotter
            " at upper levels")
830 7ee7c0c7 Guido Trotter
831 7ee7c0c7 Guido Trotter
    # Release will complain if we don't own the locks already
832 7ee7c0c7 Guido Trotter
    return self.__keyring[level].release(names)
833 7ee7c0c7 Guido Trotter
834 7ee7c0c7 Guido Trotter
  def add(self, level, names, acquired=0, shared=0):
835 7ee7c0c7 Guido Trotter
    """Add locks at the specified level.
836 7ee7c0c7 Guido Trotter

837 7ee7c0c7 Guido Trotter
    Args:
838 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be added.
839 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS_MOD.
840 7ee7c0c7 Guido Trotter
      names: names of the locks to acquire
841 7ee7c0c7 Guido Trotter
      acquired: whether to acquire the newly added locks
842 7ee7c0c7 Guido Trotter
      shared: whether the acquisition will be shared
843 7ee7c0c7 Guido Trotter
    """
844 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
845 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
846 7ee7c0c7 Guido Trotter
           " operations")
847 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
848 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
849 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
850 7ee7c0c7 Guido Trotter
851 7ee7c0c7 Guido Trotter
  def remove(self, level, names, blocking=1):
852 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
853 7ee7c0c7 Guido Trotter

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

857 7ee7c0c7 Guido Trotter
    Args:
858 7ee7c0c7 Guido Trotter
      level: the level at which the locks shall be removed.
859 7ee7c0c7 Guido Trotter
             It must be a memmber of LEVELS_MOD.
860 7ee7c0c7 Guido Trotter
      names: the names of the locks which shall be removed.
861 7ee7c0c7 Guido Trotter
             (special lock names, or instance/node names)
862 7ee7c0c7 Guido Trotter
      blocking: whether to block while trying to operate in try-lock mode.
863 7ee7c0c7 Guido Trotter
                this locking mode is not supported yet.
864 7ee7c0c7 Guido Trotter

865 7ee7c0c7 Guido Trotter
    """
866 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
867 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
868 7ee7c0c7 Guido Trotter
           " operations")
869 7ee7c0c7 Guido Trotter
    # Check we either own the level or don't own anything from here up.
870 7ee7c0c7 Guido Trotter
    # LockSet.remove() will check the case in which we don't own all the needed
871 7ee7c0c7 Guido Trotter
    # resources, or we have a shared ownership.
872 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
873 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
874 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
875 cdb08f44 Michael Hanselmann
    return self.__keyring[level].remove(names, blocking=blocking)