diff options
author | Johan Dahlin <johan@async.com.br> | 2008-12-08 16:29:33 +0000 |
---|---|---|
committer | Johan Dahlin <johan@src.gnome.org> | 2008-12-08 16:29:33 +0000 |
commit | d05de46ddec10d4b7f9968320d2cb5f54d14d2f4 (patch) | |
tree | 92bcd7013972925ef7dfeef5e422e13dc7b03e36 /giscanner/cachestore.py | |
parent | 645cc555cce7b6c1252e19f70d5083f30b40c03e (diff) | |
download | gobject-introspection-d05de46ddec10d4b7f9968320d2cb5f54d14d2f4.tar.gz |
Dump the cache file to a temporary file and rename it the expected
2008-12-08 Johan Dahlin <johan@async.com.br>
* giscanner/cachestore.py (CacheStore.store): Dump the cache
file to a temporary file and rename it the expected filename
only when it's completely written.
This should make the cache more roboust when run in parallel,
and hopefully avoid triggering bugs in Python.
svn path=/trunk/; revision=985
Diffstat (limited to 'giscanner/cachestore.py')
-rw-r--r-- | giscanner/cachestore.py | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/giscanner/cachestore.py b/giscanner/cachestore.py index 4629e622..d9163464 100644 --- a/giscanner/cachestore.py +++ b/giscanner/cachestore.py @@ -18,11 +18,11 @@ # Boston, MA 02111-1307, USA. # +import errno import cPickle import hashlib import os -import errno - +import tempfile def _get_cachedir(): cachedir = os.path.join(os.environ['HOME'], '.cache') @@ -61,7 +61,7 @@ class CacheStore(object): return (os.stat(store_filename).st_mtime >= os.stat(filename).st_mtime) - def _purge_cache(self, filename): + def _remove_filename(filename): try: os.unlink(filename) except IOError, e: @@ -81,19 +81,31 @@ class CacheStore(object): store_filename = self._get_filename(filename) if store_filename is None: return + if (os.path.exists(store_filename) and self._cache_is_valid(store_filename, filename)): return None - fd = open(store_filename, 'w') + + tmp_fd, tmp_filename = tempfile.mkstemp(prefix='g-ir-scanner-cache-') try: - cPickle.dump(data, fd) + cPickle.dump(data, os.fdopen(tmp_fd, 'w')) except IOError, e: # No space left on device - if e.errno == e.ENOSPC: + if e.errno == errno.ENOSPC: + self._remove_filename(tmp_filename) return else: raise + try: + os.rename(tmp_filename, store_filename) + except OSError, e: + # Permission denied + if e.errno == errno.EACCES: + self._remove_filename(tmp_filename) + else: + raise + def load(self, filename): store_filename = self._get_filename(filename) if store_filename is None: @@ -111,6 +123,6 @@ class CacheStore(object): data = cPickle.load(fd) except (EOFError, ValueError, cPickle.BadPickleGet): # Broken cache entry, remove it - self._purge_cache(store_filename) + self._remove_filename(store_filename) data = None return data |