diff options
author | Lars Wirzenius <liw@liw.fi> | 2015-05-19 20:14:14 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2015-05-19 21:01:34 +0300 |
commit | 05c9a466a9db200f90acb2f4a76368a5b760baeb (patch) | |
tree | 50c5a6a70a096ff81fcb23d7c717a820a506ddd2 /obnamlib/repo_interface.py | |
parent | 09653f91ac82446aa42c4b68fc3446350a6219f1 (diff) | |
download | obnam-05c9a466a9db200f90acb2f4a76368a5b760baeb.tar.gz |
Add lock_everything and unlock_everything
Diffstat (limited to 'obnamlib/repo_interface.py')
-rw-r--r-- | obnamlib/repo_interface.py | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/obnamlib/repo_interface.py b/obnamlib/repo_interface.py index 540d1590..0081aeb3 100644 --- a/obnamlib/repo_interface.py +++ b/obnamlib/repo_interface.py @@ -359,10 +359,50 @@ class RepositoryInterface(object): ''' raise NotImplementedError() + # Global. + + def lock_everything(self): + '''Lock every part of the repository. + + If the caller already holds a lock, that is kept. If anyone + else holds a lock, the operation will fail. Ideally, the + caller shouldn't hold a lock, since that may lead to a + deadlock. + + ''' + unlockers = [] + try: + if not self.got_client_list_lock(): + self.lock_client_list() + unlockers.append((self.unlock_client_list, [])) + + for client_name in self.get_client_names(): + if not self.got_client_lock(client_name): + self.lock_client(client_name) + unlockers.append((self.unlock_client, [client_name])) + + if not self.got_chunk_indexes_lock(): + self.lock_chunk_indexes() + except obnamlib.LockFail: + for unlocker, args in unlockers: + unlocker(*args) + raise + + def unlock_everything(self): + '''Unock every part of the repository to which we hold a lock.''' + if self.got_client_list_lock(): + self.unlock_client_list() + + for client_name in self.get_client_names(): + if self.got_client_lock(client_name): + self.unlock_client(client_name) + + if self.got_chunk_indexes_lock(): + self.unlock_chunk_indexes() + # Client list. def get_client_names(self): - '''Return client names currently existing in the repository.''' raise NotImplementedError() @@ -847,6 +887,29 @@ class RepositoryInterfaceTests(unittest.TestCase): # pragma: no cover def test_returns_list_of_shared_directories(self): self.assertTrue(type(self.repo.get_shared_directories()), list) + # Global locking. + + def test_has_no_client_lock_initially(self): + self.setup_client() + self.assertFalse(self.repo.client_is_locked('fooclient')) + + def test_locks_everything(self): + self.setup_client() + self.repo.lock_everything() + self.assertTrue(self.repo.got_client_list_lock()) + self.assertTrue(self.repo.client_is_locked('fooclient')) + self.assertTrue(self.repo.got_client_lock('fooclient')) + self.assertTrue(self.repo.got_chunk_indexes_lock()) + + def test_unlocks_everything(self): + self.setup_client() + self.repo.lock_everything() + self.repo.unlock_everything() + self.assertFalse(self.repo.got_client_list_lock()) + self.assertFalse(self.repo.client_is_locked('fooclient')) + self.assertFalse(self.repo.got_client_lock('fooclient')) + self.assertFalse(self.repo.got_chunk_indexes_lock()) + # Tests for the client list. def test_has_not_got_client_list_lock_initially(self): |