Revision 3b7ed473 lib/locking.py

b/lib/locking.py
372 372
    # Check we don't already own locks at this level
373 373
    assert not self._is_owned(), "Cannot acquire locks in the same set twice"
374 374

  
375
    if names is None:
376
      # If no names are given acquire the whole set by not letting new names
377
      # being added before we release, and getting the current list of names.
378
      # Some of them may then be deleted later, but we'll cope with this.
379
      #
380
      # We'd like to acquire this lock in a shared way, as it's nice if
381
      # everybody else can use the instances at the same time. If are acquiring
382
      # them exclusively though they won't be able to do this anyway, though,
383
      # so we'll get the list lock exclusively as well in order to be able to
384
      # do add() on the set while owning it.
385
      self.__lock.acquire(shared=shared)
386

  
375 387
    try:
376 388
      # Support passing in a single resource to acquire rather than many
377 389
      if isinstance(names, basestring):
378 390
        names = [names]
379 391
      else:
392
        if names is None:
393
          names = self.__names()
380 394
        names.sort()
381 395

  
382 396
      acquire_list = []
......
388 402
          lock = self.__lockdict[lname] # raises KeyError if the lock is not there
389 403
          acquire_list.append((lname, lock))
390 404
        except (KeyError):
391
          raise errors.LockError('non-existing lock in set (%s)' % lname)
405
          if self.__lock._is_owned():
406
            # We are acquiring all the set, it doesn't matter if this particular
407
            # element is not there anymore.
408
            continue
409
          else:
410
            raise errors.LockError('non-existing lock in set (%s)' % lname)
392 411

  
393 412
      # This will hold the locknames we effectively acquired.
394 413
      acquired = set()
......
411 430
            raise
412 431

  
413 432
        except (errors.LockError):
414
          name_fail = lname
415
          for lname in self._list_owned():
416
            self.__lockdict[lname].release()
417
            self._del_owned(lname)
418
          raise errors.LockError('non-existing lock in set (%s)' % name_fail)
433
          if self.__lock._is_owned():
434
            # We are acquiring all the set, it doesn't matter if this particular
435
            # element is not there anymore.
436
            continue
437
          else:
438
            name_fail = lname
439
            for lname in self._list_owned():
440
              self.__lockdict[lname].release()
441
              self._del_owned(lname)
442
            raise errors.LockError('non-existing lock in set (%s)' % name_fail)
419 443

  
420 444
    except:
445
      # If something went wrong and we had the set-lock let's release it...
446
      if self.__lock._is_owned():
447
        self.__lock.release()
421 448
      raise
422 449

  
423 450
    return acquired
......
448 475
               "release() on unheld resources %s" %
449 476
               names.difference(self._list_owned()))
450 477

  
478
    # First of all let's release the "all elements" lock, if set.
479
    # After this 'add' can work again
480
    if self.__lock._is_owned():
481
      self.__lock.release()
482

  
451 483
    for lockname in names:
452 484
      # If we are sure the lock doesn't leave __lockdict without being
453 485
      # exclusively held we can do this...
......
463 495
      shared: is the pre-acquisition shared?
464 496

  
465 497
    """
498

  
499
    assert not self.__lock._is_owned(shared=1), (
500
           "Cannot add new elements while sharing the set-lock")
501

  
466 502
    # Support passing in a single resource to add rather than many
467 503
    if isinstance(names, basestring):
468 504
      names = [names]
469 505

  
470
    # Acquire the internal lock in an exclusive way, so there cannot be a
471
    # conflicting add()
472
    self.__lock.acquire()
506
    # If we don't already own the set-level lock acquire it in an exclusive way
507
    # we'll get it and note we need to release it later.
508
    release_lock = False
509
    if not self.__lock._is_owned():
510
      release_lock = True
511
      self.__lock.acquire()
512

  
473 513
    try:
474 514
      invalid_names = set(self.__names()).intersection(names)
475 515
      if invalid_names:
......
499 539
        self.__lockdict[lockname] = lock
500 540

  
501 541
    finally:
502
      self.__lock.release()
542
      # Only release __lock if we were not holding it previously.
543
      if release_lock:
544
        self.__lock.release()
503 545

  
504 546
    return True
505 547

  

Also available in: Unified diff