Statistics
| Branch: | Tag: | Revision:

root / lib / locking.py @ 5af3da74

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 c41eea6e Iustin Pop
    @param shared:
108 c41eea6e Iustin Pop
        - < 0: check for any type of ownership (default)
109 c41eea6e Iustin Pop
        - 0: check for exclusive ownership
110 c41eea6e Iustin Pop
        - > 0: check for shared ownership
111 162c1c1f Guido Trotter

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

125 c41eea6e Iustin Pop
    @param c: the condition to wait on
126 a95fd5d7 Guido Trotter

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

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

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

159 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
160 c41eea6e Iustin Pop
        exclusive lock will be acquired
161 c41eea6e Iustin Pop
    @param blocking: whether to block while trying to acquire or to
162 c41eea6e Iustin Pop
        operate in try-lock mode (this locking mode is not supported yet)
163 162c1c1f Guido Trotter

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

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

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

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

270 c41eea6e Iustin Pop
    @param blocking: whether to block while trying to acquire or to
271 c41eea6e Iustin Pop
        operate in try-lock mode.  this locking mode is not supported
272 c41eea6e Iustin Pop
        yet unless you are already holding exclusively the lock.
273 a95fd5d7 Guido Trotter

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

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

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

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

318 c41eea6e Iustin Pop
    @param members: initial members of the set
319 aaae9bc0 Guido Trotter

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

378 aaae9bc0 Guido Trotter
    Only call this function while holding __lock and don't iterate on the
379 aaae9bc0 Guido Trotter
    result after releasing the lock.
380 aaae9bc0 Guido Trotter

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

387 aaae9bc0 Guido Trotter
    Used only for debugging purposes.
388 cdb08f44 Michael Hanselmann

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

406 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
407 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
408 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default an
409 c41eea6e Iustin Pop
        exclusive lock will be acquired
410 c41eea6e Iustin Pop
    @param blocking: whether to block while trying to acquire or to
411 c41eea6e Iustin Pop
        operate in try-lock mode (this locking mode is not supported yet)
412 aaae9bc0 Guido Trotter

413 c41eea6e Iustin Pop
    @return: True when all the locks are successfully acquired
414 aaae9bc0 Guido Trotter

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

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

514 aaae9bc0 Guido Trotter
    You must have acquired the locks, either in shared or in exclusive mode,
515 aaae9bc0 Guido Trotter
    before releasing them.
516 aaae9bc0 Guido Trotter

517 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
518 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level).
519 aaae9bc0 Guido Trotter

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

550 c41eea6e Iustin Pop
    @param names: names of the new elements to add
551 c41eea6e Iustin Pop
    @param acquired: pre-acquire the new resource?
552 c41eea6e Iustin Pop
    @param shared: is the pre-acquisition shared?
553 aaae9bc0 Guido Trotter

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

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

611 c41eea6e Iustin Pop
    @param names: names of the resource to remove.
612 c41eea6e Iustin Pop
    @param blocking: whether to block while trying to acquire or to
613 c41eea6e Iustin Pop
        operate in try-lock mode (this locking mode is not supported
614 c41eea6e Iustin Pop
        yet unless you are already holding exclusively the locks)
615 aaae9bc0 Guido Trotter

616 c41eea6e Iustin Pop
    @return:: a list of locks which we removed; the list is always
617 c41eea6e Iustin Pop
        equal to the names list if we were holding all the locks
618 c41eea6e Iustin Pop
        exclusively
619 aaae9bc0 Guido Trotter

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

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

697 7ee7c0c7 Guido Trotter
  """
698 7ee7c0c7 Guido Trotter
  _instance = None
699 7ee7c0c7 Guido Trotter
700 7ee7c0c7 Guido Trotter
  def __init__(self, nodes=None, instances=None):
701 7ee7c0c7 Guido Trotter
    """Constructs a new GanetiLockManager object.
702 7ee7c0c7 Guido Trotter

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

706 c41eea6e Iustin Pop
    @param nodes: list of node names
707 c41eea6e Iustin Pop
    @param instances: list of instance names
708 7ee7c0c7 Guido Trotter

709 7ee7c0c7 Guido Trotter
    """
710 c41eea6e Iustin Pop
    assert self.__class__._instance is None, \
711 c41eea6e Iustin Pop
           "double GanetiLockManager instance"
712 c41eea6e Iustin Pop
713 7ee7c0c7 Guido Trotter
    self.__class__._instance = self
714 7ee7c0c7 Guido Trotter
715 7ee7c0c7 Guido Trotter
    # The keyring contains all the locks, at their level and in the correct
716 7ee7c0c7 Guido Trotter
    # locking order.
717 7ee7c0c7 Guido Trotter
    self.__keyring = {
718 7ee7c0c7 Guido Trotter
      LEVEL_CLUSTER: LockSet([BGL]),
719 7ee7c0c7 Guido Trotter
      LEVEL_NODE: LockSet(nodes),
720 7ee7c0c7 Guido Trotter
      LEVEL_INSTANCE: LockSet(instances),
721 7ee7c0c7 Guido Trotter
    }
722 7ee7c0c7 Guido Trotter
723 7ee7c0c7 Guido Trotter
  def _names(self, level):
724 7ee7c0c7 Guido Trotter
    """List the lock names at the given level.
725 7ee7c0c7 Guido Trotter

726 c41eea6e Iustin Pop
    This can be used for debugging/testing purposes.
727 c41eea6e Iustin Pop

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

730 7ee7c0c7 Guido Trotter
    """
731 7ee7c0c7 Guido Trotter
    assert level in LEVELS, "Invalid locking level %s" % level
732 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._names()
733 7ee7c0c7 Guido Trotter
734 7ee7c0c7 Guido Trotter
  def _is_owned(self, level):
735 7ee7c0c7 Guido Trotter
    """Check whether we are owning locks at the given level
736 7ee7c0c7 Guido Trotter

737 7ee7c0c7 Guido Trotter
    """
738 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._is_owned()
739 7ee7c0c7 Guido Trotter
740 d4f4b3e7 Guido Trotter
  is_owned = _is_owned
741 d4f4b3e7 Guido Trotter
742 7ee7c0c7 Guido Trotter
  def _list_owned(self, level):
743 7ee7c0c7 Guido Trotter
    """Get the set of owned locks at the given level
744 7ee7c0c7 Guido Trotter

745 7ee7c0c7 Guido Trotter
    """
746 7ee7c0c7 Guido Trotter
    return self.__keyring[level]._list_owned()
747 7ee7c0c7 Guido Trotter
748 7ee7c0c7 Guido Trotter
  def _upper_owned(self, level):
749 7ee7c0c7 Guido Trotter
    """Check that we don't own any lock at a level greater than the given one.
750 7ee7c0c7 Guido Trotter

751 7ee7c0c7 Guido Trotter
    """
752 7ee7c0c7 Guido Trotter
    # This way of checking only works if LEVELS[i] = i, which we check for in
753 7ee7c0c7 Guido Trotter
    # the test cases.
754 7ee7c0c7 Guido Trotter
    return utils.any((self._is_owned(l) for l in LEVELS[level + 1:]))
755 7ee7c0c7 Guido Trotter
756 7ee7c0c7 Guido Trotter
  def _BGL_owned(self):
757 7ee7c0c7 Guido Trotter
    """Check if the current thread owns the BGL.
758 7ee7c0c7 Guido Trotter

759 7ee7c0c7 Guido Trotter
    Both an exclusive or a shared acquisition work.
760 7ee7c0c7 Guido Trotter

761 7ee7c0c7 Guido Trotter
    """
762 7ee7c0c7 Guido Trotter
    return BGL in self.__keyring[LEVEL_CLUSTER]._list_owned()
763 7ee7c0c7 Guido Trotter
764 7ee7c0c7 Guido Trotter
  def _contains_BGL(self, level, names):
765 c41eea6e Iustin Pop
    """Check if the level contains the BGL.
766 c41eea6e Iustin Pop

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

770 7ee7c0c7 Guido Trotter
    """
771 7ee7c0c7 Guido Trotter
    return level == LEVEL_CLUSTER and (names is None or BGL in names)
772 7ee7c0c7 Guido Trotter
773 7ee7c0c7 Guido Trotter
  def acquire(self, level, names, blocking=1, shared=0):
774 7ee7c0c7 Guido Trotter
    """Acquire a set of resource locks, at the same level.
775 7ee7c0c7 Guido Trotter

776 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be acquired;
777 c41eea6e Iustin Pop
        it must be a memmber of LEVELS.
778 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be acquired
779 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
780 c41eea6e Iustin Pop
    @param shared: whether to acquire in shared mode; by default
781 c41eea6e Iustin Pop
        an exclusive lock will be acquired
782 c41eea6e Iustin Pop
    @param blocking: whether to block while trying to acquire or to
783 c41eea6e Iustin Pop
        operate in try-lock mode (this locking mode is not supported yet)
784 7ee7c0c7 Guido Trotter

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

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

811 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be released;
812 c41eea6e Iustin Pop
        it must be a memmber of LEVELS
813 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be released
814 c41eea6e Iustin Pop
        (defaults to all the locks acquired at that level)
815 7ee7c0c7 Guido Trotter

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

829 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be added;
830 c41eea6e Iustin Pop
        it must be a memmber of LEVELS_MOD.
831 c41eea6e Iustin Pop
    @param names: names of the locks to acquire
832 c41eea6e Iustin Pop
    @param acquired: whether to acquire the newly added locks
833 c41eea6e Iustin Pop
    @param shared: whether the acquisition will be shared
834 c41eea6e Iustin Pop

835 7ee7c0c7 Guido Trotter
    """
836 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
837 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
838 7ee7c0c7 Guido Trotter
           " operations")
839 7ee7c0c7 Guido Trotter
    assert not self._upper_owned(level), ("Cannot add locks at a level"
840 7ee7c0c7 Guido Trotter
           " while owning some at a greater one")
841 7ee7c0c7 Guido Trotter
    return self.__keyring[level].add(names, acquired=acquired, shared=shared)
842 7ee7c0c7 Guido Trotter
843 7ee7c0c7 Guido Trotter
  def remove(self, level, names, blocking=1):
844 7ee7c0c7 Guido Trotter
    """Remove locks from the specified level.
845 7ee7c0c7 Guido Trotter

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

849 c41eea6e Iustin Pop
    @param level: the level at which the locks shall be removed;
850 c41eea6e Iustin Pop
        it must be a member of LEVELS_MOD
851 c41eea6e Iustin Pop
    @param names: the names of the locks which shall be removed
852 c41eea6e Iustin Pop
        (special lock names, or instance/node names)
853 c41eea6e Iustin Pop
    @param blocking: whether to block while trying to operate in
854 c41eea6e Iustin Pop
        try-lock mode (this locking mode is not supported yet)
855 7ee7c0c7 Guido Trotter

856 7ee7c0c7 Guido Trotter
    """
857 7ee7c0c7 Guido Trotter
    assert level in LEVELS_MOD, "Invalid or immutable level %s" % level
858 7ee7c0c7 Guido Trotter
    assert self._BGL_owned(), ("You must own the BGL before performing other"
859 7ee7c0c7 Guido Trotter
           " operations")
860 f12eadb3 Iustin Pop
    # Check we either own the level or don't own anything from here
861 f12eadb3 Iustin Pop
    # up. LockSet.remove() will check the case in which we don't own
862 f12eadb3 Iustin Pop
    # all the needed resources, or we have a shared ownership.
863 7ee7c0c7 Guido Trotter
    assert self._is_owned(level) or not self._upper_owned(level), (
864 7ee7c0c7 Guido Trotter
           "Cannot remove locks at a level while not owning it or"
865 7ee7c0c7 Guido Trotter
           " owning some at a greater one")
866 cdb08f44 Michael Hanselmann
    return self.__keyring[level].remove(names, blocking=blocking)