Revision 42a999d1

b/lib/locking.py
29 29
from ganeti import utils
30 30

  
31 31

  
32
def ssynchronized(lock, shared=0):
33
  """Shared Synchronization decorator.
34

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

  
39
  """
40
  def wrap(fn):
41
    def sync_function(*args, **kwargs):
42
      lock.acquire(shared=shared)
43
      try:
44
        return fn(*args, **kwargs)
45
      finally:
46
        lock.release()
47
    return sync_function
48
  return wrap
49

  
50

  
32 51
class SharedLock:
33 52
  """Implements a shared lock.
34 53

  
b/test/ganeti.locking_unittest.py
32 32
from threading import Thread
33 33

  
34 34

  
35
# This is used to test the ssynchronize decorator.
36
# Since it's passed as input to a decorator it must be declared as a global.
37
_decoratorlock = locking.SharedLock()
38

  
39

  
35 40
class TestSharedLock(unittest.TestCase):
36 41
  """SharedLock tests"""
37 42

  
......
230 235
    self.assertEqual(self.done.get(True, 1), 'ERR')
231 236

  
232 237

  
238
class TestSSynchronizedDecorator(unittest.TestCase):
239
  """Shared Lock Synchronized decorator test"""
240

  
241
  def setUp(self):
242
    # helper threads use the 'done' queue to tell the master they finished.
243
    self.done = Queue.Queue(0)
244

  
245
  @locking.ssynchronized(_decoratorlock)
246
  def _doItExclusive(self):
247
    self.assert_(_decoratorlock._is_owned())
248
    self.done.put('EXC')
249

  
250
  @locking.ssynchronized(_decoratorlock, shared=1)
251
  def _doItSharer(self):
252
    self.assert_(_decoratorlock._is_owned(shared=1))
253
    self.done.put('SHR')
254

  
255
  def testDecoratedFunctions(self):
256
    self._doItExclusive()
257
    self.assert_(not _decoratorlock._is_owned())
258
    self._doItSharer()
259
    self.assert_(not _decoratorlock._is_owned())
260

  
261
  def testSharersCanCoexist(self):
262
    _decoratorlock.acquire(shared=1)
263
    Thread(target=self._doItSharer).start()
264
    self.assert_(self.done.get(True, 1))
265
    _decoratorlock.release()
266

  
267
  def testExclusiveBlocksExclusive(self):
268
    _decoratorlock.acquire()
269
    Thread(target=self._doItExclusive).start()
270
    # give it a bit of time to check that it's not actually doing anything
271
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
272
    _decoratorlock.release()
273
    self.assert_(self.done.get(True, 1))
274

  
275
  def testExclusiveBlocksSharer(self):
276
    _decoratorlock.acquire()
277
    Thread(target=self._doItSharer).start()
278
    time.sleep(0.05)
279
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
280
    _decoratorlock.release()
281
    self.assert_(self.done.get(True, 1))
282

  
283
  def testSharerBlocksExclusive(self):
284
    _decoratorlock.acquire(shared=1)
285
    Thread(target=self._doItExclusive).start()
286
    time.sleep(0.05)
287
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
288
    _decoratorlock.release()
289
    self.assert_(self.done.get(True, 1))
290

  
291

  
233 292
class TestLockSet(unittest.TestCase):
234 293
  """LockSet tests"""
235 294

  

Also available in: Unified diff