Revision b2dabfd6

b/lib/locking.py
297 297
    """Is the current thread a current level owner?"""
298 298
    return threading.currentThread() in self.__owners
299 299

  
300
  def _add_owned(self, name):
300
  def _add_owned(self, name=None):
301 301
    """Note the current thread owns the given lock"""
302
    if self._is_owned():
303
      self.__owners[threading.currentThread()].add(name)
302
    if name is None:
303
      if not self._is_owned():
304
        self.__owners[threading.currentThread()] = set()
304 305
    else:
305
       self.__owners[threading.currentThread()] = set([name])
306
      if self._is_owned():
307
        self.__owners[threading.currentThread()].add(name)
308
      else:
309
        self.__owners[threading.currentThread()] = set([name])
310

  
306 311

  
307
  def _del_owned(self, name):
312
  def _del_owned(self, name=None):
308 313
    """Note the current thread owns the given lock"""
309
    self.__owners[threading.currentThread()].remove(name)
310 314

  
311
    if not self.__owners[threading.currentThread()]:
315
    if name is not None:
316
      self.__owners[threading.currentThread()].remove(name)
317

  
318
    # Only remove the key if we don't hold the set-lock as well
319
    if (not self.__lock._is_owned() and
320
        not self.__owners[threading.currentThread()]):
312 321
      del self.__owners[threading.currentThread()]
313 322

  
314 323
  def _list_owned(self):
......
378 387
      # so we'll get the list lock exclusively as well in order to be able to
379 388
      # do add() on the set while owning it.
380 389
      self.__lock.acquire(shared=shared)
390
      try:
391
        # note we own the set-lock
392
        self._add_owned()
393
        names = self.__names()
394
      except:
395
        # We shouldn't have problems adding the lock to the owners list, but
396
        # if we did we'll try to release this lock and re-raise exception.
397
        # Of course something is going to be really wrong, after this.
398
        self.__lock.release()
399
        raise
381 400

  
382 401
    try:
383 402
      # Support passing in a single resource to acquire rather than many
384 403
      if isinstance(names, basestring):
385 404
        names = [names]
386 405
      else:
387
        if names is None:
388
          names = self.__names()
389 406
        names.sort()
390 407

  
391 408
      acquire_list = []
......
414 431
        try:
415 432
          lock.acquire(shared=shared) # raises LockError if the lock is deleted
416 433
          # now the lock cannot be deleted, we have it!
417
          self._add_owned(lname)
434
          self._add_owned(name=lname)
418 435
          acquired.add(lname)
419 436
        except (errors.LockError):
420 437
          if self.__lock._is_owned():
......
425 442
            name_fail = lname
426 443
            for lname in self._list_owned():
427 444
              self.__lockdict[lname].release()
428
              self._del_owned(lname)
445
              self._del_owned(name=lname)
429 446
            raise errors.LockError('non-existing lock in set (%s)' % name_fail)
430 447
        except:
431 448
          # We shouldn't have problems adding the lock to the owners list, but
......
472 489
    # After this 'add' can work again
473 490
    if self.__lock._is_owned():
474 491
      self.__lock.release()
492
      self._del_owned()
475 493

  
476 494
    for lockname in names:
477 495
      # If we are sure the lock doesn't leave __lockdict without being
478 496
      # exclusively held we can do this...
479 497
      self.__lockdict[lockname].release()
480
      self._del_owned(lockname)
498
      self._del_owned(name=lockname)
481 499

  
482 500
  def add(self, names, acquired=0, shared=0):
483 501
    """Add a new set of elements to the set
......
518 536
          lock.acquire(shared=shared)
519 537
          # now the lock cannot be deleted, we have it!
520 538
          try:
521
            self._add_owned(lockname)
539
            self._add_owned(name=lockname)
522 540
          except:
523 541
            # We shouldn't have problems adding the lock to the owners list,
524 542
            # but if we did we'll try to release this lock and re-raise
......
594 612
        del self.__lockdict[lname]
595 613
        # And let's remove it from our private list if we owned it.
596 614
        if self._is_owned():
597
          self._del_owned(lname)
615
          self._del_owned(name=lname)
598 616

  
599 617
    return removed
600 618

  
b/test/ganeti.locking_unittest.py
470 470
    self.assertEqual(self.done.get(True, 1), 'DONE')
471 471
    self.assertEqual(self.done.get(True, 1), 'DONE')
472 472

  
473
  def testEmptyLockSet(self):
474
    # get the set-lock
475
    self.assertEqual(self.ls.acquire(None), set(['one', 'two', 'three']))
476
    # now empty it...
477
    self.ls.remove(['one', 'two', 'three'])
478
    # and adds/locks by another thread still wait
479
    Thread(target=self._doAddSet, args=(['nine'])).start()
480
    Thread(target=self._doLockSet, args=(None, 1)).start()
481
    Thread(target=self._doLockSet, args=(None, 0)).start()
482
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
483
    self.ls.release()
484
    self.assertEqual(self.done.get(True, 1), 'DONE')
485
    self.assertEqual(self.done.get(True, 1), 'DONE')
486
    self.assertEqual(self.done.get(True, 1), 'DONE')
487
    # empty it again...
488
    self.assertEqual(self.ls.remove(['nine']), ['nine'])
489
    # now share it...
490
    self.assertEqual(self.ls.acquire(None, shared=1), set())
491
    # other sharers can go, adds still wait
492
    Thread(target=self._doLockSet, args=(None, 1)).start()
493
    self.assertEqual(self.done.get(True, 1), 'DONE')
494
    Thread(target=self._doAddSet, args=(['nine'])).start()
495
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
496
    self.ls.release()
497
    self.assertEqual(self.done.get(True, 1), 'DONE')
498

  
473 499

  
474 500
class TestGanetiLockManager(unittest.TestCase):
475 501

  

Also available in: Unified diff