diff --git a/swift/common/utils.py b/swift/common/utils.py index 7c9f7a93c7..49e1878b21 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -1600,6 +1600,10 @@ def lock_path(directory, timeout=10, timeout_class=None): mkdirs(directory) lockpath = '%s/.lock' % directory fd = os.open(lockpath, os.O_WRONLY | os.O_CREAT) + sleep_time = 0.01 + slower_sleep_time = max(timeout * 0.01, sleep_time) + slowdown_at = timeout * 0.01 + time_slept = 0 try: with timeout_class(timeout, lockpath): while True: @@ -1609,7 +1613,10 @@ def lock_path(directory, timeout=10, timeout_class=None): except IOError as err: if err.errno != errno.EAGAIN: raise - sleep(0.01) + if time_slept > slowdown_at: + sleep_time = slower_sleep_time + sleep(sleep_time) + time_slept += sleep_time yield True finally: os.close(fd) diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py index a7733f8c25..2c2eb343ed 100644 --- a/test/unit/common/test_utils.py +++ b/test/unit/common/test_utils.py @@ -727,6 +727,30 @@ class TestUtils(unittest.TestCase): finally: shutil.rmtree(tmpdir) + def test_lock_path_num_sleeps(self): + tmpdir = mkdtemp() + num_short_calls = [0] + exception_raised = [False] + + def my_sleep(to_sleep): + if to_sleep == 0.01: + num_short_calls[0] += 1 + else: + raise Exception('sleep time changed: %s' % to_sleep) + + try: + with mock.patch('swift.common.utils.sleep', my_sleep): + with utils.lock_path(tmpdir): + with utils.lock_path(tmpdir): + pass + except Exception as e: + exception_raised[0] = True + self.assertTrue('sleep time changed' in str(e)) + finally: + shutil.rmtree(tmpdir) + self.assertEqual(num_short_calls[0], 11) + self.assertTrue(exception_raised[0]) + def test_lock_path_class(self): tmpdir = mkdtemp() try: