+ if names is not None:
+ assert timeout is None or not opportunistic, \
+ ("Opportunistic acquisitions can only use a timeout if no"
+ " names are given; see docstring for details")
+
+ # Support passing in a single resource to acquire rather than many
+ if isinstance(names, basestring):
+ names = [names]
+
+ (mode, _, timeout_fn) = \
+ _GetLsAcquireModeAndTimeouts(False, timeout, opportunistic)
+
+ return self.__acquire_inner(names, mode, shared, priority,
+ timeout_fn, test_notify)
+
+ else:
+ (mode, ls_timeout_fn, timeout_fn) = \
+ _GetLsAcquireModeAndTimeouts(True, timeout, opportunistic)
+
+ # If no names are given acquire the whole set by not letting new names
+ # being added before we release, and getting the current list of names.
+ # Some of them may then be deleted later, but we'll cope with this.
+ #
+ # We'd like to acquire this lock in a shared way, as it's nice if
+ # everybody else can use the instances at the same time. If we are
+ # acquiring them exclusively though they won't be able to do this
+ # anyway, though, so we'll get the list lock exclusively as well in
+ # order to be able to do add() on the set while owning it.
+ if not self.__lock.acquire(shared=shared, priority=priority,
+ timeout=ls_timeout_fn()):
+ raise _AcquireTimeout()
+
+ try:
+ # note we own the set-lock
+ self._add_owned()
+
+ return self.__acquire_inner(self.__names(), mode, shared,
+ priority, timeout_fn, test_notify)
+ except:
+ # We shouldn't have problems adding the lock to the owners list, but
+ # if we did we'll try to release this lock and re-raise exception.
+ # Of course something is going to be really wrong, after this.
+ self.__lock.release()
+ self._del_owned()
+ raise
+
+ except _AcquireTimeout:
+ return None
+
+ def __acquire_inner(self, names, mode, shared, priority,
+ timeout_fn, test_notify):
+ """Inner logic for acquiring a number of locks.
+
+ Acquisition modes:
+
+ - C{_LS_ACQUIRE_ALL}: C{names} contains names of all locks in set, but
+ deleted locks can be ignored as the whole set is being acquired with
+ its internal lock held
+ - C{_LS_ACQUIRE_EXACT}: The names listed in C{names} must be acquired;
+ timeouts and deleted locks are fatal
+ - C{_LS_ACQUIRE_OPPORTUNISTIC}: C{names} lists names of locks (potentially
+ all within the set) which should be acquired opportunistically, that is
+ failures are ignored
+
+ @param names: Names of the locks to be acquired
+ @param mode: Lock acquisition mode (one of L{_LS_ACQUIRE_MODES})
+ @param shared: Whether to acquire in shared mode
+ @param timeout_fn: Function returning remaining timeout (C{None} for
+ opportunistic acquisitions)
+ @param priority: Priority for acquiring locks
+ @param test_notify: Special callback function for unittesting
+
+ """
+ assert mode in _LS_ACQUIRE_MODES
+
+ acquire_list = []
+
+ # First we look the locks up on __lockdict. We have no way of being sure
+ # they will still be there after, but this makes it a lot faster should
+ # just one of them be the already wrong. Using a sorted sequence to prevent
+ # deadlocks.
+ for lname in sorted(frozenset(names)):
+ try:
+ lock = self.__lockdict[lname] # raises KeyError if lock is not there
+ except KeyError:
+ # We are acquiring the whole set, it doesn't matter if this particular
+ # element is not there anymore. If, however, only certain names should
+ # be acquired, not finding a lock is an error.
+ if mode == _LS_ACQUIRE_EXACT:
+ raise errors.LockError("Lock '%s' not found in set '%s' (it may have"
+ " been removed)" % (lname, self.name))