From d4fef411ff23681d5aaa298157f81576576eeb2b Mon Sep 17 00:00:00 2001 From: Jason Conti Date: Thu, 4 Oct 2012 21:52:02 -0400 Subject: * apt/cache.py: - Add Cache.close() to delete the records and free up file descriptors - Add with statement support for Cache.close() --- apt/cache.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'apt/cache.py') diff --git a/apt/cache.py b/apt/cache.py index 86a788bb..adc936ef 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -42,6 +42,9 @@ class FetchFailedException(IOError): class LockFailedException(IOError): """Exception that is thrown when locking fails.""" +class CacheClosedException(Exception): + """Exception that is thrown when the cache is used after close().""" + class Cache(object): """Dictionary-like package cache. @@ -172,6 +175,19 @@ class Cache(object): progress.done() self._run_callbacks("cache_post_open") + def close(self): + """ Close the package cache """ + del self._records + self._records = None + + def __enter__(self): + """ Enter the with statement """ + return self + + def __exit__(self, exc_type, exc_value, traceback): + """ Exit the with statement """ + self.close() + def __getitem__(self, key): """ look like a dictionary (get key) """ try: @@ -238,6 +254,8 @@ class Cache(object): @property def required_download(self): """Get the size of the packages that are required to download.""" + if self._records is None: + raise CacheClosedException("Cache object used after close() called") pm = apt_pkg.PackageManager(self._depcache) fetcher = apt_pkg.Acquire() pm.get_archives(fetcher, self._list, self._records) @@ -288,6 +306,8 @@ class Cache(object): def _fetch_archives(self, fetcher, pm): """ fetch the needed archives """ + if self._records is None: + raise CacheClosedException("Cache object used after close() called") # get lock lockfile = apt_pkg.config.find_dir("Dir::Cache::Archives") + "lock" -- cgit v1.2.3 From 3a7246ab8faa36eb270f28e6b47e1608e587365a Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 15 Oct 2012 11:27:49 +0200 Subject: close cache on (re)open --- apt/cache.py | 2 ++ tests/test_apt_cache.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'apt/cache.py') diff --git a/apt/cache.py b/apt/cache.py index adc936ef..beebde8a 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -142,6 +142,8 @@ class Cache(object): """ if progress is None: progress = apt.progress.base.OpProgress() + # close old cache on (re)open + self.close() self.op_progress = progress self._run_callbacks("cache_pre_open") diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py index c850cec2..22c4e871 100644 --- a/tests/test_apt_cache.py +++ b/tests/test_apt_cache.py @@ -100,6 +100,23 @@ class TestAptCache(TestCase): self.assertEqual(fds_before_open, fds_after_close) self.assertEqual(unclosed_fd, set()) + def test_cache_open_twice_leaks_fds(self): + cache = apt.Cache() + fds_before_open = get_open_file_descriptors() + cache.open() + fds_after_open_twice = get_open_file_descriptors() + self.assertEqual(fds_before_open, fds_after_open_twice) + + @if_sources_list_is_readable + def test_cache_delete_leasks_fds(self): + fds_before_open = get_open_file_descriptors() + cache = apt.Cache() + del cache + import gc + gc.collect() + fds_after_delete = get_open_file_descriptors() + self.assertEqual(fds_before_open, fds_after_delete) + @if_sources_list_is_readable def test_cache_close_download_fails(self): cache = apt.Cache() -- cgit v1.2.3 From f4f89cd0080e9ee8632b42a575393ce0b7dbb987 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 15 Oct 2012 11:36:41 +0200 Subject: apt/cache.py: add comment --- apt/cache.py | 1 + 1 file changed, 1 insertion(+) (limited to 'apt/cache.py') diff --git a/apt/cache.py b/apt/cache.py index beebde8a..9842cb2a 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -179,6 +179,7 @@ class Cache(object): def close(self): """ Close the package cache """ + # explicitely free the FDs that _records has open del self._records self._records = None -- cgit v1.2.3