Revision 76e2f08a lib/locking.py
b/lib/locking.py | ||
---|---|---|
782 | 782 |
start = time.time() |
783 | 783 |
calc_remaining_timeout = lambda: (start + timeout) - time.time() |
784 | 784 |
|
785 |
want_all = names is None |
|
786 |
|
|
787 |
if want_all: |
|
788 |
# If no names are given acquire the whole set by not letting new names |
|
789 |
# being added before we release, and getting the current list of names. |
|
790 |
# Some of them may then be deleted later, but we'll cope with this. |
|
791 |
# |
|
792 |
# We'd like to acquire this lock in a shared way, as it's nice if |
|
793 |
# everybody else can use the instances at the same time. If are acquiring |
|
794 |
# them exclusively though they won't be able to do this anyway, though, |
|
795 |
# so we'll get the list lock exclusively as well in order to be able to |
|
796 |
# do add() on the set while owning it. |
|
797 |
self.__lock.acquire(shared=shared, timeout=remaining_timeout) |
|
798 |
try: |
|
799 |
# note we own the set-lock |
|
800 |
self._add_owned() |
|
801 |
names = self.__names() |
|
802 |
except: |
|
803 |
# We shouldn't have problems adding the lock to the owners list, but |
|
804 |
# if we did we'll try to release this lock and re-raise exception. |
|
805 |
# Of course something is going to be really wrong, after this. |
|
806 |
self.__lock.release() |
|
807 |
raise |
|
808 |
|
|
809 |
# Re-calculate timeout |
|
810 |
remaining_timeout = calc_remaining_timeout() |
|
811 |
|
|
812 | 785 |
try: |
813 |
try:
|
|
786 |
if names is not None:
|
|
814 | 787 |
# Support passing in a single resource to acquire rather than many |
815 | 788 |
if isinstance(names, basestring): |
816 | 789 |
names = [names] |
817 | 790 |
else: |
818 | 791 |
names = sorted(names) |
819 | 792 |
|
820 |
acquire_list = [] |
|
821 |
# First we look the locks up on __lockdict. We have no way of being sure |
|
822 |
# they will still be there after, but this makes it a lot faster should |
|
823 |
# just one of them be the already wrong |
|
824 |
for lname in utils.UniqueSequence(names): |
|
825 |
try: |
|
826 |
lock = self.__lockdict[lname] # raises KeyError if lock is not there |
|
827 |
acquire_list.append((lname, lock)) |
|
828 |
except KeyError: |
|
829 |
if want_all: |
|
830 |
# We are acquiring all the set, it doesn't matter if this |
|
831 |
# particular element is not there anymore. |
|
832 |
continue |
|
833 |
else: |
|
834 |
raise errors.LockError("Non-existing lock in set (%s)" % lname) |
|
835 |
|
|
836 |
# This will hold the locknames we effectively acquired. |
|
837 |
acquired = set() |
|
838 |
|
|
839 |
# Now acquire_list contains a sorted list of resources and locks we |
|
840 |
# want. In order to get them we loop on this (private) list and |
|
841 |
# acquire() them. We gave no real guarantee they will still exist till |
|
842 |
# this is done but .acquire() itself is safe and will alert us if the |
|
843 |
# lock gets deleted. |
|
844 |
for (lname, lock) in acquire_list: |
|
845 |
if __debug__ and callable(test_notify): |
|
846 |
test_notify_fn = lambda: test_notify(lname) |
|
847 |
else: |
|
848 |
test_notify_fn = None |
|
793 |
return self.__acquire_inner(names, False, shared, |
|
794 |
calc_remaining_timeout, test_notify) |
|
849 | 795 |
|
850 |
try: |
|
851 |
if timeout is not None and remaining_timeout < 0: |
|
852 |
raise _AcquireTimeout() |
|
853 |
|
|
854 |
# raises LockError if the lock was deleted |
|
855 |
if not lock.acquire(shared=shared, timeout=remaining_timeout, |
|
856 |
test_notify=test_notify_fn): |
|
857 |
# Couldn't get lock or timeout occurred |
|
858 |
if timeout is None: |
|
859 |
# This shouldn't happen as SharedLock.acquire(timeout=None) is |
|
860 |
# blocking. |
|
861 |
raise errors.LockError("Failed to get lock %s" % lname) |
|
862 |
|
|
863 |
raise _AcquireTimeout() |
|
864 |
|
|
865 |
# Re-calculate timeout |
|
866 |
remaining_timeout = calc_remaining_timeout() |
|
867 |
|
|
868 |
# now the lock cannot be deleted, we have it! |
|
869 |
self._add_owned(name=lname) |
|
870 |
acquired.add(lname) |
|
871 |
|
|
872 |
except _AcquireTimeout: |
|
873 |
# Release all acquired locks |
|
874 |
self._release_and_delete_owned() |
|
875 |
raise |
|
876 |
|
|
877 |
except errors.LockError: |
|
878 |
if want_all: |
|
879 |
# We are acquiring all the set, it doesn't matter if this |
|
880 |
# particular element is not there anymore. |
|
881 |
continue |
|
796 |
else: |
|
797 |
# If no names are given acquire the whole set by not letting new names |
|
798 |
# being added before we release, and getting the current list of names. |
|
799 |
# Some of them may then be deleted later, but we'll cope with this. |
|
800 |
# |
|
801 |
# We'd like to acquire this lock in a shared way, as it's nice if |
|
802 |
# everybody else can use the instances at the same time. If are |
|
803 |
# acquiring them exclusively though they won't be able to do this |
|
804 |
# anyway, though, so we'll get the list lock exclusively as well in |
|
805 |
# order to be able to do add() on the set while owning it. |
|
806 |
if not self.__lock.acquire(shared=shared, |
|
807 |
timeout=calc_remaining_timeout()): |
|
808 |
raise _AcquireTimeout() |
|
809 |
try: |
|
810 |
# note we own the set-lock |
|
811 |
self._add_owned() |
|
812 |
|
|
813 |
return self.__acquire_inner(self.__names(), True, shared, |
|
814 |
calc_remaining_timeout, test_notify) |
|
815 |
except: |
|
816 |
# We shouldn't have problems adding the lock to the owners list, but |
|
817 |
# if we did we'll try to release this lock and re-raise exception. |
|
818 |
# Of course something is going to be really wrong, after this. |
|
819 |
self.__lock.release() |
|
820 |
self._del_owned() |
|
821 |
raise |
|
882 | 822 |
|
883 |
self._release_and_delete_owned() |
|
823 |
except _AcquireTimeout: |
|
824 |
return None |
|
884 | 825 |
|
885 |
raise errors.LockError("Non-existing lock in set (%s)" % lname) |
|
826 |
def __acquire_inner(self, names, want_all, shared, timeout_fn, test_notify): |
|
827 |
""" |
|
886 | 828 |
|
887 |
except: |
|
888 |
# We shouldn't have problems adding the lock to the owners list, but |
|
889 |
# if we did we'll try to release this lock and re-raise exception. |
|
890 |
# Of course something is going to be really wrong, after this. |
|
891 |
if lock._is_owned(): |
|
892 |
lock.release() |
|
893 |
raise |
|
829 |
""" |
|
830 |
acquire_list = [] |
|
894 | 831 |
|
895 |
except: |
|
896 |
# If something went wrong and we had the set-lock let's release it... |
|
832 |
# First we look the locks up on __lockdict. We have no way of being sure |
|
833 |
# they will still be there after, but this makes it a lot faster should |
|
834 |
# just one of them be the already wrong |
|
835 |
for lname in utils.UniqueSequence(names): |
|
836 |
try: |
|
837 |
lock = self.__lockdict[lname] # raises KeyError if lock is not there |
|
838 |
acquire_list.append((lname, lock)) |
|
839 |
except KeyError: |
|
897 | 840 |
if want_all: |
898 |
self.__lock.release() |
|
899 |
raise |
|
841 |
# We are acquiring all the set, it doesn't matter if this particular |
|
842 |
# element is not there anymore. |
|
843 |
continue |
|
900 | 844 |
|
901 |
except _AcquireTimeout: |
|
902 |
if want_all: |
|
903 |
self._del_owned() |
|
845 |
raise errors.LockError("Non-existing lock in set (%s)" % lname) |
|
904 | 846 |
|
905 |
return None |
|
847 |
# This will hold the locknames we effectively acquired. |
|
848 |
acquired = set() |
|
849 |
|
|
850 |
try: |
|
851 |
# Now acquire_list contains a sorted list of resources and locks we |
|
852 |
# want. In order to get them we loop on this (private) list and |
|
853 |
# acquire() them. We gave no real guarantee they will still exist till |
|
854 |
# this is done but .acquire() itself is safe and will alert us if the |
|
855 |
# lock gets deleted. |
|
856 |
for (lname, lock) in acquire_list: |
|
857 |
if __debug__ and callable(test_notify): |
|
858 |
test_notify_fn = lambda: test_notify(lname) |
|
859 |
else: |
|
860 |
test_notify_fn = None |
|
861 |
|
|
862 |
timeout = timeout_fn() |
|
863 |
if timeout is not None and timeout < 0: |
|
864 |
raise _AcquireTimeout() |
|
865 |
|
|
866 |
try: |
|
867 |
# raises LockError if the lock was deleted |
|
868 |
acq_success = lock.acquire(shared=shared, timeout=timeout, |
|
869 |
test_notify=test_notify_fn) |
|
870 |
except errors.LockError: |
|
871 |
if want_all: |
|
872 |
# We are acquiring all the set, it doesn't matter if this |
|
873 |
# particular element is not there anymore. |
|
874 |
continue |
|
875 |
|
|
876 |
raise errors.LockError("Non-existing lock in set (%s)" % lname) |
|
877 |
|
|
878 |
if not acq_success: |
|
879 |
# Couldn't get lock or timeout occurred |
|
880 |
if timeout is None: |
|
881 |
# This shouldn't happen as SharedLock.acquire(timeout=None) is |
|
882 |
# blocking. |
|
883 |
raise errors.LockError("Failed to get lock %s" % lname) |
|
884 |
|
|
885 |
raise _AcquireTimeout() |
|
886 |
|
|
887 |
try: |
|
888 |
# now the lock cannot be deleted, we have it! |
|
889 |
self._add_owned(name=lname) |
|
890 |
acquired.add(lname) |
|
891 |
|
|
892 |
except: |
|
893 |
# We shouldn't have problems adding the lock to the owners list, but |
|
894 |
# if we did we'll try to release this lock and re-raise exception. |
|
895 |
# Of course something is going to be really wrong after this. |
|
896 |
if lock._is_owned(): |
|
897 |
lock.release() |
|
898 |
raise |
|
899 |
|
|
900 |
except: |
|
901 |
# Release all owned locks |
|
902 |
self._release_and_delete_owned() |
|
903 |
raise |
|
906 | 904 |
|
907 | 905 |
return acquired |
908 | 906 |
|
Also available in: Unified diff